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