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)
86 do_request
<ieee80211req
>(ieee80211req
& request
, const char* name
, int option
)
88 int socket
= ::socket(AF_INET
, SOCK_DGRAM
, 0);
92 FileDescriptorCloser
closer(socket
);
94 strlcpy(((struct ieee80211req
&)request
).i_name
, name
, IFNAMSIZ
);
96 if (ioctl(socket
, option
, &request
, sizeof(request
)) < 0)
103 //! Read a 16 bit little endian value
105 read_le16(uint8
*& data
, int32
& length
)
107 uint16 value
= B_LENDIAN_TO_HOST_INT16(*(uint16
*)data
);
114 //! Read a 32 bit little endian value
116 read_le32(uint8
*& data
, int32
& length
)
118 uint32 value
= B_LENDIAN_TO_HOST_INT32(*(uint32
*)data
);
126 from_rsn_cipher(uint32 cipher
)
128 if ((cipher
& 0xffffff) != RSN_OUI
)
129 return B_NETWORK_CIPHER_CCMP
;
131 switch (cipher
>> 24) {
133 return B_NETWORK_CIPHER_NONE
;
135 return B_NETWORK_CIPHER_WEP_40
;
137 return B_NETWORK_CIPHER_WEP_104
;
139 return B_NETWORK_CIPHER_TKIP
;
142 return B_NETWORK_CIPHER_CCMP
;
144 return B_NETWORK_CIPHER_AES_128_CMAC
;
150 from_rsn_key_mode(uint32 mode
)
152 if ((mode
& 0xffffff) != RSN_OUI
)
153 return B_KEY_MODE_IEEE802_1X
;
155 switch (mode
>> 24) {
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
163 return B_KEY_MODE_FT_IEEE802_1X
;
165 return B_KEY_MODE_FT_PSK
;
167 return B_KEY_MODE_IEEE802_1X_SHA256
;
169 return B_KEY_MODE_PSK_SHA256
;
174 //! Parse RSN/WPA information elements common data
176 parse_ie_rsn_wpa(wireless_network
& network
, uint8
*& data
, int32
& length
)
179 // parse group cipher
180 network
.group_cipher
= from_rsn_cipher(read_le32(data
, length
));
181 } else if (length
> 0)
185 // parse unicast cipher
186 uint16 count
= read_le16(data
, length
);
189 for (uint16 i
= 0; i
< count
; i
++) {
192 network
.cipher
|= from_rsn_cipher(read_le32(data
, length
));
194 } else if (length
> 0)
198 // parse key management mode
199 uint16 count
= read_le16(data
, length
);
200 network
.key_mode
= 0;
202 for (uint16 i
= 0; i
< count
; i
++) {
205 network
.key_mode
|= from_rsn_key_mode(read_le32(data
, length
));
207 } else if (length
> 0)
210 // TODO: capabilities, and PMKID following in case of RSN
214 //! Parse RSN (Robust Security Network) information element.
216 parse_ie_rsn(wireless_network
& network
, ie_data
* ie
)
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
;
223 int32 length
= ie
->length
;
227 uint8
* data
= ie
->data
;
229 uint16 version
= read_le16(data
, length
);
230 if (version
!= RSN_VERSION
)
233 parse_ie_rsn_wpa(network
, data
, length
);
237 //! Parse WPA information element.
239 parse_ie_wpa(wireless_network
& network
, ie_data
* ie
)
241 int32 length
= ie
->length
;
245 uint8
* data
= ie
->data
;
247 uint32 oui
= read_le32(data
, length
);
248 TRACE(" oui: %" B_PRIx32
"\n", oui
);
249 if (oui
!= ((WPA_OUI_TYPE
<< 24) | WPA_OUI
))
252 uint16 version
= read_le16(data
, length
);
253 if (version
!= WPA_VERSION
)
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
;
261 parse_ie_rsn_wpa(network
, data
, length
);
266 //! Parse information elements.
268 parse_ie(wireless_network
& network
, uint8
* _ie
, int32 ieLength
)
270 struct ie_data
* ie
= (ie_data
*)_ie
;
274 while (ieLength
> 1) {
275 TRACE("ie type %u\n", ie
->type
);
277 case IEEE80211_ELEMID_SSID
:
278 strlcpy(network
.name
, (char*)ie
->data
,
279 min_c(ie
->length
+ 1, (int)sizeof(network
.name
)));
281 case IEEE80211_ELEMID_RSN
:
282 parse_ie_rsn(network
, ie
);
285 case IEEE80211_ELEMID_VENDOR
:
286 if (!hadRSN
&& parse_ie_wpa(network
, ie
))
291 ieLength
-= 2 + ie
->length
;
292 ie
= (ie_data
*)((uint8
*)ie
+ 2 + ie
->length
);
295 if (hadRSN
|| hadWPA
) {
296 // Determine authentication mode
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) {
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
;
311 network
.authentication_mode
= B_NETWORK_AUTHENTICATION_NONE
;
318 parse_ie(wireless_network
& network
, struct ieee80211req_sta_info
& info
)
320 parse_ie(network
, (uint8
*)&info
+ info
.isi_ie_off
, info
.isi_ie_len
);
325 parse_ie(wireless_network
& network
, struct ieee80211req_scan_result
& result
)
327 parse_ie(network
, (uint8
*)&result
+ result
.isr_ie_off
+ result
.isr_ssid_len
328 + result
.isr_meshid_len
, result
.isr_ie_len
);
333 get_ssid_from_ie(char* name
, uint8
* _ie
, int32 ieLength
)
335 struct ie_data
* ie
= (ie_data
*)_ie
;
337 while (ieLength
> 1) {
339 case IEEE80211_ELEMID_SSID
:
340 strlcpy(name
, (char*)ie
->data
, min_c(ie
->length
+ 1, 32));
344 ieLength
-= 2 + ie
->length
;
345 ie
= (ie_data
*)((uint8
*)ie
+ 2 + ie
->length
);
352 get_ssid_from_ie(char* name
, struct ieee80211req_sta_info
& info
)
354 return get_ssid_from_ie(name
, (uint8
*)&info
+ info
.isi_ie_off
,
360 fill_wireless_network(wireless_network
& network
,
361 struct ieee80211req_sta_info
& info
)
363 network
.name
[0] = '\0';
364 network
.address
.SetToLinkLevel(info
.isi_macaddr
,
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;
371 network
.authentication_mode
= 0;
373 network
.group_cipher
= 0;
374 network
.key_mode
= 0;
376 parse_ie(network
, info
);
381 fill_wireless_network(wireless_network
& network
, const char* networkName
,
382 struct ieee80211req_scan_result
& result
)
384 strlcpy(network
.name
, networkName
, sizeof(network
.name
));
385 network
.address
.SetToLinkLevel(result
.isr_bssid
,
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;
392 network
.authentication_mode
= 0;
394 network
.group_cipher
= 0;
395 network
.key_mode
= 0;
397 parse_ie(network
, result
);
402 get_scan_result(const char* device
, wireless_network
& network
, uint32 index
,
403 const BNetworkAddress
* address
, const char* name
)
405 if (address
!= NULL
&& address
->Family() != AF_LINK
)
408 const size_t kBufferSize
= 65535;
409 uint8
* buffer
= (uint8
*)malloc(kBufferSize
);
413 MemoryDeleter
deleter(buffer
);
415 int32 length
= kBufferSize
;
416 status_t status
= get_80211(device
, IEEE80211_IOC_SCAN_RESULTS
, buffer
,
421 int32 bytesLeft
= length
;
422 uint8
* entry
= buffer
;
425 while (bytesLeft
> (int32
)sizeof(struct ieee80211req_scan_result
)) {
426 ieee80211req_scan_result
* result
427 = (ieee80211req_scan_result
*)entry
;
429 char networkName
[32];
430 strlcpy(networkName
, (char*)(result
+ 1),
431 min_c((int)sizeof(networkName
), result
->isr_ssid_len
+ 1));
433 if (index
== count
|| (address
!= NULL
&& !memcmp(
434 address
->LinkLevelAddress(), result
->isr_bssid
,
436 || (name
!= NULL
&& !strcmp(networkName
, name
))) {
437 // Fill wireless_network with scan result data
438 fill_wireless_network(network
, networkName
, *result
);
442 entry
+= result
->isr_len
;
443 bytesLeft
-= result
->isr_len
;
447 return B_ENTRY_NOT_FOUND
;
452 get_station(const char* device
, wireless_network
& network
, uint32 index
,
453 const BNetworkAddress
* address
, const char* name
)
455 if (address
!= NULL
&& address
->Family() != AF_LINK
)
458 const size_t kBufferSize
= 65535;
459 uint8
* buffer
= (uint8
*)malloc(kBufferSize
);
463 MemoryDeleter
deleter(buffer
);
465 struct ieee80211req_sta_req
& request
= *(ieee80211req_sta_req
*)buffer
;
466 if (address
!= NULL
) {
467 memcpy(request
.is_u
.macaddr
, address
->LinkLevelAddress(),
470 memset(request
.is_u
.macaddr
, 0xff, IEEE80211_ADDR_LEN
);
472 int32 length
= kBufferSize
;
473 status_t status
= get_80211(device
, IEEE80211_IOC_STA_INFO
, &request
,
478 int32 bytesLeft
= length
;
479 uint8
* entry
= (uint8
*)&request
.info
[0];
482 while (bytesLeft
> (int32
)sizeof(struct ieee80211req_sta_info
)) {
483 ieee80211req_sta_info
* info
= (ieee80211req_sta_info
*)entry
;
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
);
493 entry
+= info
->isi_len
;
494 bytesLeft
-= info
->isi_len
;
498 return B_ENTRY_NOT_FOUND
;
503 get_network(const char* device
, wireless_network
& network
, uint32 index
,
504 const BNetworkAddress
* address
, const char* name
)
506 status_t status
= get_station(device
, network
, index
, address
, name
);
508 return get_scan_result(device
, network
, index
, address
, name
);
520 BNetworkDevice::BNetworkDevice()
526 BNetworkDevice::BNetworkDevice(const char* name
)
532 BNetworkDevice::~BNetworkDevice()
538 BNetworkDevice::Unset()
545 BNetworkDevice::SetTo(const char* name
)
547 strlcpy(fName
, name
, IF_NAMESIZE
);
552 BNetworkDevice::Name() const
559 BNetworkDevice::Exists() const
562 return do_request(request
, Name(), SIOCGIFINDEX
) == B_OK
;
567 BNetworkDevice::Index() const
570 if (do_request(request
, Name(), SIOCGIFINDEX
) != B_OK
)
573 return request
.ifr_index
;
578 BNetworkDevice::Flags() const
581 if (do_request(request
, Name(), SIOCGIFFLAGS
) != B_OK
)
584 return request
.ifr_flags
;
589 BNetworkDevice::HasLink() const
591 return (Flags() & IFF_LINK
) != 0;
596 BNetworkDevice::CountMedia() const
599 request
.ifm_count
= 0;
600 request
.ifm_ulist
= NULL
;
602 if (do_request(request
, Name(), SIOCGIFMEDIA
) != B_OK
)
605 return request
.ifm_count
;
610 BNetworkDevice::Media() const
613 request
.ifm_count
= 0;
614 request
.ifm_ulist
= NULL
;
616 if (do_request(request
, Name(), SIOCGIFMEDIA
) != B_OK
)
619 return request
.ifm_current
;
624 BNetworkDevice::GetMediaAt(int32 index
) const
626 // TODO: this could do some caching
632 BNetworkDevice::SetMedia(int32 media
)
635 request
.ifr_media
= media
;
636 return do_request(request
, Name(), SIOCSIFMEDIA
);
641 BNetworkDevice::GetHardwareAddress(BNetworkAddress
& address
)
644 status_t status
= do_request(request
, Name(), SIOCGIFADDR
);
648 address
.SetTo(request
.ifr_addr
);
654 BNetworkDevice::IsEthernet()
656 return IFM_TYPE(Media()) == IFM_ETHER
;
661 BNetworkDevice::IsWireless()
663 return IFM_TYPE(Media()) == IFM_IEEE80211
;
668 BNetworkDevice::Control(int option
, void* request
)
670 switch (IFM_TYPE(Media())) {
672 return do_request(*reinterpret_cast<ifreq
*>(request
),
676 return do_request(*reinterpret_cast<ieee80211req
*>(request
),
686 BNetworkDevice::Scan(bool wait
, bool forceRescan
)
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
);
703 BNetworkDevice::GetNextNetwork(uint32
& cookie
, wireless_network
& network
)
705 status_t status
= get_scan_result(Name(), network
, cookie
, NULL
, NULL
);
715 BNetworkDevice::GetNetwork(const char* name
, wireless_network
& network
)
717 if (name
== NULL
|| name
[0] == '\0')
720 return get_network(Name(), network
, UINT32_MAX
, NULL
, name
);
725 BNetworkDevice::GetNetwork(const BNetworkAddress
& address
,
726 wireless_network
& network
)
728 if (address
.Family() != AF_LINK
)
731 return get_network(Name(), network
, UINT32_MAX
, &address
, NULL
);
736 BNetworkDevice::JoinNetwork(const char* name
, const char* password
)
738 if (name
== NULL
|| name
[0] == '\0')
741 BMessage
message(kMsgJoinNetwork
);
742 status_t status
= message
.AddString("device", Name());
745 status
= message
.AddString("name", name
);
746 if (status
== B_OK
&& password
!= NULL
)
747 status
= message
.AddString("password", password
);
751 // Send message to the net_server
753 BMessenger
networkServer(kNetServerSignature
);
755 status
= networkServer
.SendMessage(&message
, &reply
);
757 reply
.FindInt32("status", &status
);
764 BNetworkDevice::JoinNetwork(const wireless_network
& network
,
765 const char* password
)
767 return JoinNetwork(network
.address
, password
);
772 BNetworkDevice::JoinNetwork(const BNetworkAddress
& address
,
773 const char* password
)
775 if (address
.InitCheck() != B_OK
)
778 BMessage
message(kMsgJoinNetwork
);
779 status_t status
= message
.AddString("device", Name());
781 if (status
== B_OK
) {
782 status
= message
.AddFlat("address",
783 const_cast<BNetworkAddress
*>(&address
));
785 if (status
== B_OK
&& password
!= NULL
)
786 status
= message
.AddString("password", password
);
790 // Send message to the net_server
792 BMessenger
networkServer(kNetServerSignature
);
794 status
= networkServer
.SendMessage(&message
, &reply
);
796 reply
.FindInt32("status", &status
);
803 BNetworkDevice::LeaveNetwork(const char* name
)
805 BMessage
message(kMsgLeaveNetwork
);
806 status_t status
= message
.AddString("device", Name());
808 status
= message
.AddString("name", name
);
810 status
= message
.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED
);
814 BMessenger
networkServer(kNetServerSignature
);
816 status
= networkServer
.SendMessage(&message
, &reply
);
818 reply
.FindInt32("status", &status
);
825 BNetworkDevice::LeaveNetwork(const wireless_network
& network
)
827 return LeaveNetwork(network
.address
);
832 BNetworkDevice::LeaveNetwork(const BNetworkAddress
& address
)
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
));
841 status
= message
.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED
);
845 BMessenger
networkServer(kNetServerSignature
);
847 status
= networkServer
.SendMessage(&message
, &reply
);
849 reply
.FindInt32("status", &status
);
856 BNetworkDevice::GetNextAssociatedNetwork(uint32
& cookie
,
857 wireless_network
& network
)
859 BNetworkAddress address
;
860 status_t status
= GetNextAssociatedNetwork(cookie
, address
);
864 return GetNetwork(address
, network
);
869 BNetworkDevice::GetNextAssociatedNetwork(uint32
& cookie
,
870 BNetworkAddress
& address
)
872 // We currently support only a single associated network
874 return B_ENTRY_NOT_FOUND
;
876 uint8 mac
[IEEE80211_ADDR_LEN
];
877 int32 length
= IEEE80211_ADDR_LEN
;
878 status_t status
= get_80211(Name(), IEEE80211_IOC_BSSID
, mac
, length
);
882 if (mac
[0] == 0 && mac
[1] == 0 && mac
[2] == 0 && mac
[3] == 0 && mac
[4] == 0
884 return B_ENTRY_NOT_FOUND
;
887 address
.SetToLinkLevel(mac
, IEEE80211_ADDR_LEN
);