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
22extern "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
37namespace {
38
39
40struct 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
50static status_t
51get_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
73static status_t
74set_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
96template<typename T> status_t
97do_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
112template<> status_t
113do_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
129static uint16
130read_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
140static uint32
141read_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
150static uint32
151from_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
174static uint32
175from_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
200static void
201parse_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.
240static void
241parse_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.
263static bool
264parse_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.
292static void
293parse_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
342static void
343parse_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
349static void
350parse_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
357static bool
358get_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
376static bool
377get_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
384static void
385fill_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
405static void
406fill_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
426static status_t
427get_scan_results(const char* device, wireless_network*& networks, uint32& count)
428{
429	if (networks != NULL)
430		return B_BAD_VALUE;
431
432	// TODO: Find some way to reduce code duplication with the following function!
433	const size_t kBufferSize = 65535;
434	uint8* buffer = (uint8*)malloc(kBufferSize);
435	if (buffer == NULL)
436		return B_NO_MEMORY;
437	MemoryDeleter deleter(buffer);
438
439	int32 length = kBufferSize;
440	status_t status = get_80211(device, IEEE80211_IOC_SCAN_RESULTS, buffer,
441		length);
442	if (status != B_OK)
443		return status;
444
445	BObjectList<wireless_network> networksList(true);
446
447	int32 bytesLeft = length;
448	uint8* entry = buffer;
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		wireless_network* network = new wireless_network;
459		fill_wireless_network(*network, networkName, *result);
460		networksList.AddItem(network);
461
462		entry += result->isr_len;
463		bytesLeft -= result->isr_len;
464	}
465
466	count = 0;
467	if (!networksList.IsEmpty()) {
468		networks = new wireless_network[networksList.CountItems()];
469		for (int32 i = 0; i < networksList.CountItems(); i++) {
470			networks[i] = *networksList.ItemAt(i);
471			count++;
472		}
473	}
474
475	return B_OK;
476}
477
478
479static status_t
480get_scan_result(const char* device, wireless_network& network, uint32 index,
481	const BNetworkAddress* address, const char* name)
482{
483	if (address != NULL && address->Family() != AF_LINK)
484		return B_BAD_VALUE;
485
486	// TODO: Find some way to reduce code duplication with the preceding function!
487	const size_t kBufferSize = 65535;
488	uint8* buffer = (uint8*)malloc(kBufferSize);
489	if (buffer == NULL)
490		return B_NO_MEMORY;
491
492	MemoryDeleter deleter(buffer);
493
494	int32 length = kBufferSize;
495	status_t status = get_80211(device, IEEE80211_IOC_SCAN_RESULTS, buffer,
496		length);
497	if (status != B_OK)
498		return status;
499
500	int32 bytesLeft = length;
501	uint8* entry = buffer;
502	uint32 count = 0;
503
504	while (bytesLeft > (int32)sizeof(struct ieee80211req_scan_result)) {
505		ieee80211req_scan_result* result
506			= (ieee80211req_scan_result*)entry;
507
508		char networkName[32];
509		strlcpy(networkName, (char*)(result + 1),
510			min_c((int)sizeof(networkName), result->isr_ssid_len + 1));
511
512		if (index == count || (address != NULL && !memcmp(
513				address->LinkLevelAddress(), result->isr_bssid,
514				IEEE80211_ADDR_LEN))
515			|| (name != NULL && !strcmp(networkName, name))) {
516			// Fill wireless_network with scan result data
517			fill_wireless_network(network, networkName, *result);
518			return B_OK;
519		}
520
521		entry += result->isr_len;
522		bytesLeft -= result->isr_len;
523		count++;
524	}
525
526	return B_ENTRY_NOT_FOUND;
527}
528
529
530static status_t
531get_station(const char* device, wireless_network& network, uint32 index,
532	const BNetworkAddress* address, const char* name)
533{
534	if (address != NULL && address->Family() != AF_LINK)
535		return B_BAD_VALUE;
536
537	const size_t kBufferSize = 65535;
538	uint8* buffer = (uint8*)malloc(kBufferSize);
539	if (buffer == NULL)
540		return B_NO_MEMORY;
541
542	MemoryDeleter deleter(buffer);
543
544	struct ieee80211req_sta_req& request = *(ieee80211req_sta_req*)buffer;
545	if (address != NULL) {
546		memcpy(request.is_u.macaddr, address->LinkLevelAddress(),
547			IEEE80211_ADDR_LEN);
548	} else
549		memset(request.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
550
551	int32 length = kBufferSize;
552	status_t status = get_80211(device, IEEE80211_IOC_STA_INFO, &request,
553		length);
554	if (status != B_OK)
555		return status;
556
557	int32 bytesLeft = length;
558	uint8* entry = (uint8*)&request.info[0];
559	uint32 count = 0;
560
561	while (bytesLeft > (int32)sizeof(struct ieee80211req_sta_info)) {
562		ieee80211req_sta_info* info = (ieee80211req_sta_info*)entry;
563
564		char networkName[32];
565		get_ssid_from_ie(networkName, *info);
566		if (index == count || address != NULL
567			|| (name != NULL && !strcmp(networkName, name))) {
568			fill_wireless_network(network, *info);
569			return B_OK;
570		}
571
572		entry += info->isi_len;
573		bytesLeft -= info->isi_len;
574		count++;
575	}
576
577	return B_ENTRY_NOT_FOUND;
578}
579
580
581static status_t
582get_network(const char* device, wireless_network& network, uint32 index,
583	const BNetworkAddress* address, const char* name)
584{
585	status_t status = get_station(device, network, index, address, name);
586	if (status != B_OK)
587		return get_scan_result(device, network, index, address, name);
588
589	return B_OK;
590}
591
592
593}	// namespace
594
595
596// #pragma mark -
597
598
599BNetworkDevice::BNetworkDevice()
600{
601	Unset();
602}
603
604
605BNetworkDevice::BNetworkDevice(const char* name)
606{
607	SetTo(name);
608}
609
610
611BNetworkDevice::~BNetworkDevice()
612{
613}
614
615
616void
617BNetworkDevice::Unset()
618{
619	fName[0] = '\0';
620}
621
622
623void
624BNetworkDevice::SetTo(const char* name)
625{
626	strlcpy(fName, name, IF_NAMESIZE);
627}
628
629
630const char*
631BNetworkDevice::Name() const
632{
633	return fName;
634}
635
636
637bool
638BNetworkDevice::Exists() const
639{
640	ifreq request;
641	return do_request(request, Name(), SIOCGIFINDEX) == B_OK;
642}
643
644
645uint32
646BNetworkDevice::Index() const
647{
648	ifreq request;
649	if (do_request(request, Name(), SIOCGIFINDEX) != B_OK)
650		return 0;
651
652	return request.ifr_index;
653}
654
655
656uint32
657BNetworkDevice::Flags() const
658{
659	ifreq request;
660	if (do_request(request, Name(), SIOCGIFFLAGS) != B_OK)
661		return 0;
662
663	return request.ifr_flags;
664}
665
666
667bool
668BNetworkDevice::HasLink() const
669{
670	return (Flags() & IFF_LINK) != 0;
671}
672
673
674int32
675BNetworkDevice::Media() const
676{
677	ifreq request;
678	if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK)
679		return -1;
680
681	return request.ifr_media;
682}
683
684
685status_t
686BNetworkDevice::SetMedia(int32 media)
687{
688	ifreq request;
689	request.ifr_media = media;
690	return do_request(request, Name(), SIOCSIFMEDIA);
691}
692
693
694status_t
695BNetworkDevice::GetHardwareAddress(BNetworkAddress& address)
696{
697	ifreq request;
698	status_t status = do_request(request, Name(), SIOCGIFADDR);
699	if (status != B_OK)
700		return status;
701
702	address.SetTo(request.ifr_addr);
703	return B_OK;
704}
705
706
707bool
708BNetworkDevice::IsEthernet()
709{
710	return IFM_TYPE(Media()) == IFM_ETHER;
711}
712
713
714bool
715BNetworkDevice::IsWireless()
716{
717	return IFM_TYPE(Media()) == IFM_IEEE80211;
718}
719
720
721status_t
722BNetworkDevice::Control(int option, void* request)
723{
724	switch (IFM_TYPE(Media())) {
725		case IFM_ETHER:
726			return do_request(*reinterpret_cast<ifreq*>(request),
727				&fName[0], option);
728
729		case IFM_IEEE80211:
730			return do_request(*reinterpret_cast<ieee80211req*>(request),
731				&fName[0], option);
732
733		default:
734			return B_ERROR;
735	}
736}
737
738
739status_t
740BNetworkDevice::Scan(bool wait, bool forceRescan)
741{
742	// Network status listener for change notifications
743	class ScanListener : public BLooper {
744	public:
745		ScanListener(BString iface)
746			:
747			fInterface(iface)
748		{
749			start_watching_network(B_WATCH_NETWORK_WLAN_CHANGES, this);
750		}
751		virtual ~ScanListener()
752		{
753			stop_watching_network(this);
754		}
755
756	protected:
757		virtual void MessageReceived(BMessage *message)
758		{
759			if (message->what != B_NETWORK_MONITOR) {
760				BLooper::MessageReceived(message);
761				return;
762			}
763
764			BString interfaceName;
765			if (message->FindString("interface", &interfaceName) != B_OK)
766				return;
767			// See comment in AutoconfigLooper::_NetworkMonitorNotification
768			// for the reason as to why we use FindFirst instead of ==.
769			if (fInterface.FindFirst(interfaceName) < 0)
770				return;
771			if (message->FindInt32("opcode") != B_NETWORK_WLAN_SCANNED)
772				return;
773
774			Lock();
775			Quit();
776		}
777
778	private:
779		BString fInterface;
780	};
781
782	ScanListener* listener = NULL;
783	if (wait)
784		listener = new ScanListener(Name());
785
786	// Trigger the scan
787	struct ieee80211_scan_req request;
788	memset(&request, 0, sizeof(request));
789	request.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
790		| IEEE80211_IOC_SCAN_BGSCAN
791		| IEEE80211_IOC_SCAN_NOPICK
792		| IEEE80211_IOC_SCAN_ONCE
793		| (forceRescan ? IEEE80211_IOC_SCAN_FLUSH : 0);
794	request.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
795	request.sr_nssid = 0;
796
797	status_t status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request,
798		sizeof(request));
799
800	// If there are no VAPs running, the net80211 layer will return ENXIO.
801	// Try to bring up the interface (which should start a VAP) and try again.
802	if (status == ENXIO) {
803		struct ieee80211req dummy;
804		status = set_80211(Name(), IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP, &dummy,
805			sizeof(dummy));
806		if (status != B_OK)
807			return status;
808
809		status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request,
810			sizeof(request));
811	}
812
813	// If there is already a scan currently running, it's probably an "infinite"
814	// one, which we of course don't want to wait for. So just return immediately
815	// if that's the case.
816	if (status == EINPROGRESS) {
817		delete listener;
818		return B_OK;
819	}
820
821	if (!wait || status != B_OK) {
822		delete listener;
823		return status;
824	}
825
826	while (wait_for_thread(listener->Run(), NULL) == B_INTERRUPTED)
827		;
828	return B_OK;
829}
830
831
832status_t
833BNetworkDevice::GetNetworks(wireless_network*& networks, uint32& count)
834{
835	return get_scan_results(Name(), networks, count);
836}
837
838
839status_t
840BNetworkDevice::GetNetwork(const char* name, wireless_network& network)
841{
842	if (name == NULL || name[0] == '\0')
843		return B_BAD_VALUE;
844
845	return get_network(Name(), network, UINT32_MAX, NULL, name);
846}
847
848
849status_t
850BNetworkDevice::GetNetwork(const BNetworkAddress& address,
851	wireless_network& network)
852{
853	if (address.Family() != AF_LINK)
854		return B_BAD_VALUE;
855
856	return get_network(Name(), network, UINT32_MAX, &address, NULL);
857}
858
859
860status_t
861BNetworkDevice::JoinNetwork(const char* name, const char* password)
862{
863	if (name == NULL || name[0] == '\0')
864		return B_BAD_VALUE;
865
866	BMessage message(kMsgJoinNetwork);
867	status_t status = message.AddString("device", Name());
868
869	if (status == B_OK)
870		status = message.AddString("name", name);
871	if (status == B_OK && password != NULL)
872		status = message.AddString("password", password);
873	if (status != B_OK)
874		return status;
875
876	// Send message to the net_server
877
878	BMessenger networkServer(kNetServerSignature);
879	BMessage reply;
880	status = networkServer.SendMessage(&message, &reply);
881	if (status == B_OK)
882		reply.FindInt32("status", &status);
883
884	return status;
885}
886
887
888status_t
889BNetworkDevice::JoinNetwork(const wireless_network& network,
890	const char* password)
891{
892	return JoinNetwork(network.address, password);
893}
894
895
896status_t
897BNetworkDevice::JoinNetwork(const BNetworkAddress& address,
898	const char* password)
899{
900	if (address.InitCheck() != B_OK)
901		return B_BAD_VALUE;
902
903	BMessage message(kMsgJoinNetwork);
904	status_t status = message.AddString("device", Name());
905
906	if (status == B_OK) {
907		status = message.AddFlat("address",
908			const_cast<BNetworkAddress*>(&address));
909	}
910	if (status == B_OK && password != NULL)
911		status = message.AddString("password", password);
912	if (status != B_OK)
913		return status;
914
915	// Send message to the net_server
916
917	BMessenger networkServer(kNetServerSignature);
918	BMessage reply;
919	status = networkServer.SendMessage(&message, &reply);
920	if (status == B_OK)
921		reply.FindInt32("status", &status);
922
923	return status;
924}
925
926
927status_t
928BNetworkDevice::LeaveNetwork(const char* name)
929{
930	BMessage message(kMsgLeaveNetwork);
931	status_t status = message.AddString("device", Name());
932	if (status == B_OK)
933		status = message.AddString("name", name);
934	if (status == B_OK)
935		status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED);
936	if (status != B_OK)
937		return status;
938
939	BMessenger networkServer(kNetServerSignature);
940	BMessage reply;
941	status = networkServer.SendMessage(&message, &reply);
942	if (status == B_OK)
943		reply.FindInt32("status", &status);
944
945	return status;
946}
947
948
949status_t
950BNetworkDevice::LeaveNetwork(const wireless_network& network)
951{
952	return LeaveNetwork(network.address);
953}
954
955
956status_t
957BNetworkDevice::LeaveNetwork(const BNetworkAddress& address)
958{
959	BMessage message(kMsgLeaveNetwork);
960	status_t status = message.AddString("device", Name());
961	if (status == B_OK) {
962		status = message.AddFlat("address",
963			const_cast<BNetworkAddress*>(&address));
964	}
965	if (status == B_OK)
966		status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED);
967	if (status != B_OK)
968		return status;
969
970	BMessenger networkServer(kNetServerSignature);
971	BMessage reply;
972	status = networkServer.SendMessage(&message, &reply);
973	if (status == B_OK)
974		reply.FindInt32("status", &status);
975
976	return status;
977}
978
979
980status_t
981BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
982	wireless_network& network)
983{
984	BNetworkAddress address;
985	status_t status = GetNextAssociatedNetwork(cookie, address);
986	if (status != B_OK)
987		return status;
988
989	return GetNetwork(address, network);
990}
991
992
993status_t
994BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
995	BNetworkAddress& address)
996{
997	// We currently support only a single associated network
998	if (cookie != 0)
999		return B_ENTRY_NOT_FOUND;
1000
1001	uint8 mac[IEEE80211_ADDR_LEN];
1002	int32 length = IEEE80211_ADDR_LEN;
1003	status_t status = get_80211(Name(), IEEE80211_IOC_BSSID, mac, length);
1004	if (status != B_OK)
1005		return status;
1006
1007	if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0
1008			&& mac[5] == 0) {
1009		return B_ENTRY_NOT_FOUND;
1010	}
1011
1012	address.SetToLinkLevel(mac, IEEE80211_ADDR_LEN);
1013	cookie++;
1014	return B_OK;
1015}
1016