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
get_80211(const char * name,int32 type,void * data,int32 & length)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
set_80211(const char * name,int32 type,void * data,int32 length=0,int32 value=0)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
do_request(T & request,const char * name,int option)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
do_request(ieee80211req & request,const char * name,int option)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
read_le16(uint8 * & data,int32 & length)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
read_le32(uint8 * & data,int32 & length)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
from_rsn_cipher(uint32 cipher)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
from_rsn_key_mode(uint32 mode)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
parse_ie_rsn_wpa(wireless_network & network,uint8 * & data,int32 & length)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
parse_ie_rsn(wireless_network & network,ie_data * ie)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
parse_ie_wpa(wireless_network & network,ie_data * ie)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
parse_ie(wireless_network & network,uint8 * _ie,int32 ieLength)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
parse_ie(wireless_network & network,struct ieee80211req_sta_info & info)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
parse_ie(wireless_network & network,struct ieee80211req_scan_result & result)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
get_ssid_from_ie(char * name,uint8 * _ie,int32 ieLength)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
get_ssid_from_ie(char * name,struct ieee80211req_sta_info & info)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
fill_wireless_network(wireless_network & network,struct ieee80211req_sta_info & info)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
fill_wireless_network(wireless_network & network,const char * networkName,struct ieee80211req_scan_result & result)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
get_scan_results(const char * device,wireless_network * & networks,uint32 & count)427 get_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
479 static status_t
get_scan_result(const char * device,wireless_network & network,uint32 index,const BNetworkAddress * address,const char * name)480 get_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
530 static status_t
get_station(const char * device,wireless_network & network,uint32 index,const BNetworkAddress * address,const char * name)531 get_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
581 static status_t
get_network(const char * device,wireless_network & network,uint32 index,const BNetworkAddress * address,const char * name)582 get_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
BNetworkDevice()599 BNetworkDevice::BNetworkDevice()
600 {
601 Unset();
602 }
603
604
BNetworkDevice(const char * name)605 BNetworkDevice::BNetworkDevice(const char* name)
606 {
607 SetTo(name);
608 }
609
610
~BNetworkDevice()611 BNetworkDevice::~BNetworkDevice()
612 {
613 }
614
615
616 void
Unset()617 BNetworkDevice::Unset()
618 {
619 fName[0] = '\0';
620 }
621
622
623 void
SetTo(const char * name)624 BNetworkDevice::SetTo(const char* name)
625 {
626 strlcpy(fName, name, IF_NAMESIZE);
627 }
628
629
630 const char*
Name() const631 BNetworkDevice::Name() const
632 {
633 return fName;
634 }
635
636
637 bool
Exists() const638 BNetworkDevice::Exists() const
639 {
640 ifreq request;
641 return do_request(request, Name(), SIOCGIFINDEX) == B_OK;
642 }
643
644
645 uint32
Index() const646 BNetworkDevice::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
656 uint32
Flags() const657 BNetworkDevice::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
667 bool
HasLink() const668 BNetworkDevice::HasLink() const
669 {
670 return (Flags() & IFF_LINK) != 0;
671 }
672
673
674 int32
Media() const675 BNetworkDevice::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
685 status_t
SetMedia(int32 media)686 BNetworkDevice::SetMedia(int32 media)
687 {
688 ifreq request;
689 request.ifr_media = media;
690 return do_request(request, Name(), SIOCSIFMEDIA);
691 }
692
693
694 status_t
GetHardwareAddress(BNetworkAddress & address)695 BNetworkDevice::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
707 bool
IsEthernet()708 BNetworkDevice::IsEthernet()
709 {
710 return IFM_TYPE(Media()) == IFM_ETHER;
711 }
712
713
714 bool
IsWireless()715 BNetworkDevice::IsWireless()
716 {
717 return IFM_TYPE(Media()) == IFM_IEEE80211;
718 }
719
720
721 status_t
Control(int option,void * request)722 BNetworkDevice::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
739 status_t
Scan(bool wait,bool forceRescan)740 BNetworkDevice::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
832 status_t
GetNetworks(wireless_network * & networks,uint32 & count)833 BNetworkDevice::GetNetworks(wireless_network*& networks, uint32& count)
834 {
835 return get_scan_results(Name(), networks, count);
836 }
837
838
839 status_t
GetNetwork(const char * name,wireless_network & network)840 BNetworkDevice::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
849 status_t
GetNetwork(const BNetworkAddress & address,wireless_network & network)850 BNetworkDevice::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
860 status_t
JoinNetwork(const char * name,const char * password)861 BNetworkDevice::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
888 status_t
JoinNetwork(const wireless_network & network,const char * password)889 BNetworkDevice::JoinNetwork(const wireless_network& network,
890 const char* password)
891 {
892 return JoinNetwork(network.address, password);
893 }
894
895
896 status_t
JoinNetwork(const BNetworkAddress & address,const char * password)897 BNetworkDevice::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
927 status_t
LeaveNetwork(const char * name)928 BNetworkDevice::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
949 status_t
LeaveNetwork(const wireless_network & network)950 BNetworkDevice::LeaveNetwork(const wireless_network& network)
951 {
952 return LeaveNetwork(network.address);
953 }
954
955
956 status_t
LeaveNetwork(const BNetworkAddress & address)957 BNetworkDevice::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
980 status_t
GetNextAssociatedNetwork(uint32 & cookie,wireless_network & network)981 BNetworkDevice::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
993 status_t
GetNextAssociatedNetwork(uint32 & cookie,BNetworkAddress & address)994 BNetworkDevice::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