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