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 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 54 if (socket < 0) 55 return errno; 56 57 FileDescriptorCloser closer(socket); 58 59 struct ieee80211req ireq; 60 strlcpy(ireq.i_name, name, IF_NAMESIZE); 61 ireq.i_type = type; 62 ireq.i_val = 0; 63 ireq.i_len = length; 64 ireq.i_data = data; 65 66 if (ioctl(socket, SIOCG80211, &ireq, sizeof(struct ieee80211req)) < 0) 67 return errno; 68 69 length = ireq.i_len; 70 return B_OK; 71 } 72 73 74 static status_t 75 set_80211(const char* name, int32 type, void* data, 76 int32 length = 0, int32 value = 0) 77 { 78 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 79 if (socket < 0) 80 return errno; 81 82 FileDescriptorCloser closer(socket); 83 84 struct ieee80211req ireq; 85 strlcpy(ireq.i_name, name, IF_NAMESIZE); 86 ireq.i_type = type; 87 ireq.i_val = value; 88 ireq.i_len = length; 89 ireq.i_data = data; 90 91 if (ioctl(socket, SIOCS80211, &ireq, sizeof(struct ieee80211req)) < 0) 92 return errno; 93 94 return B_OK; 95 } 96 97 98 template<typename T> status_t 99 do_request(T& request, const char* name, int option) 100 { 101 int socket = ::socket(AF_LINK, SOCK_DGRAM, 0); 102 if (socket < 0) 103 return errno; 104 105 FileDescriptorCloser closer(socket); 106 107 strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE); 108 109 if (ioctl(socket, option, &request, sizeof(T)) < 0) 110 return errno; 111 112 return B_OK; 113 } 114 115 116 template<> status_t 117 do_request<ieee80211req>(ieee80211req& request, const char* name, int option) 118 { 119 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 120 if (socket < 0) 121 return errno; 122 123 FileDescriptorCloser closer(socket); 124 125 strlcpy(((struct ieee80211req&)request).i_name, name, IFNAMSIZ); 126 127 if (ioctl(socket, option, &request, sizeof(request)) < 0) 128 return errno; 129 130 return B_OK; 131 } 132 133 134 //! Read a 16 bit little endian value 135 static uint16 136 read_le16(uint8*& data, int32& length) 137 { 138 uint16 value = B_LENDIAN_TO_HOST_INT16(*(uint16*)data); 139 data += 2; 140 length -= 2; 141 return value; 142 } 143 144 145 //! Read a 32 bit little endian value 146 static uint32 147 read_le32(uint8*& data, int32& length) 148 { 149 uint32 value = B_LENDIAN_TO_HOST_INT32(*(uint32*)data); 150 data += 4; 151 length -= 4; 152 return value; 153 } 154 155 156 static uint32 157 from_rsn_cipher(uint32 cipher) 158 { 159 if ((cipher & 0xffffff) != RSN_OUI) 160 return B_NETWORK_CIPHER_CCMP; 161 162 switch (cipher >> 24) { 163 case RSN_CSE_NULL: 164 return B_NETWORK_CIPHER_NONE; 165 case RSN_CSE_WEP40: 166 return B_NETWORK_CIPHER_WEP_40; 167 case RSN_CSE_WEP104: 168 return B_NETWORK_CIPHER_WEP_104; 169 case RSN_CSE_TKIP: 170 return B_NETWORK_CIPHER_TKIP; 171 default: 172 case RSN_CSE_CCMP: 173 return B_NETWORK_CIPHER_CCMP; 174 case RSN_CSE_WRAP: 175 return B_NETWORK_CIPHER_AES_128_CMAC; 176 } 177 } 178 179 180 static uint32 181 from_rsn_key_mode(uint32 mode) 182 { 183 if ((mode & 0xffffff) != RSN_OUI) 184 return B_KEY_MODE_IEEE802_1X; 185 186 switch (mode >> 24) { 187 default: 188 case RSN_ASE_8021X_UNSPEC: 189 return B_KEY_MODE_IEEE802_1X; 190 case RSN_ASE_8021X_PSK: 191 return B_KEY_MODE_PSK; 192 // the following are currently not defined in net80211 193 case 3: 194 return B_KEY_MODE_FT_IEEE802_1X; 195 case 4: 196 return B_KEY_MODE_FT_PSK; 197 case 5: 198 return B_KEY_MODE_IEEE802_1X_SHA256; 199 case 6: 200 return B_KEY_MODE_PSK_SHA256; 201 } 202 } 203 204 205 //! Parse RSN/WPA information elements common data 206 static void 207 parse_ie_rsn_wpa(wireless_network& network, uint8*& data, int32& length) 208 { 209 if (length >= 4) { 210 // parse group cipher 211 network.group_cipher = from_rsn_cipher(read_le32(data, length)); 212 } else if (length > 0) 213 return; 214 215 if (length >= 2) { 216 // parse unicast cipher 217 uint16 count = read_le16(data, length); 218 network.cipher = 0; 219 220 for (uint16 i = 0; i < count; i++) { 221 if (length < 4) 222 return; 223 network.cipher |= from_rsn_cipher(read_le32(data, length)); 224 } 225 } else if (length > 0) 226 return; 227 228 if (length >= 2) { 229 // parse key management mode 230 uint16 count = read_le16(data, length); 231 network.key_mode = 0; 232 233 for (uint16 i = 0; i < count; i++) { 234 if (length < 4) 235 return; 236 network.key_mode |= from_rsn_key_mode(read_le32(data, length)); 237 } 238 } else if (length > 0) 239 return; 240 241 // TODO: capabilities, and PMKID following in case of RSN 242 } 243 244 245 //! Parse RSN (Robust Security Network) information element. 246 static void 247 parse_ie_rsn(wireless_network& network, ie_data* ie) 248 { 249 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2; 250 network.cipher = B_NETWORK_CIPHER_CCMP; 251 network.group_cipher = B_NETWORK_CIPHER_CCMP; 252 network.key_mode = B_KEY_MODE_IEEE802_1X; 253 254 int32 length = ie->length; 255 if (length < 2) 256 return; 257 258 uint8* data = ie->data; 259 260 uint16 version = read_le16(data, length); 261 if (version != RSN_VERSION) 262 return; 263 264 parse_ie_rsn_wpa(network, data, length); 265 } 266 267 268 //! Parse WPA information element. 269 static bool 270 parse_ie_wpa(wireless_network& network, ie_data* ie) 271 { 272 int32 length = ie->length; 273 if (length < 6) 274 return false; 275 276 uint8* data = ie->data; 277 278 uint32 oui = read_le32(data, length); 279 TRACE(" oui: %" B_PRIx32 "\n", oui); 280 if (oui != ((WPA_OUI_TYPE << 24) | WPA_OUI)) 281 return false; 282 283 uint16 version = read_le16(data, length); 284 if (version != WPA_VERSION) 285 return false; 286 287 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA; 288 network.cipher = B_NETWORK_CIPHER_TKIP; 289 network.group_cipher = B_NETWORK_CIPHER_TKIP; 290 network.key_mode = B_KEY_MODE_IEEE802_1X; 291 292 parse_ie_rsn_wpa(network, data, length); 293 return true; 294 } 295 296 297 //! Parse information elements. 298 static void 299 parse_ie(wireless_network& network, uint8* _ie, int32 ieLength) 300 { 301 struct ie_data* ie = (ie_data*)_ie; 302 bool hadRSN = false; 303 bool hadWPA = false; 304 305 while (ieLength > 1) { 306 TRACE("ie type %u\n", ie->type); 307 switch (ie->type) { 308 case IEEE80211_ELEMID_SSID: 309 strlcpy(network.name, (char*)ie->data, 310 min_c(ie->length + 1, (int)sizeof(network.name))); 311 break; 312 case IEEE80211_ELEMID_RSN: 313 parse_ie_rsn(network, ie); 314 hadRSN = true; 315 break; 316 case IEEE80211_ELEMID_VENDOR: 317 if (!hadRSN && parse_ie_wpa(network, ie)) 318 hadWPA = true; 319 break; 320 } 321 322 ieLength -= 2 + ie->length; 323 ie = (ie_data*)((uint8*)ie + 2 + ie->length); 324 } 325 326 if (hadRSN || hadWPA) { 327 // Determine authentication mode 328 329 if ((network.key_mode & (B_KEY_MODE_IEEE802_1X_SHA256 330 | B_KEY_MODE_PSK_SHA256)) != 0) { 331 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2; 332 } else if ((network.key_mode & (B_KEY_MODE_IEEE802_1X 333 | B_KEY_MODE_PSK | B_KEY_MODE_FT_IEEE802_1X 334 | B_KEY_MODE_FT_PSK)) != 0) { 335 if (!hadRSN) 336 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA; 337 } else if ((network.key_mode & B_KEY_MODE_NONE) != 0) { 338 if ((network.cipher & (B_NETWORK_CIPHER_WEP_40 339 | B_NETWORK_CIPHER_WEP_104)) != 0) 340 network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP; 341 else 342 network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE; 343 } 344 } 345 } 346 347 348 static void 349 parse_ie(wireless_network& network, struct ieee80211req_sta_info& info) 350 { 351 parse_ie(network, (uint8*)&info + info.isi_ie_off, info.isi_ie_len); 352 } 353 354 355 static void 356 parse_ie(wireless_network& network, struct ieee80211req_scan_result& result) 357 { 358 parse_ie(network, (uint8*)&result + result.isr_ie_off + result.isr_ssid_len 359 + result.isr_meshid_len, result.isr_ie_len); 360 } 361 362 363 static bool 364 get_ssid_from_ie(char* name, uint8* _ie, int32 ieLength) 365 { 366 struct ie_data* ie = (ie_data*)_ie; 367 368 while (ieLength > 1) { 369 switch (ie->type) { 370 case IEEE80211_ELEMID_SSID: 371 strlcpy(name, (char*)ie->data, min_c(ie->length + 1, 32)); 372 return true; 373 } 374 375 ieLength -= 2 + ie->length; 376 ie = (ie_data*)((uint8*)ie + 2 + ie->length); 377 } 378 return false; 379 } 380 381 382 static bool 383 get_ssid_from_ie(char* name, struct ieee80211req_sta_info& info) 384 { 385 return get_ssid_from_ie(name, (uint8*)&info + info.isi_ie_off, 386 info.isi_ie_len); 387 } 388 389 390 static void 391 fill_wireless_network(wireless_network& network, 392 struct ieee80211req_sta_info& info) 393 { 394 network.name[0] = '\0'; 395 network.address.SetToLinkLevel(info.isi_macaddr, 396 IEEE80211_ADDR_LEN); 397 network.signal_strength = info.isi_rssi; 398 network.noise_level = info.isi_noise; 399 network.flags |= (info.isi_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0 400 ? B_NETWORK_IS_ENCRYPTED : 0; 401 402 network.authentication_mode = 0; 403 network.cipher = 0; 404 network.group_cipher = 0; 405 network.key_mode = 0; 406 407 parse_ie(network, info); 408 } 409 410 411 static void 412 fill_wireless_network(wireless_network& network, const char* networkName, 413 struct ieee80211req_scan_result& result) 414 { 415 strlcpy(network.name, networkName, sizeof(network.name)); 416 network.address.SetToLinkLevel(result.isr_bssid, 417 IEEE80211_ADDR_LEN); 418 network.signal_strength = result.isr_rssi; 419 network.noise_level = result.isr_noise; 420 network.flags = (result.isr_capinfo & IEEE80211_CAPINFO_PRIVACY) 421 != 0 ? B_NETWORK_IS_ENCRYPTED : 0; 422 423 network.authentication_mode = 0; 424 network.cipher = 0; 425 network.group_cipher = 0; 426 network.key_mode = 0; 427 428 parse_ie(network, result); 429 } 430 431 432 static status_t 433 get_scan_result(const char* device, wireless_network& network, uint32 index, 434 const BNetworkAddress* address, const char* name) 435 { 436 if (address != NULL && address->Family() != AF_LINK) 437 return B_BAD_VALUE; 438 439 const size_t kBufferSize = 65535; 440 uint8* buffer = (uint8*)malloc(kBufferSize); 441 if (buffer == NULL) 442 return B_NO_MEMORY; 443 444 MemoryDeleter deleter(buffer); 445 446 int32 length = kBufferSize; 447 status_t status = get_80211(device, IEEE80211_IOC_SCAN_RESULTS, buffer, 448 length); 449 if (status != B_OK) 450 return status; 451 452 int32 bytesLeft = length; 453 uint8* entry = buffer; 454 uint32 count = 0; 455 456 while (bytesLeft > (int32)sizeof(struct ieee80211req_scan_result)) { 457 ieee80211req_scan_result* result 458 = (ieee80211req_scan_result*)entry; 459 460 char networkName[32]; 461 strlcpy(networkName, (char*)(result + 1), 462 min_c((int)sizeof(networkName), result->isr_ssid_len + 1)); 463 464 if (index == count || (address != NULL && !memcmp( 465 address->LinkLevelAddress(), result->isr_bssid, 466 IEEE80211_ADDR_LEN)) 467 || (name != NULL && !strcmp(networkName, name))) { 468 // Fill wireless_network with scan result data 469 fill_wireless_network(network, networkName, *result); 470 return B_OK; 471 } 472 473 entry += result->isr_len; 474 bytesLeft -= result->isr_len; 475 count++; 476 } 477 478 return B_ENTRY_NOT_FOUND; 479 } 480 481 482 static status_t 483 get_station(const char* device, wireless_network& network, uint32 index, 484 const BNetworkAddress* address, const char* name) 485 { 486 if (address != NULL && address->Family() != AF_LINK) 487 return B_BAD_VALUE; 488 489 const size_t kBufferSize = 65535; 490 uint8* buffer = (uint8*)malloc(kBufferSize); 491 if (buffer == NULL) 492 return B_NO_MEMORY; 493 494 MemoryDeleter deleter(buffer); 495 496 struct ieee80211req_sta_req& request = *(ieee80211req_sta_req*)buffer; 497 if (address != NULL) { 498 memcpy(request.is_u.macaddr, address->LinkLevelAddress(), 499 IEEE80211_ADDR_LEN); 500 } else 501 memset(request.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); 502 503 int32 length = kBufferSize; 504 status_t status = get_80211(device, IEEE80211_IOC_STA_INFO, &request, 505 length); 506 if (status != B_OK) 507 return status; 508 509 int32 bytesLeft = length; 510 uint8* entry = (uint8*)&request.info[0]; 511 uint32 count = 0; 512 513 while (bytesLeft > (int32)sizeof(struct ieee80211req_sta_info)) { 514 ieee80211req_sta_info* info = (ieee80211req_sta_info*)entry; 515 516 char networkName[32]; 517 get_ssid_from_ie(networkName, *info); 518 if (index == count || address != NULL 519 || (name != NULL && !strcmp(networkName, name))) { 520 fill_wireless_network(network, *info); 521 return B_OK; 522 } 523 524 entry += info->isi_len; 525 bytesLeft -= info->isi_len; 526 count++; 527 } 528 529 return B_ENTRY_NOT_FOUND; 530 } 531 532 533 static status_t 534 get_network(const char* device, wireless_network& network, uint32 index, 535 const BNetworkAddress* address, const char* name) 536 { 537 status_t status = get_station(device, network, index, address, name); 538 if (status != B_OK) 539 return get_scan_result(device, network, index, address, name); 540 541 return B_OK; 542 } 543 544 545 } // namespace 546 547 548 // #pragma mark - 549 550 551 BNetworkDevice::BNetworkDevice() 552 { 553 Unset(); 554 } 555 556 557 BNetworkDevice::BNetworkDevice(const char* name) 558 { 559 SetTo(name); 560 } 561 562 563 BNetworkDevice::~BNetworkDevice() 564 { 565 } 566 567 568 void 569 BNetworkDevice::Unset() 570 { 571 fName[0] = '\0'; 572 } 573 574 575 void 576 BNetworkDevice::SetTo(const char* name) 577 { 578 strlcpy(fName, name, IF_NAMESIZE); 579 } 580 581 582 const char* 583 BNetworkDevice::Name() const 584 { 585 return fName; 586 } 587 588 589 bool 590 BNetworkDevice::Exists() const 591 { 592 ifreq request; 593 return do_request(request, Name(), SIOCGIFINDEX) == B_OK; 594 } 595 596 597 uint32 598 BNetworkDevice::Index() const 599 { 600 ifreq request; 601 if (do_request(request, Name(), SIOCGIFINDEX) != B_OK) 602 return 0; 603 604 return request.ifr_index; 605 } 606 607 608 uint32 609 BNetworkDevice::Flags() const 610 { 611 ifreq request; 612 if (do_request(request, Name(), SIOCGIFFLAGS) != B_OK) 613 return 0; 614 615 return request.ifr_flags; 616 } 617 618 619 bool 620 BNetworkDevice::HasLink() const 621 { 622 return (Flags() & IFF_LINK) != 0; 623 } 624 625 626 int32 627 BNetworkDevice::CountMedia() const 628 { 629 ifmediareq request; 630 request.ifm_count = 0; 631 request.ifm_ulist = NULL; 632 633 if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK) 634 return -1; 635 636 return request.ifm_count; 637 } 638 639 640 int32 641 BNetworkDevice::Media() const 642 { 643 ifmediareq request; 644 request.ifm_count = 0; 645 request.ifm_ulist = NULL; 646 647 if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK) 648 return -1; 649 650 return request.ifm_current; 651 } 652 653 654 int32 655 BNetworkDevice::GetMediaAt(int32 index) const 656 { 657 // TODO: this could do some caching 658 return 0; 659 } 660 661 662 status_t 663 BNetworkDevice::SetMedia(int32 media) 664 { 665 ifreq request; 666 request.ifr_media = media; 667 return do_request(request, Name(), SIOCSIFMEDIA); 668 } 669 670 671 status_t 672 BNetworkDevice::GetHardwareAddress(BNetworkAddress& address) 673 { 674 ifreq request; 675 status_t status = do_request(request, Name(), SIOCGIFADDR); 676 if (status != B_OK) 677 return status; 678 679 address.SetTo(request.ifr_addr); 680 return B_OK; 681 } 682 683 684 bool 685 BNetworkDevice::IsEthernet() 686 { 687 return IFM_TYPE(Media()) == IFM_ETHER; 688 } 689 690 691 bool 692 BNetworkDevice::IsWireless() 693 { 694 return IFM_TYPE(Media()) == IFM_IEEE80211; 695 } 696 697 698 status_t 699 BNetworkDevice::Control(int option, void* request) 700 { 701 switch (IFM_TYPE(Media())) { 702 case IFM_ETHER: 703 return do_request(*reinterpret_cast<ifreq*>(request), 704 &fName[0], option); 705 706 case IFM_IEEE80211: 707 return do_request(*reinterpret_cast<ieee80211req*>(request), 708 &fName[0], option); 709 710 default: 711 return B_ERROR; 712 } 713 } 714 715 716 status_t 717 BNetworkDevice::Scan(bool wait, bool forceRescan) 718 { 719 // Network status listener for change notifications 720 class ScanListener : public BLooper { 721 public: 722 ScanListener(BString iface) 723 : 724 fInterface(iface) 725 { 726 start_watching_network(B_WATCH_NETWORK_WLAN_CHANGES, this); 727 } 728 virtual ~ScanListener() 729 { 730 stop_watching_network(this); 731 } 732 733 protected: 734 virtual void MessageReceived(BMessage *message) 735 { 736 if (message->what != B_NETWORK_MONITOR) { 737 BLooper::MessageReceived(message); 738 return; 739 } 740 741 BString interfaceName; 742 if (message->FindString("interface", &interfaceName) != B_OK) 743 return; 744 // See comment in AutoconfigLooper::_NetworkMonitorNotification 745 // for the reason as to why we use FindFirst instead of ==. 746 if (fInterface.FindFirst(interfaceName) < 0) 747 return; 748 if (message->FindInt32("opcode") != B_NETWORK_WLAN_SCANNED) 749 return; 750 751 Lock(); 752 Quit(); 753 } 754 755 private: 756 BString fInterface; 757 }; 758 759 ScanListener* listener = NULL; 760 if (wait) 761 listener = new ScanListener(Name()); 762 763 // Trigger the scan 764 struct ieee80211_scan_req request; 765 memset(&request, 0, sizeof(request)); 766 request.sr_flags = IEEE80211_IOC_SCAN_ACTIVE 767 | IEEE80211_IOC_SCAN_BGSCAN 768 | IEEE80211_IOC_SCAN_NOPICK 769 | IEEE80211_IOC_SCAN_ONCE 770 | (forceRescan ? IEEE80211_IOC_SCAN_FLUSH : 0); 771 request.sr_duration = IEEE80211_IOC_SCAN_FOREVER; 772 request.sr_nssid = 0; 773 774 status_t status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request, 775 sizeof(request)); 776 777 // If there are no VAPs running, the net80211 layer will return ENXIO. 778 // Try to bring up the interface (which should start a VAP) and try again. 779 if (status == ENXIO) { 780 struct ieee80211req dummy; 781 status = set_80211(Name(), IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP, &dummy, 782 sizeof(dummy)); 783 if (status != B_OK) 784 return status; 785 786 status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request, 787 sizeof(request)); 788 } 789 790 // If there is already a scan currently running, it's probably an "infinite" 791 // one, which we of course don't want to wait for. So just return immediately 792 // if that's the case. 793 if (status == EINPROGRESS) { 794 delete listener; 795 return B_OK; 796 } 797 798 if (!wait || status != B_OK) { 799 delete listener; 800 return status; 801 } 802 803 while (wait_for_thread(listener->Run(), NULL) == B_INTERRUPTED) 804 ; 805 return B_OK; 806 } 807 808 809 status_t 810 BNetworkDevice::GetNextNetwork(uint32& cookie, wireless_network& network) 811 { 812 status_t status = get_scan_result(Name(), network, cookie, NULL, NULL); 813 if (status != B_OK) 814 return status; 815 816 cookie++; 817 return B_OK; 818 } 819 820 821 status_t 822 BNetworkDevice::GetNetwork(const char* name, wireless_network& network) 823 { 824 if (name == NULL || name[0] == '\0') 825 return B_BAD_VALUE; 826 827 return get_network(Name(), network, UINT32_MAX, NULL, name); 828 } 829 830 831 status_t 832 BNetworkDevice::GetNetwork(const BNetworkAddress& address, 833 wireless_network& network) 834 { 835 if (address.Family() != AF_LINK) 836 return B_BAD_VALUE; 837 838 return get_network(Name(), network, UINT32_MAX, &address, NULL); 839 } 840 841 842 status_t 843 BNetworkDevice::JoinNetwork(const char* name, const char* password) 844 { 845 if (name == NULL || name[0] == '\0') 846 return B_BAD_VALUE; 847 848 BMessage message(kMsgJoinNetwork); 849 status_t status = message.AddString("device", Name()); 850 851 if (status == B_OK) 852 status = message.AddString("name", name); 853 if (status == B_OK && password != NULL) 854 status = message.AddString("password", password); 855 if (status != B_OK) 856 return status; 857 858 // Send message to the net_server 859 860 BMessenger networkServer(kNetServerSignature); 861 BMessage reply; 862 status = networkServer.SendMessage(&message, &reply); 863 if (status == B_OK) 864 reply.FindInt32("status", &status); 865 866 return status; 867 } 868 869 870 status_t 871 BNetworkDevice::JoinNetwork(const wireless_network& network, 872 const char* password) 873 { 874 return JoinNetwork(network.address, password); 875 } 876 877 878 status_t 879 BNetworkDevice::JoinNetwork(const BNetworkAddress& address, 880 const char* password) 881 { 882 if (address.InitCheck() != B_OK) 883 return B_BAD_VALUE; 884 885 BMessage message(kMsgJoinNetwork); 886 status_t status = message.AddString("device", Name()); 887 888 if (status == B_OK) { 889 status = message.AddFlat("address", 890 const_cast<BNetworkAddress*>(&address)); 891 } 892 if (status == B_OK && password != NULL) 893 status = message.AddString("password", password); 894 if (status != B_OK) 895 return status; 896 897 // Send message to the net_server 898 899 BMessenger networkServer(kNetServerSignature); 900 BMessage reply; 901 status = networkServer.SendMessage(&message, &reply); 902 if (status == B_OK) 903 reply.FindInt32("status", &status); 904 905 return status; 906 } 907 908 909 status_t 910 BNetworkDevice::LeaveNetwork(const char* name) 911 { 912 BMessage message(kMsgLeaveNetwork); 913 status_t status = message.AddString("device", Name()); 914 if (status == B_OK) 915 status = message.AddString("name", name); 916 if (status == B_OK) 917 status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED); 918 if (status != B_OK) 919 return status; 920 921 BMessenger networkServer(kNetServerSignature); 922 BMessage reply; 923 status = networkServer.SendMessage(&message, &reply); 924 if (status == B_OK) 925 reply.FindInt32("status", &status); 926 927 return status; 928 } 929 930 931 status_t 932 BNetworkDevice::LeaveNetwork(const wireless_network& network) 933 { 934 return LeaveNetwork(network.address); 935 } 936 937 938 status_t 939 BNetworkDevice::LeaveNetwork(const BNetworkAddress& address) 940 { 941 BMessage message(kMsgLeaveNetwork); 942 status_t status = message.AddString("device", Name()); 943 if (status == B_OK) { 944 status = message.AddFlat("address", 945 const_cast<BNetworkAddress*>(&address)); 946 } 947 if (status == B_OK) 948 status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED); 949 if (status != B_OK) 950 return status; 951 952 BMessenger networkServer(kNetServerSignature); 953 BMessage reply; 954 status = networkServer.SendMessage(&message, &reply); 955 if (status == B_OK) 956 reply.FindInt32("status", &status); 957 958 return status; 959 } 960 961 962 status_t 963 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie, 964 wireless_network& network) 965 { 966 BNetworkAddress address; 967 status_t status = GetNextAssociatedNetwork(cookie, address); 968 if (status != B_OK) 969 return status; 970 971 return GetNetwork(address, network); 972 } 973 974 975 status_t 976 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie, 977 BNetworkAddress& address) 978 { 979 // We currently support only a single associated network 980 if (cookie != 0) 981 return B_ENTRY_NOT_FOUND; 982 983 uint8 mac[IEEE80211_ADDR_LEN]; 984 int32 length = IEEE80211_ADDR_LEN; 985 status_t status = get_80211(Name(), IEEE80211_IOC_BSSID, mac, length); 986 if (status != B_OK) 987 return status; 988 989 if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 990 && mac[5] == 0) { 991 return B_ENTRY_NOT_FOUND; 992 } 993 994 address.SetToLinkLevel(mac, IEEE80211_ADDR_LEN); 995 cookie++; 996 return B_OK; 997 } 998