xref: /haiku/src/kits/network/libnetapi/NetworkDevice.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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::Media() const
622 {
623 	ifreq request;
624 	if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK)
625 		return -1;
626 
627 	return request.ifr_media;
628 }
629 
630 
631 status_t
632 BNetworkDevice::SetMedia(int32 media)
633 {
634 	ifreq request;
635 	request.ifr_media = media;
636 	return do_request(request, Name(), SIOCSIFMEDIA);
637 }
638 
639 
640 status_t
641 BNetworkDevice::GetHardwareAddress(BNetworkAddress& address)
642 {
643 	ifreq request;
644 	status_t status = do_request(request, Name(), SIOCGIFADDR);
645 	if (status != B_OK)
646 		return status;
647 
648 	address.SetTo(request.ifr_addr);
649 	return B_OK;
650 }
651 
652 
653 bool
654 BNetworkDevice::IsEthernet()
655 {
656 	return IFM_TYPE(Media()) == IFM_ETHER;
657 }
658 
659 
660 bool
661 BNetworkDevice::IsWireless()
662 {
663 	return IFM_TYPE(Media()) == IFM_IEEE80211;
664 }
665 
666 
667 status_t
668 BNetworkDevice::Control(int option, void* request)
669 {
670 	switch (IFM_TYPE(Media())) {
671 		case IFM_ETHER:
672 			return do_request(*reinterpret_cast<ifreq*>(request),
673 				&fName[0], option);
674 
675 		case IFM_IEEE80211:
676 			return do_request(*reinterpret_cast<ieee80211req*>(request),
677 				&fName[0], option);
678 
679 		default:
680 			return B_ERROR;
681 	}
682 }
683 
684 
685 status_t
686 BNetworkDevice::Scan(bool wait, bool forceRescan)
687 {
688 	// Network status listener for change notifications
689 	class ScanListener : public BLooper {
690 	public:
691 		ScanListener(BString iface)
692 			:
693 			fInterface(iface)
694 		{
695 			start_watching_network(B_WATCH_NETWORK_WLAN_CHANGES, this);
696 		}
697 		virtual ~ScanListener()
698 		{
699 			stop_watching_network(this);
700 		}
701 
702 	protected:
703 		virtual void MessageReceived(BMessage *message)
704 		{
705 			if (message->what != B_NETWORK_MONITOR) {
706 				BLooper::MessageReceived(message);
707 				return;
708 			}
709 
710 			BString interfaceName;
711 			if (message->FindString("interface", &interfaceName) != B_OK)
712 				return;
713 			// See comment in AutoconfigLooper::_NetworkMonitorNotification
714 			// for the reason as to why we use FindFirst instead of ==.
715 			if (fInterface.FindFirst(interfaceName) < 0)
716 				return;
717 			if (message->FindInt32("opcode") != B_NETWORK_WLAN_SCANNED)
718 				return;
719 
720 			Lock();
721 			Quit();
722 		}
723 
724 	private:
725 		BString fInterface;
726 	};
727 
728 	ScanListener* listener = NULL;
729 	if (wait)
730 		listener = new ScanListener(Name());
731 
732 	// Trigger the scan
733 	struct ieee80211_scan_req request;
734 	memset(&request, 0, sizeof(request));
735 	request.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
736 		| IEEE80211_IOC_SCAN_BGSCAN
737 		| IEEE80211_IOC_SCAN_NOPICK
738 		| IEEE80211_IOC_SCAN_ONCE
739 		| (forceRescan ? IEEE80211_IOC_SCAN_FLUSH : 0);
740 	request.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
741 	request.sr_nssid = 0;
742 
743 	status_t status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request,
744 		sizeof(request));
745 
746 	// If there are no VAPs running, the net80211 layer will return ENXIO.
747 	// Try to bring up the interface (which should start a VAP) and try again.
748 	if (status == ENXIO) {
749 		struct ieee80211req dummy;
750 		status = set_80211(Name(), IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP, &dummy,
751 			sizeof(dummy));
752 		if (status != B_OK)
753 			return status;
754 
755 		status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request,
756 			sizeof(request));
757 	}
758 
759 	// If there is already a scan currently running, it's probably an "infinite"
760 	// one, which we of course don't want to wait for. So just return immediately
761 	// if that's the case.
762 	if (status == EINPROGRESS) {
763 		delete listener;
764 		return B_OK;
765 	}
766 
767 	if (!wait || status != B_OK) {
768 		delete listener;
769 		return status;
770 	}
771 
772 	while (wait_for_thread(listener->Run(), NULL) == B_INTERRUPTED)
773 		;
774 	return B_OK;
775 }
776 
777 
778 status_t
779 BNetworkDevice::GetNextNetwork(uint32& cookie, wireless_network& network)
780 {
781 	status_t status = get_scan_result(Name(), network, cookie, NULL, NULL);
782 	if (status != B_OK)
783 		return status;
784 
785 	cookie++;
786 	return B_OK;
787 }
788 
789 
790 status_t
791 BNetworkDevice::GetNetwork(const char* name, wireless_network& network)
792 {
793 	if (name == NULL || name[0] == '\0')
794 		return B_BAD_VALUE;
795 
796 	return get_network(Name(), network, UINT32_MAX, NULL, name);
797 }
798 
799 
800 status_t
801 BNetworkDevice::GetNetwork(const BNetworkAddress& address,
802 	wireless_network& network)
803 {
804 	if (address.Family() != AF_LINK)
805 		return B_BAD_VALUE;
806 
807 	return get_network(Name(), network, UINT32_MAX, &address, NULL);
808 }
809 
810 
811 status_t
812 BNetworkDevice::JoinNetwork(const char* name, const char* password)
813 {
814 	if (name == NULL || name[0] == '\0')
815 		return B_BAD_VALUE;
816 
817 	BMessage message(kMsgJoinNetwork);
818 	status_t status = message.AddString("device", Name());
819 
820 	if (status == B_OK)
821 		status = message.AddString("name", name);
822 	if (status == B_OK && password != NULL)
823 		status = message.AddString("password", password);
824 	if (status != B_OK)
825 		return status;
826 
827 	// Send message to the net_server
828 
829 	BMessenger networkServer(kNetServerSignature);
830 	BMessage reply;
831 	status = networkServer.SendMessage(&message, &reply);
832 	if (status == B_OK)
833 		reply.FindInt32("status", &status);
834 
835 	return status;
836 }
837 
838 
839 status_t
840 BNetworkDevice::JoinNetwork(const wireless_network& network,
841 	const char* password)
842 {
843 	return JoinNetwork(network.address, password);
844 }
845 
846 
847 status_t
848 BNetworkDevice::JoinNetwork(const BNetworkAddress& address,
849 	const char* password)
850 {
851 	if (address.InitCheck() != B_OK)
852 		return B_BAD_VALUE;
853 
854 	BMessage message(kMsgJoinNetwork);
855 	status_t status = message.AddString("device", Name());
856 
857 	if (status == B_OK) {
858 		status = message.AddFlat("address",
859 			const_cast<BNetworkAddress*>(&address));
860 	}
861 	if (status == B_OK && password != NULL)
862 		status = message.AddString("password", password);
863 	if (status != B_OK)
864 		return status;
865 
866 	// Send message to the net_server
867 
868 	BMessenger networkServer(kNetServerSignature);
869 	BMessage reply;
870 	status = networkServer.SendMessage(&message, &reply);
871 	if (status == B_OK)
872 		reply.FindInt32("status", &status);
873 
874 	return status;
875 }
876 
877 
878 status_t
879 BNetworkDevice::LeaveNetwork(const char* name)
880 {
881 	BMessage message(kMsgLeaveNetwork);
882 	status_t status = message.AddString("device", Name());
883 	if (status == B_OK)
884 		status = message.AddString("name", name);
885 	if (status == B_OK)
886 		status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED);
887 	if (status != B_OK)
888 		return status;
889 
890 	BMessenger networkServer(kNetServerSignature);
891 	BMessage reply;
892 	status = networkServer.SendMessage(&message, &reply);
893 	if (status == B_OK)
894 		reply.FindInt32("status", &status);
895 
896 	return status;
897 }
898 
899 
900 status_t
901 BNetworkDevice::LeaveNetwork(const wireless_network& network)
902 {
903 	return LeaveNetwork(network.address);
904 }
905 
906 
907 status_t
908 BNetworkDevice::LeaveNetwork(const BNetworkAddress& address)
909 {
910 	BMessage message(kMsgLeaveNetwork);
911 	status_t status = message.AddString("device", Name());
912 	if (status == B_OK) {
913 		status = message.AddFlat("address",
914 			const_cast<BNetworkAddress*>(&address));
915 	}
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::GetNextAssociatedNetwork(uint32& cookie,
933 	wireless_network& network)
934 {
935 	BNetworkAddress address;
936 	status_t status = GetNextAssociatedNetwork(cookie, address);
937 	if (status != B_OK)
938 		return status;
939 
940 	return GetNetwork(address, network);
941 }
942 
943 
944 status_t
945 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
946 	BNetworkAddress& address)
947 {
948 	// We currently support only a single associated network
949 	if (cookie != 0)
950 		return B_ENTRY_NOT_FOUND;
951 
952 	uint8 mac[IEEE80211_ADDR_LEN];
953 	int32 length = IEEE80211_ADDR_LEN;
954 	status_t status = get_80211(Name(), IEEE80211_IOC_BSSID, mac, length);
955 	if (status != B_OK)
956 		return status;
957 
958 	if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0
959 			&& mac[5] == 0) {
960 		return B_ENTRY_NOT_FOUND;
961 	}
962 
963 	address.SetToLinkLevel(mac, IEEE80211_ADDR_LEN);
964 	cookie++;
965 	return B_OK;
966 }
967