2 * Copyright 2010-2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include <NetworkDevice.h>
11 #include <net/if_media.h>
13 #include <sys/sockio.h>
15 #include <Messenger.h>
17 #include <AutoDeleter.h>
18 #include <NetServer.h>
21 # include <net80211/ieee80211_ioctl.h>
25 //#define TRACE_DEVICE
27 # define TRACE(x, ...) printf(x, __VA_ARGS__);
29 # define TRACE(x, ...) ;
44 get_80211(const char* name
, int32 type
, void* data
, int32
& length
)
46 int socket
= ::socket(AF_INET
, SOCK_DGRAM
, 0);
50 FileDescriptorCloser
closer(socket
);
52 struct ieee80211req ireq
;
53 strlcpy(ireq
.i_name
, name
, IF_NAMESIZE
);
59 if (ioctl(socket
, SIOCG80211
, &ireq
, sizeof(struct ieee80211req
)) < 0)
67 template<typename T
> status_t
68 do_request(T
& request
, const char* name
, int option
)
70 int socket
= ::socket(AF_LINK
, SOCK_DGRAM
, 0);
74 FileDescriptorCloser
closer(socket
);
76 strlcpy(((struct ifreq
&)request
).ifr_name
, name
, IF_NAMESIZE
);
78 if (ioctl(socket
, option
, &request
, sizeof(T
)) < 0)
85 //! Read a 16 bit little endian value
87 read_le16(uint8
*& data
, int32
& length
)
89 uint16 value
= B_LENDIAN_TO_HOST_INT16(*(uint16
*)data
);
96 //! Read a 32 bit little endian value
98 read_le32(uint8
*& data
, int32
& length
)
100 uint32 value
= B_LENDIAN_TO_HOST_INT32(*(uint32
*)data
);
108 from_rsn_cipher(uint32 cipher
)
110 if ((cipher
& 0xffffff) != RSN_OUI
)
111 return B_NETWORK_CIPHER_CCMP
;
113 switch (cipher
>> 24) {
115 return B_NETWORK_CIPHER_NONE
;
117 return B_NETWORK_CIPHER_WEP_40
;
119 return B_NETWORK_CIPHER_WEP_104
;
121 return B_NETWORK_CIPHER_TKIP
;
124 return B_NETWORK_CIPHER_CCMP
;
126 return B_NETWORK_CIPHER_AES_128_CMAC
;
132 from_rsn_key_mode(uint32 mode
)
134 if ((mode
& 0xffffff) != RSN_OUI
)
135 return B_KEY_MODE_IEEE802_1X
;
137 switch (mode
>> 24) {
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
145 return B_KEY_MODE_FT_IEEE802_1X
;
147 return B_KEY_MODE_FT_PSK
;
149 return B_KEY_MODE_IEEE802_1X_SHA256
;
151 return B_KEY_MODE_PSK_SHA256
;
156 //! Parse RSN/WPA information elements common data
158 parse_ie_rsn_wpa(wireless_network
& network
, uint8
*& data
, int32
& length
)
161 // parse group cipher
162 network
.group_cipher
= from_rsn_cipher(read_le32(data
, length
));
163 } else if (length
> 0)
167 // parse unicast cipher
168 uint16 count
= read_le16(data
, length
);
171 for (uint16 i
= 0; i
< count
; i
++) {
174 network
.cipher
|= from_rsn_cipher(read_le32(data
, length
));
176 } else if (length
> 0)
180 // parse key management mode
181 uint16 count
= read_le16(data
, length
);
182 network
.key_mode
= 0;
184 for (uint16 i
= 0; i
< count
; i
++) {
187 network
.key_mode
|= from_rsn_key_mode(read_le32(data
, length
));
189 } else if (length
> 0)
192 // TODO: capabilities, and PMKID following in case of RSN
196 //! Parse RSN (Robust Security Network) information element.
198 parse_ie_rsn(wireless_network
& network
, ie_data
* ie
)
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
;
205 int32 length
= ie
->length
;
209 uint8
* data
= ie
->data
;
211 uint16 version
= read_le16(data
, length
);
212 if (version
!= RSN_VERSION
)
215 parse_ie_rsn_wpa(network
, data
, length
);
219 //! Parse WPA information element.
221 parse_ie_wpa(wireless_network
& network
, ie_data
* ie
)
223 int32 length
= ie
->length
;
227 uint8
* data
= ie
->data
;
229 uint32 oui
= read_le32(data
, length
);
230 TRACE(" oui: %" B_PRIx32
"\n", oui
);
231 if (oui
!= ((WPA_OUI_TYPE
<< 24) | WPA_OUI
))
234 uint16 version
= read_le16(data
, length
);
235 if (version
!= WPA_VERSION
)
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
;
243 parse_ie_rsn_wpa(network
, data
, length
);
248 //! Parse information elements.
250 parse_ie(wireless_network
& network
, uint8
* _ie
, int32 ieLength
)
252 struct ie_data
* ie
= (ie_data
*)_ie
;
256 while (ieLength
> 1) {
257 TRACE("ie type %u\n", ie
->type
);
259 case IEEE80211_ELEMID_SSID
:
260 strlcpy(network
.name
, (char*)ie
->data
,
261 min_c(ie
->length
+ 1, (int)sizeof(network
.name
)));
263 case IEEE80211_ELEMID_RSN
:
264 parse_ie_rsn(network
, ie
);
267 case IEEE80211_ELEMID_VENDOR
:
268 if (!hadRSN
&& parse_ie_wpa(network
, ie
))
273 ieLength
-= 2 + ie
->length
;
274 ie
= (ie_data
*)((uint8
*)ie
+ 2 + ie
->length
);
277 if (hadRSN
|| hadWPA
) {
278 // Determine authentication mode
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) {
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
;
293 network
.authentication_mode
= B_NETWORK_AUTHENTICATION_NONE
;
300 parse_ie(wireless_network
& network
, struct ieee80211req_sta_info
& info
)
302 parse_ie(network
, (uint8
*)&info
+ info
.isi_ie_off
, info
.isi_ie_len
);
307 parse_ie(wireless_network
& network
, struct ieee80211req_scan_result
& result
)
309 parse_ie(network
, (uint8
*)&result
+ result
.isr_ie_off
+ result
.isr_ssid_len
310 + result
.isr_meshid_len
, result
.isr_ie_len
);
315 get_ssid_from_ie(char* name
, uint8
* _ie
, int32 ieLength
)
317 struct ie_data
* ie
= (ie_data
*)_ie
;
319 while (ieLength
> 1) {
321 case IEEE80211_ELEMID_SSID
:
322 strlcpy(name
, (char*)ie
->data
, min_c(ie
->length
+ 1, 32));
326 ieLength
-= 2 + ie
->length
;
327 ie
= (ie_data
*)((uint8
*)ie
+ 2 + ie
->length
);
334 get_ssid_from_ie(char* name
, struct ieee80211req_sta_info
& info
)
336 return get_ssid_from_ie(name
, (uint8
*)&info
+ info
.isi_ie_off
,
342 fill_wireless_network(wireless_network
& network
,
343 struct ieee80211req_sta_info
& info
)
345 network
.name
[0] = '\0';
346 network
.address
.SetToLinkLevel(info
.isi_macaddr
,
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;
353 network
.authentication_mode
= 0;
355 network
.group_cipher
= 0;
356 network
.key_mode
= 0;
358 parse_ie(network
, info
);
363 fill_wireless_network(wireless_network
& network
, const char* networkName
,
364 struct ieee80211req_scan_result
& result
)
366 strlcpy(network
.name
, networkName
, sizeof(network
.name
));
367 network
.address
.SetToLinkLevel(result
.isr_bssid
,
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;
374 network
.authentication_mode
= 0;
376 network
.group_cipher
= 0;
377 network
.key_mode
= 0;
379 parse_ie(network
, result
);
384 get_scan_result(const char* device
, wireless_network
& network
, uint32 index
,
385 const BNetworkAddress
* address
, const char* name
)
387 if (address
!= NULL
&& address
->Family() != AF_LINK
)
390 const size_t kBufferSize
= 65535;
391 uint8
* buffer
= (uint8
*)malloc(kBufferSize
);
395 MemoryDeleter
deleter(buffer
);
397 int32 length
= kBufferSize
;
398 status_t status
= get_80211(device
, IEEE80211_IOC_SCAN_RESULTS
, buffer
,
403 int32 bytesLeft
= length
;
404 uint8
* entry
= buffer
;
407 while (bytesLeft
> (int32
)sizeof(struct ieee80211req_scan_result
)) {
408 ieee80211req_scan_result
* result
409 = (ieee80211req_scan_result
*)entry
;
411 char networkName
[32];
412 strlcpy(networkName
, (char*)(result
+ 1),
413 min_c((int)sizeof(networkName
), result
->isr_ssid_len
+ 1));
415 if (index
== count
|| (address
!= NULL
&& !memcmp(
416 address
->LinkLevelAddress(), result
->isr_bssid
,
418 || (name
!= NULL
&& !strcmp(networkName
, name
))) {
419 // Fill wireless_network with scan result data
420 fill_wireless_network(network
, networkName
, *result
);
424 entry
+= result
->isr_len
;
425 bytesLeft
-= result
->isr_len
;
429 return B_ENTRY_NOT_FOUND
;
434 get_station(const char* device
, wireless_network
& network
, uint32 index
,
435 const BNetworkAddress
* address
, const char* name
)
437 if (address
!= NULL
&& address
->Family() != AF_LINK
)
440 const size_t kBufferSize
= 65535;
441 uint8
* buffer
= (uint8
*)malloc(kBufferSize
);
445 MemoryDeleter
deleter(buffer
);
447 struct ieee80211req_sta_req
& request
= *(ieee80211req_sta_req
*)buffer
;
448 if (address
!= NULL
) {
449 memcpy(request
.is_u
.macaddr
, address
->LinkLevelAddress(),
452 memset(request
.is_u
.macaddr
, 0xff, IEEE80211_ADDR_LEN
);
454 int32 length
= kBufferSize
;
455 status_t status
= get_80211(device
, IEEE80211_IOC_STA_INFO
, &request
,
460 int32 bytesLeft
= length
;
461 uint8
* entry
= (uint8
*)&request
.info
[0];
464 while (bytesLeft
> (int32
)sizeof(struct ieee80211req_sta_info
)) {
465 ieee80211req_sta_info
* info
= (ieee80211req_sta_info
*)entry
;
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
);
475 entry
+= info
->isi_len
;
476 bytesLeft
-= info
->isi_len
;
480 return B_ENTRY_NOT_FOUND
;
485 get_network(const char* device
, wireless_network
& network
, uint32 index
,
486 const BNetworkAddress
* address
, const char* name
)
488 status_t status
= get_station(device
, network
, index
, address
, name
);
490 return get_scan_result(device
, network
, index
, address
, name
);
502 BNetworkDevice::BNetworkDevice()
508 BNetworkDevice::BNetworkDevice(const char* name
)
514 BNetworkDevice::~BNetworkDevice()
520 BNetworkDevice::Unset()
527 BNetworkDevice::SetTo(const char* name
)
529 strlcpy(fName
, name
, IF_NAMESIZE
);
534 BNetworkDevice::Name() const
541 BNetworkDevice::Exists() const
544 return do_request(request
, Name(), SIOCGIFINDEX
) == B_OK
;
549 BNetworkDevice::Index() const
552 if (do_request(request
, Name(), SIOCGIFINDEX
) != B_OK
)
555 return request
.ifr_index
;
560 BNetworkDevice::Flags() const
563 if (do_request(request
, Name(), SIOCGIFFLAGS
) != B_OK
)
566 return request
.ifr_flags
;
571 BNetworkDevice::HasLink() const
573 return (Flags() & IFF_LINK
) != 0;
578 BNetworkDevice::CountMedia() const
581 request
.ifm_count
= 0;
582 request
.ifm_ulist
= NULL
;
584 if (do_request(request
, Name(), SIOCGIFMEDIA
) != B_OK
)
587 return request
.ifm_count
;
592 BNetworkDevice::Media() const
595 request
.ifm_count
= 0;
596 request
.ifm_ulist
= NULL
;
598 if (do_request(request
, Name(), SIOCGIFMEDIA
) != B_OK
)
601 return request
.ifm_current
;
606 BNetworkDevice::GetMediaAt(int32 index
) const
608 // TODO: this could do some caching
614 BNetworkDevice::SetMedia(int32 media
)
617 request
.ifr_media
= media
;
618 return do_request(request
, Name(), SIOCSIFMEDIA
);
623 BNetworkDevice::GetHardwareAddress(BNetworkAddress
& address
)
626 status_t status
= do_request(request
, Name(), SIOCGIFADDR
);
630 address
.SetTo(request
.ifr_addr
);
636 BNetworkDevice::IsEthernet()
638 return IFM_TYPE(Media()) == IFM_ETHER
;
643 BNetworkDevice::IsWireless()
645 return IFM_TYPE(Media()) == IFM_IEEE80211
;
650 BNetworkDevice::Scan(bool wait
, bool forceRescan
)
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
);
667 BNetworkDevice::GetNextNetwork(uint32
& cookie
, wireless_network
& network
)
669 status_t status
= get_scan_result(Name(), network
, cookie
, NULL
, NULL
);
679 BNetworkDevice::GetNetwork(const char* name
, wireless_network
& network
)
681 if (name
== NULL
|| name
[0] == '\0')
684 return get_network(Name(), network
, UINT32_MAX
, NULL
, name
);
689 BNetworkDevice::GetNetwork(const BNetworkAddress
& address
,
690 wireless_network
& network
)
692 if (address
.Family() != AF_LINK
)
695 return get_network(Name(), network
, UINT32_MAX
, &address
, NULL
);
700 BNetworkDevice::JoinNetwork(const char* name
, const char* password
)
702 if (name
== NULL
|| name
[0] == '\0')
705 BMessage
message(kMsgJoinNetwork
);
706 status_t status
= message
.AddString("device", Name());
709 status
= message
.AddString("name", name
);
710 if (status
== B_OK
&& password
!= NULL
)
711 status
= message
.AddString("password", password
);
715 // Send message to the net_server
717 BMessenger
networkServer(kNetServerSignature
);
719 status
= networkServer
.SendMessage(&message
, &reply
);
721 reply
.FindInt32("status", &status
);
728 BNetworkDevice::JoinNetwork(const wireless_network
& network
,
729 const char* password
)
731 return JoinNetwork(network
.address
, password
);
736 BNetworkDevice::JoinNetwork(const BNetworkAddress
& address
,
737 const char* password
)
739 if (address
.InitCheck() != B_OK
)
742 BMessage
message(kMsgJoinNetwork
);
743 status_t status
= message
.AddString("device", Name());
745 if (status
== B_OK
) {
746 status
= message
.AddFlat("address",
747 const_cast<BNetworkAddress
*>(&address
));
749 if (status
== B_OK
&& password
!= NULL
)
750 status
= message
.AddString("password", password
);
754 // Send message to the net_server
756 BMessenger
networkServer(kNetServerSignature
);
758 status
= networkServer
.SendMessage(&message
, &reply
);
760 reply
.FindInt32("status", &status
);
767 BNetworkDevice::LeaveNetwork(const char* name
)
769 BMessage
message(kMsgLeaveNetwork
);
770 status_t status
= message
.AddString("device", Name());
772 status
= message
.AddString("name", name
);
774 status
= message
.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED
);
778 BMessenger
networkServer(kNetServerSignature
);
780 status
= networkServer
.SendMessage(&message
, &reply
);
782 reply
.FindInt32("status", &status
);
789 BNetworkDevice::LeaveNetwork(const wireless_network
& network
)
791 return LeaveNetwork(network
.address
);
796 BNetworkDevice::LeaveNetwork(const BNetworkAddress
& address
)
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
));
805 status
= message
.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED
);
809 BMessenger
networkServer(kNetServerSignature
);
811 status
= networkServer
.SendMessage(&message
, &reply
);
813 reply
.FindInt32("status", &status
);
820 BNetworkDevice::GetNextAssociatedNetwork(uint32
& cookie
,
821 wireless_network
& network
)
823 BNetworkAddress address
;
824 status_t status
= GetNextAssociatedNetwork(cookie
, address
);
828 return GetNetwork(address
, network
);
833 BNetworkDevice::GetNextAssociatedNetwork(uint32
& cookie
,
834 BNetworkAddress
& address
)
836 // We currently support only a single associated network
838 return B_ENTRY_NOT_FOUND
;
840 uint8 mac
[IEEE80211_ADDR_LEN
];
841 int32 length
= IEEE80211_ADDR_LEN
;
842 status_t status
= get_80211(Name(), IEEE80211_IOC_BSSID
, mac
, length
);
846 if (mac
[0] == 0 && mac
[1] == 0 && mac
[2] == 0 && mac
[3] == 0 && mac
[4] == 0
848 return B_ENTRY_NOT_FOUND
;
851 address
.SetToLinkLevel(mac
, IEEE80211_ADDR_LEN
);