1 /* 2 * Copyright 2010-2015, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <NetworkDevice.h> 8 9 #include <errno.h> 10 #include <net/if.h> 11 #include <net/if_media.h> 12 #include <stdio.h> 13 #include <sys/sockio.h> 14 15 #include <Looper.h> 16 #include <Messenger.h> 17 18 #include <AutoDeleter.h> 19 #include <NetServer.h> 20 #include <NetworkNotifications.h> 21 22 extern "C" { 23 # include <compat/sys/cdefs.h> 24 # include <compat/sys/ioccom.h> 25 # include <net80211/ieee80211_ioctl.h> 26 } 27 28 29 //#define TRACE_DEVICE 30 #ifdef TRACE_DEVICE 31 # define TRACE(x, ...) printf(x, __VA_ARGS__); 32 #else 33 # define TRACE(x, ...) ; 34 #endif 35 36 37 namespace { 38 39 40 struct ie_data { 41 uint8 type; 42 uint8 length; 43 uint8 data[1]; 44 }; 45 46 47 // #pragma mark - private functions (code shared with net_server) 48 49 50 static status_t 51 get_80211(const char* name, int32 type, void* data, int32& length) 52 { 53 FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0)); 54 if (!socket.IsSet()) 55 return errno; 56 57 struct ieee80211req ireq; 58 strlcpy(ireq.i_name, name, IF_NAMESIZE); 59 ireq.i_type = type; 60 ireq.i_val = 0; 61 ireq.i_len = length; 62 ireq.i_data = data; 63 64 if (ioctl(socket.Get(), SIOCG80211, &ireq, sizeof(struct ieee80211req)) 65 < 0) 66 return errno; 67 68 length = ireq.i_len; 69 return B_OK; 70 } 71 72 73 static status_t 74 set_80211(const char* name, int32 type, void* data, 75 int32 length = 0, int32 value = 0) 76 { 77 FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0)); 78 if (!socket.IsSet()) 79 return errno; 80 81 struct ieee80211req ireq; 82 strlcpy(ireq.i_name, name, IF_NAMESIZE); 83 ireq.i_type = type; 84 ireq.i_val = value; 85 ireq.i_len = length; 86 ireq.i_data = data; 87 88 if (ioctl(socket.Get(), SIOCS80211, &ireq, sizeof(struct ieee80211req)) 89 < 0) 90 return errno; 91 92 return B_OK; 93 } 94 95 96 template<typename T> status_t 97 do_request(T& request, const char* name, int option) 98 { 99 FileDescriptorCloser socket(::socket(AF_LINK, SOCK_DGRAM, 0)); 100 if (!socket.IsSet()) 101 return errno; 102 103 strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE); 104 105 if (ioctl(socket.Get(), option, &request, sizeof(T)) < 0) 106 return errno; 107 108 return B_OK; 109 } 110 111 112 template<> status_t 113 do_request<ieee80211req>(ieee80211req& request, const char* name, int option) 114 { 115 FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0)); 116 if (!socket.IsSet()) 117 return errno; 118 119 strlcpy(((struct ieee80211req&)request).i_name, name, IFNAMSIZ); 120 121 if (ioctl(socket.Get(), option, &request, sizeof(request)) < 0) 122 return errno; 123 124 return B_OK; 125 } 126 127 128 //! Read a 16 bit little endian value 129 static uint16 130 read_le16(uint8*& data, int32& length) 131 { 132 uint16 value = B_LENDIAN_TO_HOST_INT16(*(uint16*)data); 133 data += 2; 134 length -= 2; 135 return value; 136 } 137 138 139 //! Read a 32 bit little endian value 140 static uint32 141 read_le32(uint8*& data, int32& length) 142 { 143 uint32 value = B_LENDIAN_TO_HOST_INT32(*(uint32*)data); 144 data += 4; 145 length -= 4; 146 return value; 147 } 148 149 150 static uint32 151 from_rsn_cipher(uint32 cipher) 152 { 153 if ((cipher & 0xffffff) != RSN_OUI) 154 return B_NETWORK_CIPHER_CCMP; 155 156 switch (cipher >> 24) { 157 case RSN_CSE_NULL: 158 return B_NETWORK_CIPHER_NONE; 159 case RSN_CSE_WEP40: 160 return B_NETWORK_CIPHER_WEP_40; 161 case RSN_CSE_WEP104: 162 return B_NETWORK_CIPHER_WEP_104; 163 case RSN_CSE_TKIP: 164 return B_NETWORK_CIPHER_TKIP; 165 default: 166 case RSN_CSE_CCMP: 167 return B_NETWORK_CIPHER_CCMP; 168 case RSN_CSE_WRAP: 169 return B_NETWORK_CIPHER_AES_128_CMAC; 170 } 171 } 172 173 174 static uint32 175 from_rsn_key_mode(uint32 mode) 176 { 177 if ((mode & 0xffffff) != RSN_OUI) 178 return B_KEY_MODE_IEEE802_1X; 179 180 switch (mode >> 24) { 181 default: 182 case RSN_ASE_8021X_UNSPEC: 183 return B_KEY_MODE_IEEE802_1X; 184 case RSN_ASE_8021X_PSK: 185 return B_KEY_MODE_PSK; 186 // the following are currently not defined in net80211 187 case 3: 188 return B_KEY_MODE_FT_IEEE802_1X; 189 case 4: 190 return B_KEY_MODE_FT_PSK; 191 case 5: 192 return B_KEY_MODE_IEEE802_1X_SHA256; 193 case 6: 194 return B_KEY_MODE_PSK_SHA256; 195 } 196 } 197 198 199 //! Parse RSN/WPA information elements common data 200 static void 201 parse_ie_rsn_wpa(wireless_network& network, uint8*& data, int32& length) 202 { 203 if (length >= 4) { 204 // parse group cipher 205 network.group_cipher = from_rsn_cipher(read_le32(data, length)); 206 } else if (length > 0) 207 return; 208 209 if (length >= 2) { 210 // parse unicast cipher 211 uint16 count = read_le16(data, length); 212 network.cipher = 0; 213 214 for (uint16 i = 0; i < count; i++) { 215 if (length < 4) 216 return; 217 network.cipher |= from_rsn_cipher(read_le32(data, length)); 218 } 219 } else if (length > 0) 220 return; 221 222 if (length >= 2) { 223 // parse key management mode 224 uint16 count = read_le16(data, length); 225 network.key_mode = 0; 226 227 for (uint16 i = 0; i < count; i++) { 228 if (length < 4) 229 return; 230 network.key_mode |= from_rsn_key_mode(read_le32(data, length)); 231 } 232 } else if (length > 0) 233 return; 234 235 // TODO: capabilities, and PMKID following in case of RSN 236 } 237 238 239 //! Parse RSN (Robust Security Network) information element. 240 static void 241 parse_ie_rsn(wireless_network& network, ie_data* ie) 242 { 243 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2; 244 network.cipher = B_NETWORK_CIPHER_CCMP; 245 network.group_cipher = B_NETWORK_CIPHER_CCMP; 246 network.key_mode = B_KEY_MODE_IEEE802_1X; 247 248 int32 length = ie->length; 249 if (length < 2) 250 return; 251 252 uint8* data = ie->data; 253 254 uint16 version = read_le16(data, length); 255 if (version != RSN_VERSION) 256 return; 257 258 parse_ie_rsn_wpa(network, data, length); 259 } 260 261 262 //! Parse WPA information element. 263 static bool 264 parse_ie_wpa(wireless_network& network, ie_data* ie) 265 { 266 int32 length = ie->length; 267 if (length < 6) 268 return false; 269 270 uint8* data = ie->data; 271 272 uint32 oui = read_le32(data, length); 273 TRACE(" oui: %" B_PRIx32 "\n", oui); 274 if (oui != ((WPA_OUI_TYPE << 24) | WPA_OUI)) 275 return false; 276 277 uint16 version = read_le16(data, length); 278 if (version != WPA_VERSION) 279 return false; 280 281 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA; 282 network.cipher = B_NETWORK_CIPHER_TKIP; 283 network.group_cipher = B_NETWORK_CIPHER_TKIP; 284 network.key_mode = B_KEY_MODE_IEEE802_1X; 285 286 parse_ie_rsn_wpa(network, data, length); 287 return true; 288 } 289 290 291 //! Parse information elements. 292 static void 293 parse_ie(wireless_network& network, uint8* _ie, int32 ieLength) 294 { 295 struct ie_data* ie = (ie_data*)_ie; 296 bool hadRSN = false; 297 bool hadWPA = false; 298 299 while (ieLength > 1) { 300 TRACE("ie type %u\n", ie->type); 301 switch (ie->type) { 302 case IEEE80211_ELEMID_SSID: 303 strlcpy(network.name, (char*)ie->data, 304 min_c(ie->length + 1, (int)sizeof(network.name))); 305 break; 306 case IEEE80211_ELEMID_RSN: 307 parse_ie_rsn(network, ie); 308 hadRSN = true; 309 break; 310 case IEEE80211_ELEMID_VENDOR: 311 if (!hadRSN && parse_ie_wpa(network, ie)) 312 hadWPA = true; 313 break; 314 } 315 316 ieLength -= 2 + ie->length; 317 ie = (ie_data*)((uint8*)ie + 2 + ie->length); 318 } 319 320 if (hadRSN || hadWPA) { 321 // Determine authentication mode 322 323 if ((network.key_mode & (B_KEY_MODE_IEEE802_1X_SHA256 324 | B_KEY_MODE_PSK_SHA256)) != 0) { 325 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2; 326 } else if ((network.key_mode & (B_KEY_MODE_IEEE802_1X 327 | B_KEY_MODE_PSK | B_KEY_MODE_FT_IEEE802_1X 328 | B_KEY_MODE_FT_PSK)) != 0) { 329 if (!hadRSN) 330 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA; 331 } else if ((network.key_mode & B_KEY_MODE_NONE) != 0) { 332 if ((network.cipher & (B_NETWORK_CIPHER_WEP_40 333 | B_NETWORK_CIPHER_WEP_104)) != 0) 334 network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP; 335 else 336 network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE; 337 } 338 } 339 } 340 341 342 static void 343 parse_ie(wireless_network& network, struct ieee80211req_sta_info& info) 344 { 345 parse_ie(network, (uint8*)&info + info.isi_ie_off, info.isi_ie_len); 346 } 347 348 349 static void 350 parse_ie(wireless_network& network, struct ieee80211req_scan_result& result) 351 { 352 parse_ie(network, (uint8*)&result + result.isr_ie_off + result.isr_ssid_len 353 + result.isr_meshid_len, result.isr_ie_len); 354 } 355 356 357 static bool 358 get_ssid_from_ie(char* name, uint8* _ie, int32 ieLength) 359 { 360 struct ie_data* ie = (ie_data*)_ie; 361 362 while (ieLength > 1) { 363 switch (ie->type) { 364 case IEEE80211_ELEMID_SSID: 365 strlcpy(name, (char*)ie->data, min_c(ie->length + 1, 32)); 366 return true; 367 } 368 369 ieLength -= 2 + ie->length; 370 ie = (ie_data*)((uint8*)ie + 2 + ie->length); 371 } 372 return false; 373 } 374 375 376 static bool 377 get_ssid_from_ie(char* name, struct ieee80211req_sta_info& info) 378 { 379 return get_ssid_from_ie(name, (uint8*)&info + info.isi_ie_off, 380 info.isi_ie_len); 381 } 382 383 384 static void 385 fill_wireless_network(wireless_network& network, 386 struct ieee80211req_sta_info& info) 387 { 388 network.name[0] = '\0'; 389 network.address.SetToLinkLevel(info.isi_macaddr, 390 IEEE80211_ADDR_LEN); 391 network.signal_strength = info.isi_rssi; 392 network.noise_level = info.isi_noise; 393 network.flags |= (info.isi_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0 394 ? B_NETWORK_IS_ENCRYPTED : 0; 395 396 network.authentication_mode = 0; 397 network.cipher = 0; 398 network.group_cipher = 0; 399 network.key_mode = 0; 400 401 parse_ie(network, info); 402 } 403 404 405 static void 406 fill_wireless_network(wireless_network& network, const char* networkName, 407 struct ieee80211req_scan_result& result) 408 { 409 strlcpy(network.name, networkName, sizeof(network.name)); 410 network.address.SetToLinkLevel(result.isr_bssid, 411 IEEE80211_ADDR_LEN); 412 network.signal_strength = result.isr_rssi; 413 network.noise_level = result.isr_noise; 414 network.flags = (result.isr_capinfo & IEEE80211_CAPINFO_PRIVACY) 415 != 0 ? B_NETWORK_IS_ENCRYPTED : 0; 416 417 network.authentication_mode = 0; 418 network.cipher = 0; 419 network.group_cipher = 0; 420 network.key_mode = 0; 421 422 parse_ie(network, result); 423 } 424 425 426 static status_t 427 get_scan_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 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 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 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 599 BNetworkDevice::BNetworkDevice() 600 { 601 Unset(); 602 } 603 604 605 BNetworkDevice::BNetworkDevice(const char* name) 606 { 607 SetTo(name); 608 } 609 610 611 BNetworkDevice::~BNetworkDevice() 612 { 613 } 614 615 616 void 617 BNetworkDevice::Unset() 618 { 619 fName[0] = '\0'; 620 } 621 622 623 void 624 BNetworkDevice::SetTo(const char* name) 625 { 626 strlcpy(fName, name, IF_NAMESIZE); 627 } 628 629 630 const char* 631 BNetworkDevice::Name() const 632 { 633 return fName; 634 } 635 636 637 bool 638 BNetworkDevice::Exists() const 639 { 640 ifreq request; 641 return do_request(request, Name(), SIOCGIFINDEX) == B_OK; 642 } 643 644 645 uint32 646 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 657 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 668 BNetworkDevice::HasLink() const 669 { 670 return (Flags() & IFF_LINK) != 0; 671 } 672 673 674 int32 675 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 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 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 708 BNetworkDevice::IsEthernet() 709 { 710 return IFM_TYPE(Media()) == IFM_ETHER; 711 } 712 713 714 bool 715 BNetworkDevice::IsWireless() 716 { 717 return IFM_TYPE(Media()) == IFM_IEEE80211; 718 } 719 720 721 status_t 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 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 833 BNetworkDevice::GetNetworks(wireless_network*& networks, uint32& count) 834 { 835 return get_scan_results(Name(), networks, count); 836 } 837 838 839 status_t 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 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 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 889 BNetworkDevice::JoinNetwork(const wireless_network& network, 890 const char* password) 891 { 892 return JoinNetwork(network.address, password); 893 } 894 895 896 status_t 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 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 950 BNetworkDevice::LeaveNetwork(const wireless_network& network) 951 { 952 return LeaveNetwork(network.address); 953 } 954 955 956 status_t 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 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 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