xref: /haiku/src/kits/network/libnetapi/NetworkDevice.cpp (revision 9e25244c5e9051f6cd333820d6332397361abd6c)
1 /*
2  * Copyright 2010-2015, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <NetworkDevice.h>
8 
9 #include <errno.h>
10 #include <net/if.h>
11 #include <net/if_media.h>
12 #include <stdio.h>
13 #include <sys/sockio.h>
14 
15 #include <Looper.h>
16 #include <Messenger.h>
17 
18 #include <AutoDeleter.h>
19 #include <NetServer.h>
20 #include <NetworkNotifications.h>
21 
22 extern "C" {
23 #	include <compat/sys/cdefs.h>
24 #	include <compat/sys/ioccom.h>
25 #	include <net80211/ieee80211_ioctl.h>
26 }
27 
28 
29 //#define TRACE_DEVICE
30 #ifdef TRACE_DEVICE
31 #	define TRACE(x, ...) printf(x, __VA_ARGS__);
32 #else
33 #	define TRACE(x, ...) ;
34 #endif
35 
36 
37 namespace {
38 
39 
40 struct ie_data {
41 	uint8	type;
42 	uint8	length;
43 	uint8	data[1];
44 };
45 
46 
47 // #pragma mark - private functions (code shared with net_server)
48 
49 
50 static status_t
51 get_80211(const char* name, int32 type, void* data, int32& length)
52 {
53 	FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0));
54 	if (!socket.IsSet())
55 		return errno;
56 
57 	struct ieee80211req ireq;
58 	strlcpy(ireq.i_name, name, IF_NAMESIZE);
59 	ireq.i_type = type;
60 	ireq.i_val = 0;
61 	ireq.i_len = length;
62 	ireq.i_data = data;
63 
64 	if (ioctl(socket.Get(), SIOCG80211, &ireq, sizeof(struct ieee80211req))
65 		< 0)
66 		return errno;
67 
68 	length = ireq.i_len;
69 	return B_OK;
70 }
71 
72 
73 static status_t
74 set_80211(const char* name, int32 type, void* data,
75 	int32 length = 0, int32 value = 0)
76 {
77 	FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0));
78 	if (!socket.IsSet())
79 		return errno;
80 
81 	struct ieee80211req ireq;
82 	strlcpy(ireq.i_name, name, IF_NAMESIZE);
83 	ireq.i_type = type;
84 	ireq.i_val = value;
85 	ireq.i_len = length;
86 	ireq.i_data = data;
87 
88 	if (ioctl(socket.Get(), SIOCS80211, &ireq, sizeof(struct ieee80211req))
89 		< 0)
90 		return errno;
91 
92 	return B_OK;
93 }
94 
95 
96 template<typename T> status_t
97 do_request(T& request, const char* name, int option)
98 {
99 	FileDescriptorCloser socket(::socket(AF_LINK, SOCK_DGRAM, 0));
100 	if (!socket.IsSet())
101 		return errno;
102 
103 	strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE);
104 
105 	if (ioctl(socket.Get(), option, &request, sizeof(T)) < 0)
106 		return errno;
107 
108 	return B_OK;
109 }
110 
111 
112 template<> status_t
113 do_request<ieee80211req>(ieee80211req& request, const char* name, int option)
114 {
115 	FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0));
116 	if (!socket.IsSet())
117 		return errno;
118 
119 	strlcpy(((struct ieee80211req&)request).i_name, name, IFNAMSIZ);
120 
121 	if (ioctl(socket.Get(), option, &request, sizeof(request)) < 0)
122 		return errno;
123 
124 	return B_OK;
125 }
126 
127 
128 //! Read a 16 bit little endian value
129 static uint16
130 read_le16(uint8*& data, int32& length)
131 {
132 	uint16 value = B_LENDIAN_TO_HOST_INT16(*(uint16*)data);
133 	data += 2;
134 	length -= 2;
135 	return value;
136 }
137 
138 
139 //! Read a 32 bit little endian value
140 static uint32
141 read_le32(uint8*& data, int32& length)
142 {
143 	uint32 value = B_LENDIAN_TO_HOST_INT32(*(uint32*)data);
144 	data += 4;
145 	length -= 4;
146 	return value;
147 }
148 
149 
150 static uint32
151 from_rsn_cipher(uint32 cipher)
152 {
153 	if ((cipher & 0xffffff) != RSN_OUI)
154 		return B_NETWORK_CIPHER_CCMP;
155 
156 	switch (cipher >> 24) {
157 		case RSN_CSE_NULL:
158 			return B_NETWORK_CIPHER_NONE;
159 		case RSN_CSE_WEP40:
160 			return B_NETWORK_CIPHER_WEP_40;
161 		case RSN_CSE_WEP104:
162 			return B_NETWORK_CIPHER_WEP_104;
163 		case RSN_CSE_TKIP:
164 			return B_NETWORK_CIPHER_TKIP;
165 		default:
166 		case RSN_CSE_CCMP:
167 			return B_NETWORK_CIPHER_CCMP;
168 		case RSN_CSE_WRAP:
169 			return B_NETWORK_CIPHER_AES_128_CMAC;
170 	}
171 }
172 
173 
174 static uint32
175 from_rsn_key_mode(uint32 mode)
176 {
177 	if ((mode & 0xffffff) != RSN_OUI)
178 		return B_KEY_MODE_IEEE802_1X;
179 
180 	switch (mode >> 24) {
181 		default:
182 		case RSN_ASE_8021X_UNSPEC:
183 			return B_KEY_MODE_IEEE802_1X;
184 		case RSN_ASE_8021X_PSK:
185 			return B_KEY_MODE_PSK;
186 		// the following are currently not defined in net80211
187 		case 3:
188 			return B_KEY_MODE_FT_IEEE802_1X;
189 		case 4:
190 			return B_KEY_MODE_FT_PSK;
191 		case 5:
192 			return B_KEY_MODE_IEEE802_1X_SHA256;
193 		case 6:
194 			return B_KEY_MODE_PSK_SHA256;
195 	}
196 }
197 
198 
199 //! Parse RSN/WPA information elements common data
200 static void
201 parse_ie_rsn_wpa(wireless_network& network, uint8*& data, int32& length)
202 {
203 	if (length >= 4) {
204 		// parse group cipher
205 		network.group_cipher = from_rsn_cipher(read_le32(data, length));
206 	} else if (length > 0)
207 		return;
208 
209 	if (length >= 2) {
210 		// parse unicast cipher
211 		uint16 count = read_le16(data, length);
212 		network.cipher = 0;
213 
214 		for (uint16 i = 0; i < count; i++) {
215 			if (length < 4)
216 				return;
217 			network.cipher |= from_rsn_cipher(read_le32(data, length));
218 		}
219 	} else if (length > 0)
220 		return;
221 
222 	if (length >= 2) {
223 		// parse key management mode
224 		uint16 count = read_le16(data, length);
225 		network.key_mode = 0;
226 
227 		for (uint16 i = 0; i < count; i++) {
228 			if (length < 4)
229 				return;
230 			network.key_mode |= from_rsn_key_mode(read_le32(data, length));
231 		}
232 	} else if (length > 0)
233 		return;
234 
235 	// TODO: capabilities, and PMKID following in case of RSN
236 }
237 
238 
239 //! Parse RSN (Robust Security Network) information element.
240 static void
241 parse_ie_rsn(wireless_network& network, ie_data* ie)
242 {
243 	network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
244 	network.cipher = B_NETWORK_CIPHER_CCMP;
245 	network.group_cipher = B_NETWORK_CIPHER_CCMP;
246 	network.key_mode = B_KEY_MODE_IEEE802_1X;
247 
248 	int32 length = ie->length;
249 	if (length < 2)
250 		return;
251 
252 	uint8* data = ie->data;
253 
254 	uint16 version = read_le16(data, length);
255 	if (version != RSN_VERSION)
256 		return;
257 
258 	parse_ie_rsn_wpa(network, data, length);
259 }
260 
261 
262 //! Parse WPA information element.
263 static bool
264 parse_ie_wpa(wireless_network& network, ie_data* ie)
265 {
266 	int32 length = ie->length;
267 	if (length < 6)
268 		return false;
269 
270 	uint8* data = ie->data;
271 
272 	uint32 oui = read_le32(data, length);
273 	TRACE("  oui: %" B_PRIx32 "\n", oui);
274 	if (oui != ((WPA_OUI_TYPE << 24) | WPA_OUI))
275 		return false;
276 
277 	uint16 version = read_le16(data, length);
278 	if (version != WPA_VERSION)
279 		return false;
280 
281 	network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
282 	network.cipher = B_NETWORK_CIPHER_TKIP;
283 	network.group_cipher = B_NETWORK_CIPHER_TKIP;
284 	network.key_mode = B_KEY_MODE_IEEE802_1X;
285 
286 	parse_ie_rsn_wpa(network, data, length);
287 	return true;
288 }
289 
290 
291 //! Parse information elements.
292 static void
293 parse_ie(wireless_network& network, uint8* _ie, int32 ieLength)
294 {
295 	struct ie_data* ie = (ie_data*)_ie;
296 	bool hadRSN = false;
297 	bool hadWPA = false;
298 
299 	while (ieLength > 1) {
300 		TRACE("ie type %u\n", ie->type);
301 		switch (ie->type) {
302 			case IEEE80211_ELEMID_SSID:
303 				strlcpy(network.name, (char*)ie->data,
304 					min_c(ie->length + 1, (int)sizeof(network.name)));
305 				break;
306 			case IEEE80211_ELEMID_RSN:
307 				parse_ie_rsn(network, ie);
308 				hadRSN = true;
309 				break;
310 			case IEEE80211_ELEMID_VENDOR:
311 				if (!hadRSN && parse_ie_wpa(network, ie))
312 					hadWPA = true;
313 				break;
314 		}
315 
316 		ieLength -= 2 + ie->length;
317 		ie = (ie_data*)((uint8*)ie + 2 + ie->length);
318 	}
319 
320 	if (hadRSN || hadWPA) {
321 		// Determine authentication mode
322 
323 		if ((network.key_mode & (B_KEY_MODE_IEEE802_1X_SHA256
324 				| B_KEY_MODE_PSK_SHA256)) != 0) {
325 			network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
326 		} else if ((network.key_mode & (B_KEY_MODE_IEEE802_1X
327 				| B_KEY_MODE_PSK | B_KEY_MODE_FT_IEEE802_1X
328 				| B_KEY_MODE_FT_PSK)) != 0) {
329 			if (!hadRSN)
330 				network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
331 		} else if ((network.key_mode & B_KEY_MODE_NONE) != 0) {
332 			if ((network.cipher & (B_NETWORK_CIPHER_WEP_40
333 					| B_NETWORK_CIPHER_WEP_104)) != 0)
334 				network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP;
335 			else
336 				network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE;
337 		}
338 	}
339 }
340 
341 
342 static void
343 parse_ie(wireless_network& network, struct ieee80211req_sta_info& info)
344 {
345 	parse_ie(network, (uint8*)&info + info.isi_ie_off, info.isi_ie_len);
346 }
347 
348 
349 static void
350 parse_ie(wireless_network& network, struct ieee80211req_scan_result& result)
351 {
352 	parse_ie(network, (uint8*)&result + result.isr_ie_off + result.isr_ssid_len
353 			+ result.isr_meshid_len, result.isr_ie_len);
354 }
355 
356 
357 static bool
358 get_ssid_from_ie(char* name, uint8* _ie, int32 ieLength)
359 {
360 	struct ie_data* ie = (ie_data*)_ie;
361 
362 	while (ieLength > 1) {
363 		switch (ie->type) {
364 			case IEEE80211_ELEMID_SSID:
365 				strlcpy(name, (char*)ie->data, min_c(ie->length + 1, 32));
366 				return true;
367 		}
368 
369 		ieLength -= 2 + ie->length;
370 		ie = (ie_data*)((uint8*)ie + 2 + ie->length);
371 	}
372 	return false;
373 }
374 
375 
376 static bool
377 get_ssid_from_ie(char* name, struct ieee80211req_sta_info& info)
378 {
379 	return get_ssid_from_ie(name, (uint8*)&info + info.isi_ie_off,
380 		info.isi_ie_len);
381 }
382 
383 
384 static void
385 fill_wireless_network(wireless_network& network,
386 	struct ieee80211req_sta_info& info)
387 {
388 	network.name[0] = '\0';
389 	network.address.SetToLinkLevel(info.isi_macaddr,
390 		IEEE80211_ADDR_LEN);
391 	network.signal_strength = info.isi_rssi;
392 	network.noise_level = info.isi_noise;
393 	network.flags |= (info.isi_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0
394 		? B_NETWORK_IS_ENCRYPTED : 0;
395 
396 	network.authentication_mode = 0;
397 	network.cipher = 0;
398 	network.group_cipher = 0;
399 	network.key_mode = 0;
400 
401 	parse_ie(network, info);
402 }
403 
404 
405 static void
406 fill_wireless_network(wireless_network& network, const char* networkName,
407 	struct ieee80211req_scan_result& result)
408 {
409 	strlcpy(network.name, networkName, sizeof(network.name));
410 	network.address.SetToLinkLevel(result.isr_bssid,
411 		IEEE80211_ADDR_LEN);
412 	network.signal_strength = result.isr_rssi;
413 	network.noise_level = result.isr_noise;
414 	network.flags = (result.isr_capinfo & IEEE80211_CAPINFO_PRIVACY)
415 		!= 0 ? B_NETWORK_IS_ENCRYPTED : 0;
416 
417 	network.authentication_mode = 0;
418 	network.cipher = 0;
419 	network.group_cipher = 0;
420 	network.key_mode = 0;
421 
422 	parse_ie(network, result);
423 }
424 
425 
426 static status_t
427 get_scan_result(const char* device, wireless_network& network, uint32 index,
428 	const BNetworkAddress* address, const char* name)
429 {
430 	if (address != NULL && address->Family() != AF_LINK)
431 		return B_BAD_VALUE;
432 
433 	const size_t kBufferSize = 65535;
434 	uint8* buffer = (uint8*)malloc(kBufferSize);
435 	if (buffer == NULL)
436 		return B_NO_MEMORY;
437 
438 	MemoryDeleter deleter(buffer);
439 
440 	int32 length = kBufferSize;
441 	status_t status = get_80211(device, IEEE80211_IOC_SCAN_RESULTS, buffer,
442 		length);
443 	if (status != B_OK)
444 		return status;
445 
446 	int32 bytesLeft = length;
447 	uint8* entry = buffer;
448 	uint32 count = 0;
449 
450 	while (bytesLeft > (int32)sizeof(struct ieee80211req_scan_result)) {
451 		ieee80211req_scan_result* result
452 			= (ieee80211req_scan_result*)entry;
453 
454 		char networkName[32];
455 		strlcpy(networkName, (char*)(result + 1),
456 			min_c((int)sizeof(networkName), result->isr_ssid_len + 1));
457 
458 		if (index == count || (address != NULL && !memcmp(
459 				address->LinkLevelAddress(), result->isr_bssid,
460 				IEEE80211_ADDR_LEN))
461 			|| (name != NULL && !strcmp(networkName, name))) {
462 			// Fill wireless_network with scan result data
463 			fill_wireless_network(network, networkName, *result);
464 			return B_OK;
465 		}
466 
467 		entry += result->isr_len;
468 		bytesLeft -= result->isr_len;
469 		count++;
470 	}
471 
472 	return B_ENTRY_NOT_FOUND;
473 }
474 
475 
476 static status_t
477 get_station(const char* device, wireless_network& network, uint32 index,
478 	const BNetworkAddress* address, const char* name)
479 {
480 	if (address != NULL && address->Family() != AF_LINK)
481 		return B_BAD_VALUE;
482 
483 	const size_t kBufferSize = 65535;
484 	uint8* buffer = (uint8*)malloc(kBufferSize);
485 	if (buffer == NULL)
486 		return B_NO_MEMORY;
487 
488 	MemoryDeleter deleter(buffer);
489 
490 	struct ieee80211req_sta_req& request = *(ieee80211req_sta_req*)buffer;
491 	if (address != NULL) {
492 		memcpy(request.is_u.macaddr, address->LinkLevelAddress(),
493 			IEEE80211_ADDR_LEN);
494 	} else
495 		memset(request.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
496 
497 	int32 length = kBufferSize;
498 	status_t status = get_80211(device, IEEE80211_IOC_STA_INFO, &request,
499 		length);
500 	if (status != B_OK)
501 		return status;
502 
503 	int32 bytesLeft = length;
504 	uint8* entry = (uint8*)&request.info[0];
505 	uint32 count = 0;
506 
507 	while (bytesLeft > (int32)sizeof(struct ieee80211req_sta_info)) {
508 		ieee80211req_sta_info* info = (ieee80211req_sta_info*)entry;
509 
510 		char networkName[32];
511 		get_ssid_from_ie(networkName, *info);
512 		if (index == count || address != NULL
513 			|| (name != NULL && !strcmp(networkName, name))) {
514 			fill_wireless_network(network, *info);
515 			return B_OK;
516 		}
517 
518 		entry += info->isi_len;
519 		bytesLeft -= info->isi_len;
520 		count++;
521 	}
522 
523 	return B_ENTRY_NOT_FOUND;
524 }
525 
526 
527 static status_t
528 get_network(const char* device, wireless_network& network, uint32 index,
529 	const BNetworkAddress* address, const char* name)
530 {
531 	status_t status = get_station(device, network, index, address, name);
532 	if (status != B_OK)
533 		return get_scan_result(device, network, index, address, name);
534 
535 	return B_OK;
536 }
537 
538 
539 }	// namespace
540 
541 
542 // #pragma mark -
543 
544 
545 BNetworkDevice::BNetworkDevice()
546 {
547 	Unset();
548 }
549 
550 
551 BNetworkDevice::BNetworkDevice(const char* name)
552 {
553 	SetTo(name);
554 }
555 
556 
557 BNetworkDevice::~BNetworkDevice()
558 {
559 }
560 
561 
562 void
563 BNetworkDevice::Unset()
564 {
565 	fName[0] = '\0';
566 }
567 
568 
569 void
570 BNetworkDevice::SetTo(const char* name)
571 {
572 	strlcpy(fName, name, IF_NAMESIZE);
573 }
574 
575 
576 const char*
577 BNetworkDevice::Name() const
578 {
579 	return fName;
580 }
581 
582 
583 bool
584 BNetworkDevice::Exists() const
585 {
586 	ifreq request;
587 	return do_request(request, Name(), SIOCGIFINDEX) == B_OK;
588 }
589 
590 
591 uint32
592 BNetworkDevice::Index() const
593 {
594 	ifreq request;
595 	if (do_request(request, Name(), SIOCGIFINDEX) != B_OK)
596 		return 0;
597 
598 	return request.ifr_index;
599 }
600 
601 
602 uint32
603 BNetworkDevice::Flags() const
604 {
605 	ifreq request;
606 	if (do_request(request, Name(), SIOCGIFFLAGS) != B_OK)
607 		return 0;
608 
609 	return request.ifr_flags;
610 }
611 
612 
613 bool
614 BNetworkDevice::HasLink() const
615 {
616 	return (Flags() & IFF_LINK) != 0;
617 }
618 
619 
620 int32
621 BNetworkDevice::CountMedia() const
622 {
623 	ifmediareq request;
624 	request.ifm_count = 0;
625 	request.ifm_ulist = NULL;
626 
627 	if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK)
628 		return -1;
629 
630 	return request.ifm_count;
631 }
632 
633 
634 int32
635 BNetworkDevice::Media() const
636 {
637 	ifmediareq request;
638 	request.ifm_count = 0;
639 	request.ifm_ulist = NULL;
640 
641 	if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK)
642 		return -1;
643 
644 	return request.ifm_current;
645 }
646 
647 
648 int32
649 BNetworkDevice::GetMediaAt(int32 index) const
650 {
651 	// TODO: this could do some caching
652 	return 0;
653 }
654 
655 
656 status_t
657 BNetworkDevice::SetMedia(int32 media)
658 {
659 	ifreq request;
660 	request.ifr_media = media;
661 	return do_request(request, Name(), SIOCSIFMEDIA);
662 }
663 
664 
665 status_t
666 BNetworkDevice::GetHardwareAddress(BNetworkAddress& address)
667 {
668 	ifreq request;
669 	status_t status = do_request(request, Name(), SIOCGIFADDR);
670 	if (status != B_OK)
671 		return status;
672 
673 	address.SetTo(request.ifr_addr);
674 	return B_OK;
675 }
676 
677 
678 bool
679 BNetworkDevice::IsEthernet()
680 {
681 	return IFM_TYPE(Media()) == IFM_ETHER;
682 }
683 
684 
685 bool
686 BNetworkDevice::IsWireless()
687 {
688 	return IFM_TYPE(Media()) == IFM_IEEE80211;
689 }
690 
691 
692 status_t
693 BNetworkDevice::Control(int option, void* request)
694 {
695 	switch (IFM_TYPE(Media())) {
696 		case IFM_ETHER:
697 			return do_request(*reinterpret_cast<ifreq*>(request),
698 				&fName[0], option);
699 
700 		case IFM_IEEE80211:
701 			return do_request(*reinterpret_cast<ieee80211req*>(request),
702 				&fName[0], option);
703 
704 		default:
705 			return B_ERROR;
706 	}
707 }
708 
709 
710 status_t
711 BNetworkDevice::Scan(bool wait, bool forceRescan)
712 {
713 	// Network status listener for change notifications
714 	class ScanListener : public BLooper {
715 	public:
716 		ScanListener(BString iface)
717 			:
718 			fInterface(iface)
719 		{
720 			start_watching_network(B_WATCH_NETWORK_WLAN_CHANGES, this);
721 		}
722 		virtual ~ScanListener()
723 		{
724 			stop_watching_network(this);
725 		}
726 
727 	protected:
728 		virtual void MessageReceived(BMessage *message)
729 		{
730 			if (message->what != B_NETWORK_MONITOR) {
731 				BLooper::MessageReceived(message);
732 				return;
733 			}
734 
735 			BString interfaceName;
736 			if (message->FindString("interface", &interfaceName) != B_OK)
737 				return;
738 			// See comment in AutoconfigLooper::_NetworkMonitorNotification
739 			// for the reason as to why we use FindFirst instead of ==.
740 			if (fInterface.FindFirst(interfaceName) < 0)
741 				return;
742 			if (message->FindInt32("opcode") != B_NETWORK_WLAN_SCANNED)
743 				return;
744 
745 			Lock();
746 			Quit();
747 		}
748 
749 	private:
750 		BString fInterface;
751 	};
752 
753 	ScanListener* listener = NULL;
754 	if (wait)
755 		listener = new ScanListener(Name());
756 
757 	// Trigger the scan
758 	struct ieee80211_scan_req request;
759 	memset(&request, 0, sizeof(request));
760 	request.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
761 		| IEEE80211_IOC_SCAN_BGSCAN
762 		| IEEE80211_IOC_SCAN_NOPICK
763 		| IEEE80211_IOC_SCAN_ONCE
764 		| (forceRescan ? IEEE80211_IOC_SCAN_FLUSH : 0);
765 	request.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
766 	request.sr_nssid = 0;
767 
768 	status_t status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request,
769 		sizeof(request));
770 
771 	// If there are no VAPs running, the net80211 layer will return ENXIO.
772 	// Try to bring up the interface (which should start a VAP) and try again.
773 	if (status == ENXIO) {
774 		struct ieee80211req dummy;
775 		status = set_80211(Name(), IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP, &dummy,
776 			sizeof(dummy));
777 		if (status != B_OK)
778 			return status;
779 
780 		status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request,
781 			sizeof(request));
782 	}
783 
784 	// If there is already a scan currently running, it's probably an "infinite"
785 	// one, which we of course don't want to wait for. So just return immediately
786 	// if that's the case.
787 	if (status == EINPROGRESS) {
788 		delete listener;
789 		return B_OK;
790 	}
791 
792 	if (!wait || status != B_OK) {
793 		delete listener;
794 		return status;
795 	}
796 
797 	while (wait_for_thread(listener->Run(), NULL) == B_INTERRUPTED)
798 		;
799 	return B_OK;
800 }
801 
802 
803 status_t
804 BNetworkDevice::GetNextNetwork(uint32& cookie, wireless_network& network)
805 {
806 	status_t status = get_scan_result(Name(), network, cookie, NULL, NULL);
807 	if (status != B_OK)
808 		return status;
809 
810 	cookie++;
811 	return B_OK;
812 }
813 
814 
815 status_t
816 BNetworkDevice::GetNetwork(const char* name, wireless_network& network)
817 {
818 	if (name == NULL || name[0] == '\0')
819 		return B_BAD_VALUE;
820 
821 	return get_network(Name(), network, UINT32_MAX, NULL, name);
822 }
823 
824 
825 status_t
826 BNetworkDevice::GetNetwork(const BNetworkAddress& address,
827 	wireless_network& network)
828 {
829 	if (address.Family() != AF_LINK)
830 		return B_BAD_VALUE;
831 
832 	return get_network(Name(), network, UINT32_MAX, &address, NULL);
833 }
834 
835 
836 status_t
837 BNetworkDevice::JoinNetwork(const char* name, const char* password)
838 {
839 	if (name == NULL || name[0] == '\0')
840 		return B_BAD_VALUE;
841 
842 	BMessage message(kMsgJoinNetwork);
843 	status_t status = message.AddString("device", Name());
844 
845 	if (status == B_OK)
846 		status = message.AddString("name", name);
847 	if (status == B_OK && password != NULL)
848 		status = message.AddString("password", password);
849 	if (status != B_OK)
850 		return status;
851 
852 	// Send message to the net_server
853 
854 	BMessenger networkServer(kNetServerSignature);
855 	BMessage reply;
856 	status = networkServer.SendMessage(&message, &reply);
857 	if (status == B_OK)
858 		reply.FindInt32("status", &status);
859 
860 	return status;
861 }
862 
863 
864 status_t
865 BNetworkDevice::JoinNetwork(const wireless_network& network,
866 	const char* password)
867 {
868 	return JoinNetwork(network.address, password);
869 }
870 
871 
872 status_t
873 BNetworkDevice::JoinNetwork(const BNetworkAddress& address,
874 	const char* password)
875 {
876 	if (address.InitCheck() != B_OK)
877 		return B_BAD_VALUE;
878 
879 	BMessage message(kMsgJoinNetwork);
880 	status_t status = message.AddString("device", Name());
881 
882 	if (status == B_OK) {
883 		status = message.AddFlat("address",
884 			const_cast<BNetworkAddress*>(&address));
885 	}
886 	if (status == B_OK && password != NULL)
887 		status = message.AddString("password", password);
888 	if (status != B_OK)
889 		return status;
890 
891 	// Send message to the net_server
892 
893 	BMessenger networkServer(kNetServerSignature);
894 	BMessage reply;
895 	status = networkServer.SendMessage(&message, &reply);
896 	if (status == B_OK)
897 		reply.FindInt32("status", &status);
898 
899 	return status;
900 }
901 
902 
903 status_t
904 BNetworkDevice::LeaveNetwork(const char* name)
905 {
906 	BMessage message(kMsgLeaveNetwork);
907 	status_t status = message.AddString("device", Name());
908 	if (status == B_OK)
909 		status = message.AddString("name", name);
910 	if (status == B_OK)
911 		status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED);
912 	if (status != B_OK)
913 		return status;
914 
915 	BMessenger networkServer(kNetServerSignature);
916 	BMessage reply;
917 	status = networkServer.SendMessage(&message, &reply);
918 	if (status == B_OK)
919 		reply.FindInt32("status", &status);
920 
921 	return status;
922 }
923 
924 
925 status_t
926 BNetworkDevice::LeaveNetwork(const wireless_network& network)
927 {
928 	return LeaveNetwork(network.address);
929 }
930 
931 
932 status_t
933 BNetworkDevice::LeaveNetwork(const BNetworkAddress& address)
934 {
935 	BMessage message(kMsgLeaveNetwork);
936 	status_t status = message.AddString("device", Name());
937 	if (status == B_OK) {
938 		status = message.AddFlat("address",
939 			const_cast<BNetworkAddress*>(&address));
940 	}
941 	if (status == B_OK)
942 		status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED);
943 	if (status != B_OK)
944 		return status;
945 
946 	BMessenger networkServer(kNetServerSignature);
947 	BMessage reply;
948 	status = networkServer.SendMessage(&message, &reply);
949 	if (status == B_OK)
950 		reply.FindInt32("status", &status);
951 
952 	return status;
953 }
954 
955 
956 status_t
957 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
958 	wireless_network& network)
959 {
960 	BNetworkAddress address;
961 	status_t status = GetNextAssociatedNetwork(cookie, address);
962 	if (status != B_OK)
963 		return status;
964 
965 	return GetNetwork(address, network);
966 }
967 
968 
969 status_t
970 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
971 	BNetworkAddress& address)
972 {
973 	// We currently support only a single associated network
974 	if (cookie != 0)
975 		return B_ENTRY_NOT_FOUND;
976 
977 	uint8 mac[IEEE80211_ADDR_LEN];
978 	int32 length = IEEE80211_ADDR_LEN;
979 	status_t status = get_80211(Name(), IEEE80211_IOC_BSSID, mac, length);
980 	if (status != B_OK)
981 		return status;
982 
983 	if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0
984 			&& mac[5] == 0) {
985 		return B_ENTRY_NOT_FOUND;
986 	}
987 
988 	address.SetToLinkLevel(mac, IEEE80211_ADDR_LEN);
989 	cookie++;
990 	return B_OK;
991 }
992