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