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