xref: /haiku/src/kits/network/libnetapi/NetworkDevice.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
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 <Messenger.h>
16 
17 #include <AutoDeleter.h>
18 #include <NetServer.h>
19 
20 extern "C" {
21 #	include <net80211/ieee80211_ioctl.h>
22 }
23 
24 
25 //#define TRACE_DEVICE
26 #ifdef TRACE_DEVICE
27 #	define TRACE(x, ...) printf(x, __VA_ARGS__);
28 #else
29 #	define TRACE(x, ...) ;
30 #endif
31 
32 
33 namespace {
34 
35 
36 struct ie_data {
37 	uint8	type;
38 	uint8	length;
39 	uint8	data[1];
40 };
41 
42 
43 static status_t
44 get_80211(const char* name, int32 type, void* data, int32& length)
45 {
46 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
47 	if (socket < 0)
48 		return errno;
49 
50 	FileDescriptorCloser closer(socket);
51 
52 	struct ieee80211req ireq;
53 	strlcpy(ireq.i_name, name, IF_NAMESIZE);
54 	ireq.i_type = type;
55 	ireq.i_val = 0;
56 	ireq.i_len = length;
57 	ireq.i_data = data;
58 
59 	if (ioctl(socket, SIOCG80211, &ireq, sizeof(struct ieee80211req)) < 0)
60 		return errno;
61 
62 	length = ireq.i_len;
63 	return B_OK;
64 }
65 
66 
67 template<typename T> status_t
68 do_request(T& request, const char* name, int option)
69 {
70 	int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
71 	if (socket < 0)
72 		return errno;
73 
74 	FileDescriptorCloser closer(socket);
75 
76 	strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE);
77 
78 	if (ioctl(socket, option, &request, sizeof(T)) < 0)
79 		return errno;
80 
81 	return B_OK;
82 }
83 
84 
85 template<> status_t
86 do_request<ieee80211req>(ieee80211req& request, const char* name, int option)
87 {
88 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
89 	if (socket < 0)
90 		return errno;
91 
92 	FileDescriptorCloser closer(socket);
93 
94 	strlcpy(((struct ieee80211req&)request).i_name, name, IFNAMSIZ);
95 
96 	if (ioctl(socket, option, &request, sizeof(request)) < 0)
97 		return errno;
98 
99 	return B_OK;
100 }
101 
102 
103 //! Read a 16 bit little endian value
104 static uint16
105 read_le16(uint8*& data, int32& length)
106 {
107 	uint16 value = B_LENDIAN_TO_HOST_INT16(*(uint16*)data);
108 	data += 2;
109 	length -= 2;
110 	return value;
111 }
112 
113 
114 //! Read a 32 bit little endian value
115 static uint32
116 read_le32(uint8*& data, int32& length)
117 {
118 	uint32 value = B_LENDIAN_TO_HOST_INT32(*(uint32*)data);
119 	data += 4;
120 	length -= 4;
121 	return value;
122 }
123 
124 
125 static uint32
126 from_rsn_cipher(uint32 cipher)
127 {
128 	if ((cipher & 0xffffff) != RSN_OUI)
129 		return B_NETWORK_CIPHER_CCMP;
130 
131 	switch (cipher >> 24) {
132 		case RSN_CSE_NULL:
133 			return B_NETWORK_CIPHER_NONE;
134 		case RSN_CSE_WEP40:
135 			return B_NETWORK_CIPHER_WEP_40;
136 		case RSN_CSE_WEP104:
137 			return B_NETWORK_CIPHER_WEP_104;
138 		case RSN_CSE_TKIP:
139 			return B_NETWORK_CIPHER_TKIP;
140 		default:
141 		case RSN_CSE_CCMP:
142 			return B_NETWORK_CIPHER_CCMP;
143 		case RSN_CSE_WRAP:
144 			return B_NETWORK_CIPHER_AES_128_CMAC;
145 	}
146 }
147 
148 
149 static uint32
150 from_rsn_key_mode(uint32 mode)
151 {
152 	if ((mode & 0xffffff) != RSN_OUI)
153 		return B_KEY_MODE_IEEE802_1X;
154 
155 	switch (mode >> 24) {
156 		default:
157 		case RSN_ASE_8021X_UNSPEC:
158 			return B_KEY_MODE_IEEE802_1X;
159 		case RSN_ASE_8021X_PSK:
160 			return B_KEY_MODE_PSK;
161 		// the following are currently not defined in net80211
162 		case 3:
163 			return B_KEY_MODE_FT_IEEE802_1X;
164 		case 4:
165 			return B_KEY_MODE_FT_PSK;
166 		case 5:
167 			return B_KEY_MODE_IEEE802_1X_SHA256;
168 		case 6:
169 			return B_KEY_MODE_PSK_SHA256;
170 	}
171 }
172 
173 
174 //! Parse RSN/WPA information elements common data
175 static void
176 parse_ie_rsn_wpa(wireless_network& network, uint8*& data, int32& length)
177 {
178 	if (length >= 4) {
179 		// parse group cipher
180 		network.group_cipher = from_rsn_cipher(read_le32(data, length));
181 	} else if (length > 0)
182 		return;
183 
184 	if (length >= 2) {
185 		// parse unicast cipher
186 		uint16 count = read_le16(data, length);
187 		network.cipher = 0;
188 
189 		for (uint16 i = 0; i < count; i++) {
190 			if (length < 4)
191 				return;
192 			network.cipher |= from_rsn_cipher(read_le32(data, length));
193 		}
194 	} else if (length > 0)
195 		return;
196 
197 	if (length >= 2) {
198 		// parse key management mode
199 		uint16 count = read_le16(data, length);
200 		network.key_mode = 0;
201 
202 		for (uint16 i = 0; i < count; i++) {
203 			if (length < 4)
204 				return;
205 			network.key_mode |= from_rsn_key_mode(read_le32(data, length));
206 		}
207 	} else if (length > 0)
208 		return;
209 
210 	// TODO: capabilities, and PMKID following in case of RSN
211 }
212 
213 
214 //! Parse RSN (Robust Security Network) information element.
215 static void
216 parse_ie_rsn(wireless_network& network, ie_data* ie)
217 {
218 	network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
219 	network.cipher = B_NETWORK_CIPHER_CCMP;
220 	network.group_cipher = B_NETWORK_CIPHER_CCMP;
221 	network.key_mode = B_KEY_MODE_IEEE802_1X;
222 
223 	int32 length = ie->length;
224 	if (length < 2)
225 		return;
226 
227 	uint8* data = ie->data;
228 
229 	uint16 version = read_le16(data, length);
230 	if (version != RSN_VERSION)
231 		return;
232 
233 	parse_ie_rsn_wpa(network, data, length);
234 }
235 
236 
237 //! Parse WPA information element.
238 static bool
239 parse_ie_wpa(wireless_network& network, ie_data* ie)
240 {
241 	int32 length = ie->length;
242 	if (length < 6)
243 		return false;
244 
245 	uint8* data = ie->data;
246 
247 	uint32 oui = read_le32(data, length);
248 	TRACE("  oui: %" B_PRIx32 "\n", oui);
249 	if (oui != ((WPA_OUI_TYPE << 24) | WPA_OUI))
250 		return false;
251 
252 	uint16 version = read_le16(data, length);
253 	if (version != WPA_VERSION)
254 		return false;
255 
256 	network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
257 	network.cipher = B_NETWORK_CIPHER_TKIP;
258 	network.group_cipher = B_NETWORK_CIPHER_TKIP;
259 	network.key_mode = B_KEY_MODE_IEEE802_1X;
260 
261 	parse_ie_rsn_wpa(network, data, length);
262 	return true;
263 }
264 
265 
266 //! Parse information elements.
267 static void
268 parse_ie(wireless_network& network, uint8* _ie, int32 ieLength)
269 {
270 	struct ie_data* ie = (ie_data*)_ie;
271 	bool hadRSN = false;
272 	bool hadWPA = false;
273 
274 	while (ieLength > 1) {
275 		TRACE("ie type %u\n", ie->type);
276 		switch (ie->type) {
277 			case IEEE80211_ELEMID_SSID:
278 				strlcpy(network.name, (char*)ie->data,
279 					min_c(ie->length + 1, (int)sizeof(network.name)));
280 				break;
281 			case IEEE80211_ELEMID_RSN:
282 				parse_ie_rsn(network, ie);
283 				hadRSN = true;
284 				break;
285 			case IEEE80211_ELEMID_VENDOR:
286 				if (!hadRSN && parse_ie_wpa(network, ie))
287 					hadWPA = true;
288 				break;
289 		}
290 
291 		ieLength -= 2 + ie->length;
292 		ie = (ie_data*)((uint8*)ie + 2 + ie->length);
293 	}
294 
295 	if (hadRSN || hadWPA) {
296 		// Determine authentication mode
297 
298 		if ((network.key_mode & (B_KEY_MODE_IEEE802_1X_SHA256
299 				| B_KEY_MODE_PSK_SHA256)) != 0) {
300 			network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
301 		} else if ((network.key_mode & (B_KEY_MODE_IEEE802_1X
302 				| B_KEY_MODE_PSK | B_KEY_MODE_FT_IEEE802_1X
303 				| B_KEY_MODE_FT_PSK)) != 0) {
304 			if (!hadRSN)
305 				network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
306 		} else if ((network.key_mode & B_KEY_MODE_NONE) != 0) {
307 			if ((network.cipher & (B_NETWORK_CIPHER_WEP_40
308 					| B_NETWORK_CIPHER_WEP_104)) != 0)
309 				network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP;
310 			else
311 				network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE;
312 		}
313 	}
314 }
315 
316 
317 static void
318 parse_ie(wireless_network& network, struct ieee80211req_sta_info& info)
319 {
320 	parse_ie(network, (uint8*)&info + info.isi_ie_off, info.isi_ie_len);
321 }
322 
323 
324 static void
325 parse_ie(wireless_network& network, struct ieee80211req_scan_result& result)
326 {
327 	parse_ie(network, (uint8*)&result + result.isr_ie_off + result.isr_ssid_len
328 			+ result.isr_meshid_len, result.isr_ie_len);
329 }
330 
331 
332 static bool
333 get_ssid_from_ie(char* name, uint8* _ie, int32 ieLength)
334 {
335 	struct ie_data* ie = (ie_data*)_ie;
336 
337 	while (ieLength > 1) {
338 		switch (ie->type) {
339 			case IEEE80211_ELEMID_SSID:
340 				strlcpy(name, (char*)ie->data, min_c(ie->length + 1, 32));
341 				return true;
342 		}
343 
344 		ieLength -= 2 + ie->length;
345 		ie = (ie_data*)((uint8*)ie + 2 + ie->length);
346 	}
347 	return false;
348 }
349 
350 
351 static bool
352 get_ssid_from_ie(char* name, struct ieee80211req_sta_info& info)
353 {
354 	return get_ssid_from_ie(name, (uint8*)&info + info.isi_ie_off,
355 		info.isi_ie_len);
356 }
357 
358 
359 static void
360 fill_wireless_network(wireless_network& network,
361 	struct ieee80211req_sta_info& info)
362 {
363 	network.name[0] = '\0';
364 	network.address.SetToLinkLevel(info.isi_macaddr,
365 		IEEE80211_ADDR_LEN);
366 	network.signal_strength = info.isi_rssi;
367 	network.noise_level = info.isi_noise;
368 	network.flags |= (info.isi_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0
369 		? B_NETWORK_IS_ENCRYPTED : 0;
370 
371 	network.authentication_mode = 0;
372 	network.cipher = 0;
373 	network.group_cipher = 0;
374 	network.key_mode = 0;
375 
376 	parse_ie(network, info);
377 }
378 
379 
380 static void
381 fill_wireless_network(wireless_network& network, const char* networkName,
382 	struct ieee80211req_scan_result& result)
383 {
384 	strlcpy(network.name, networkName, sizeof(network.name));
385 	network.address.SetToLinkLevel(result.isr_bssid,
386 		IEEE80211_ADDR_LEN);
387 	network.signal_strength = result.isr_rssi;
388 	network.noise_level = result.isr_noise;
389 	network.flags = (result.isr_capinfo & IEEE80211_CAPINFO_PRIVACY)
390 		!= 0 ? B_NETWORK_IS_ENCRYPTED : 0;
391 
392 	network.authentication_mode = 0;
393 	network.cipher = 0;
394 	network.group_cipher = 0;
395 	network.key_mode = 0;
396 
397 	parse_ie(network, result);
398 }
399 
400 
401 static status_t
402 get_scan_result(const char* device, wireless_network& network, uint32 index,
403 	const BNetworkAddress* address, const char* name)
404 {
405 	if (address != NULL && address->Family() != AF_LINK)
406 		return B_BAD_VALUE;
407 
408 	const size_t kBufferSize = 65535;
409 	uint8* buffer = (uint8*)malloc(kBufferSize);
410 	if (buffer == NULL)
411 		return B_NO_MEMORY;
412 
413 	MemoryDeleter deleter(buffer);
414 
415 	int32 length = kBufferSize;
416 	status_t status = get_80211(device, IEEE80211_IOC_SCAN_RESULTS, buffer,
417 		length);
418 	if (status != B_OK)
419 		return status;
420 
421 	int32 bytesLeft = length;
422 	uint8* entry = buffer;
423 	uint32 count = 0;
424 
425 	while (bytesLeft > (int32)sizeof(struct ieee80211req_scan_result)) {
426 		ieee80211req_scan_result* result
427 			= (ieee80211req_scan_result*)entry;
428 
429 		char networkName[32];
430 		strlcpy(networkName, (char*)(result + 1),
431 			min_c((int)sizeof(networkName), result->isr_ssid_len + 1));
432 
433 		if (index == count || (address != NULL && !memcmp(
434 				address->LinkLevelAddress(), result->isr_bssid,
435 				IEEE80211_ADDR_LEN))
436 			|| (name != NULL && !strcmp(networkName, name))) {
437 			// Fill wireless_network with scan result data
438 			fill_wireless_network(network, networkName, *result);
439 			return B_OK;
440 		}
441 
442 		entry += result->isr_len;
443 		bytesLeft -= result->isr_len;
444 		count++;
445 	}
446 
447 	return B_ENTRY_NOT_FOUND;
448 }
449 
450 
451 static status_t
452 get_station(const char* device, wireless_network& network, uint32 index,
453 	const BNetworkAddress* address, const char* name)
454 {
455 	if (address != NULL && address->Family() != AF_LINK)
456 		return B_BAD_VALUE;
457 
458 	const size_t kBufferSize = 65535;
459 	uint8* buffer = (uint8*)malloc(kBufferSize);
460 	if (buffer == NULL)
461 		return B_NO_MEMORY;
462 
463 	MemoryDeleter deleter(buffer);
464 
465 	struct ieee80211req_sta_req& request = *(ieee80211req_sta_req*)buffer;
466 	if (address != NULL) {
467 		memcpy(request.is_u.macaddr, address->LinkLevelAddress(),
468 			IEEE80211_ADDR_LEN);
469 	} else
470 		memset(request.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
471 
472 	int32 length = kBufferSize;
473 	status_t status = get_80211(device, IEEE80211_IOC_STA_INFO, &request,
474 		length);
475 	if (status != B_OK)
476 		return status;
477 
478 	int32 bytesLeft = length;
479 	uint8* entry = (uint8*)&request.info[0];
480 	uint32 count = 0;
481 
482 	while (bytesLeft > (int32)sizeof(struct ieee80211req_sta_info)) {
483 		ieee80211req_sta_info* info = (ieee80211req_sta_info*)entry;
484 
485 		char networkName[32];
486 		get_ssid_from_ie(networkName, *info);
487 		if (index == count || address != NULL
488 			|| (name != NULL && !strcmp(networkName, name))) {
489 			fill_wireless_network(network, *info);
490 			return B_OK;
491 		}
492 
493 		entry += info->isi_len;
494 		bytesLeft -= info->isi_len;
495 		count++;
496 	}
497 
498 	return B_ENTRY_NOT_FOUND;
499 }
500 
501 
502 static status_t
503 get_network(const char* device, wireless_network& network, uint32 index,
504 	const BNetworkAddress* address, const char* name)
505 {
506 	status_t status = get_station(device, network, index, address, name);
507 	if (status != B_OK)
508 		return get_scan_result(device, network, index, address, name);
509 
510 	return B_OK;
511 }
512 
513 
514 }	// namespace
515 
516 
517 // #pragma mark -
518 
519 
520 BNetworkDevice::BNetworkDevice()
521 {
522 	Unset();
523 }
524 
525 
526 BNetworkDevice::BNetworkDevice(const char* name)
527 {
528 	SetTo(name);
529 }
530 
531 
532 BNetworkDevice::~BNetworkDevice()
533 {
534 }
535 
536 
537 void
538 BNetworkDevice::Unset()
539 {
540 	fName[0] = '\0';
541 }
542 
543 
544 void
545 BNetworkDevice::SetTo(const char* name)
546 {
547 	strlcpy(fName, name, IF_NAMESIZE);
548 }
549 
550 
551 const char*
552 BNetworkDevice::Name() const
553 {
554 	return fName;
555 }
556 
557 
558 bool
559 BNetworkDevice::Exists() const
560 {
561 	ifreq request;
562 	return do_request(request, Name(), SIOCGIFINDEX) == B_OK;
563 }
564 
565 
566 uint32
567 BNetworkDevice::Index() const
568 {
569 	ifreq request;
570 	if (do_request(request, Name(), SIOCGIFINDEX) != B_OK)
571 		return 0;
572 
573 	return request.ifr_index;
574 }
575 
576 
577 uint32
578 BNetworkDevice::Flags() const
579 {
580 	ifreq request;
581 	if (do_request(request, Name(), SIOCGIFFLAGS) != B_OK)
582 		return 0;
583 
584 	return request.ifr_flags;
585 }
586 
587 
588 bool
589 BNetworkDevice::HasLink() const
590 {
591 	return (Flags() & IFF_LINK) != 0;
592 }
593 
594 
595 int32
596 BNetworkDevice::CountMedia() const
597 {
598 	ifmediareq request;
599 	request.ifm_count = 0;
600 	request.ifm_ulist = NULL;
601 
602 	if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK)
603 		return -1;
604 
605 	return request.ifm_count;
606 }
607 
608 
609 int32
610 BNetworkDevice::Media() const
611 {
612 	ifmediareq request;
613 	request.ifm_count = 0;
614 	request.ifm_ulist = NULL;
615 
616 	if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK)
617 		return -1;
618 
619 	return request.ifm_current;
620 }
621 
622 
623 int32
624 BNetworkDevice::GetMediaAt(int32 index) const
625 {
626 	// TODO: this could do some caching
627 	return 0;
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 #if 0
689 	if (index == 0) {
690 		struct ieee80211_scan_req request;
691 		memset(&request, 0, sizeof(request));
692 		request.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE
693 			| IEEE80211_IOC_SCAN_NOJOIN;
694 		request.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
695 		set_80211(Name(), IEEE80211_IOC_SCAN_REQ, NULL);
696 	}
697 #endif
698 	return B_ERROR;
699 }
700 
701 
702 status_t
703 BNetworkDevice::GetNextNetwork(uint32& cookie, wireless_network& network)
704 {
705 	status_t status = get_scan_result(Name(), network, cookie, NULL, NULL);
706 	if (status != B_OK)
707 		return status;
708 
709 	cookie++;
710 	return B_OK;
711 }
712 
713 
714 status_t
715 BNetworkDevice::GetNetwork(const char* name, wireless_network& network)
716 {
717 	if (name == NULL || name[0] == '\0')
718 		return B_BAD_VALUE;
719 
720 	return get_network(Name(), network, UINT32_MAX, NULL, name);
721 }
722 
723 
724 status_t
725 BNetworkDevice::GetNetwork(const BNetworkAddress& address,
726 	wireless_network& network)
727 {
728 	if (address.Family() != AF_LINK)
729 		return B_BAD_VALUE;
730 
731 	return get_network(Name(), network, UINT32_MAX, &address, NULL);
732 }
733 
734 
735 status_t
736 BNetworkDevice::JoinNetwork(const char* name, const char* password)
737 {
738 	if (name == NULL || name[0] == '\0')
739 		return B_BAD_VALUE;
740 
741 	BMessage message(kMsgJoinNetwork);
742 	status_t status = message.AddString("device", Name());
743 
744 	if (status == B_OK)
745 		status = message.AddString("name", name);
746 	if (status == B_OK && password != NULL)
747 		status = message.AddString("password", password);
748 	if (status != B_OK)
749 		return status;
750 
751 	// Send message to the net_server
752 
753 	BMessenger networkServer(kNetServerSignature);
754 	BMessage reply;
755 	status = networkServer.SendMessage(&message, &reply);
756 	if (status == B_OK)
757 		reply.FindInt32("status", &status);
758 
759 	return status;
760 }
761 
762 
763 status_t
764 BNetworkDevice::JoinNetwork(const wireless_network& network,
765 	const char* password)
766 {
767 	return JoinNetwork(network.address, password);
768 }
769 
770 
771 status_t
772 BNetworkDevice::JoinNetwork(const BNetworkAddress& address,
773 	const char* password)
774 {
775 	if (address.InitCheck() != B_OK)
776 		return B_BAD_VALUE;
777 
778 	BMessage message(kMsgJoinNetwork);
779 	status_t status = message.AddString("device", Name());
780 
781 	if (status == B_OK) {
782 		status = message.AddFlat("address",
783 			const_cast<BNetworkAddress*>(&address));
784 	}
785 	if (status == B_OK && password != NULL)
786 		status = message.AddString("password", password);
787 	if (status != B_OK)
788 		return status;
789 
790 	// Send message to the net_server
791 
792 	BMessenger networkServer(kNetServerSignature);
793 	BMessage reply;
794 	status = networkServer.SendMessage(&message, &reply);
795 	if (status == B_OK)
796 		reply.FindInt32("status", &status);
797 
798 	return status;
799 }
800 
801 
802 status_t
803 BNetworkDevice::LeaveNetwork(const char* name)
804 {
805 	BMessage message(kMsgLeaveNetwork);
806 	status_t status = message.AddString("device", Name());
807 	if (status == B_OK)
808 		status = message.AddString("name", name);
809 	if (status == B_OK)
810 		status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED);
811 	if (status != B_OK)
812 		return status;
813 
814 	BMessenger networkServer(kNetServerSignature);
815 	BMessage reply;
816 	status = networkServer.SendMessage(&message, &reply);
817 	if (status == B_OK)
818 		reply.FindInt32("status", &status);
819 
820 	return status;
821 }
822 
823 
824 status_t
825 BNetworkDevice::LeaveNetwork(const wireless_network& network)
826 {
827 	return LeaveNetwork(network.address);
828 }
829 
830 
831 status_t
832 BNetworkDevice::LeaveNetwork(const BNetworkAddress& address)
833 {
834 	BMessage message(kMsgLeaveNetwork);
835 	status_t status = message.AddString("device", Name());
836 	if (status == B_OK) {
837 		status = message.AddFlat("address",
838 			const_cast<BNetworkAddress*>(&address));
839 	}
840 	if (status == B_OK)
841 		status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED);
842 	if (status != B_OK)
843 		return status;
844 
845 	BMessenger networkServer(kNetServerSignature);
846 	BMessage reply;
847 	status = networkServer.SendMessage(&message, &reply);
848 	if (status == B_OK)
849 		reply.FindInt32("status", &status);
850 
851 	return status;
852 }
853 
854 
855 status_t
856 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
857 	wireless_network& network)
858 {
859 	BNetworkAddress address;
860 	status_t status = GetNextAssociatedNetwork(cookie, address);
861 	if (status != B_OK)
862 		return status;
863 
864 	return GetNetwork(address, network);
865 }
866 
867 
868 status_t
869 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
870 	BNetworkAddress& address)
871 {
872 	// We currently support only a single associated network
873 	if (cookie != 0)
874 		return B_ENTRY_NOT_FOUND;
875 
876 	uint8 mac[IEEE80211_ADDR_LEN];
877 	int32 length = IEEE80211_ADDR_LEN;
878 	status_t status = get_80211(Name(), IEEE80211_IOC_BSSID, mac, length);
879 	if (status != B_OK)
880 		return status;
881 
882 	if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0
883 			&& mac[5] == 0) {
884 		return B_ENTRY_NOT_FOUND;
885 	}
886 
887 	address.SetToLinkLevel(mac, IEEE80211_ADDR_LEN);
888 	cookie++;
889 	return B_OK;
890 }
891