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