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