vfs: check userland buffers before reading them.
[haiku.git] / src / kits / network / libnetapi / NetworkDevice.cpp
blob73f67f003a0322be17e893066311dda069b4ad03
1 /*
2 * Copyright 2010-2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <NetworkDevice.h>
9 #include <errno.h>
10 #include <net/if.h>
11 #include <net/if_media.h>
12 #include <stdio.h>
13 #include <sys/sockio.h>
15 #include <Messenger.h>
17 #include <AutoDeleter.h>
18 #include <NetServer.h>
20 extern "C" {
21 # include <net80211/ieee80211_ioctl.h>
25 //#define TRACE_DEVICE
26 #ifdef TRACE_DEVICE
27 # define TRACE(x, ...) printf(x, __VA_ARGS__);
28 #else
29 # define TRACE(x, ...) ;
30 #endif
33 namespace {
36 struct ie_data {
37 uint8 type;
38 uint8 length;
39 uint8 data[1];
43 static status_t
44 get_80211(const char* name, int32 type, void* data, int32& length)
46 int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
47 if (socket < 0)
48 return errno;
50 FileDescriptorCloser closer(socket);
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;
59 if (ioctl(socket, SIOCG80211, &ireq, sizeof(struct ieee80211req)) < 0)
60 return errno;
62 length = ireq.i_len;
63 return B_OK;
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);
71 if (socket < 0)
72 return errno;
74 FileDescriptorCloser closer(socket);
76 strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE);
78 if (ioctl(socket, option, &request, sizeof(T)) < 0)
79 return errno;
81 return B_OK;
85 template<> status_t
86 do_request<ieee80211req>(ieee80211req& request, const char* name, int option)
88 int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
89 if (socket < 0)
90 return errno;
92 FileDescriptorCloser closer(socket);
94 strlcpy(((struct ieee80211req&)request).i_name, name, IFNAMSIZ);
96 if (ioctl(socket, option, &request, sizeof(request)) < 0)
97 return errno;
99 return B_OK;
103 //! Read a 16 bit little endian value
104 static uint16
105 read_le16(uint8*& data, int32& length)
107 uint16 value = B_LENDIAN_TO_HOST_INT16(*(uint16*)data);
108 data += 2;
109 length -= 2;
110 return value;
114 //! Read a 32 bit little endian value
115 static uint32
116 read_le32(uint8*& data, int32& length)
118 uint32 value = B_LENDIAN_TO_HOST_INT32(*(uint32*)data);
119 data += 4;
120 length -= 4;
121 return value;
125 static uint32
126 from_rsn_cipher(uint32 cipher)
128 if ((cipher & 0xffffff) != RSN_OUI)
129 return B_NETWORK_CIPHER_CCMP;
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;
149 static uint32
150 from_rsn_key_mode(uint32 mode)
152 if ((mode & 0xffffff) != RSN_OUI)
153 return B_KEY_MODE_IEEE802_1X;
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;
174 //! Parse RSN/WPA information elements common data
175 static void
176 parse_ie_rsn_wpa(wireless_network& network, uint8*& data, int32& length)
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;
184 if (length >= 2) {
185 // parse unicast cipher
186 uint16 count = read_le16(data, length);
187 network.cipher = 0;
189 for (uint16 i = 0; i < count; i++) {
190 if (length < 4)
191 return;
192 network.cipher |= from_rsn_cipher(read_le32(data, length));
194 } else if (length > 0)
195 return;
197 if (length >= 2) {
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++) {
203 if (length < 4)
204 return;
205 network.key_mode |= from_rsn_key_mode(read_le32(data, length));
207 } else if (length > 0)
208 return;
210 // TODO: capabilities, and PMKID following in case of RSN
214 //! Parse RSN (Robust Security Network) information element.
215 static void
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;
224 if (length < 2)
225 return;
227 uint8* data = ie->data;
229 uint16 version = read_le16(data, length);
230 if (version != RSN_VERSION)
231 return;
233 parse_ie_rsn_wpa(network, data, length);
237 //! Parse WPA information element.
238 static bool
239 parse_ie_wpa(wireless_network& network, ie_data* ie)
241 int32 length = ie->length;
242 if (length < 6)
243 return false;
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))
250 return false;
252 uint16 version = read_le16(data, length);
253 if (version != WPA_VERSION)
254 return false;
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);
262 return true;
266 //! Parse information elements.
267 static void
268 parse_ie(wireless_network& network, uint8* _ie, int32 ieLength)
270 struct ie_data* ie = (ie_data*)_ie;
271 bool hadRSN = false;
272 bool hadWPA = false;
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;
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) {
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;
317 static void
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);
324 static void
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);
332 static bool
333 get_ssid_from_ie(char* name, uint8* _ie, int32 ieLength)
335 struct ie_data* ie = (ie_data*)_ie;
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;
344 ieLength -= 2 + ie->length;
345 ie = (ie_data*)((uint8*)ie + 2 + ie->length);
347 return false;
351 static bool
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,
355 info.isi_ie_len);
359 static void
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,
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;
371 network.authentication_mode = 0;
372 network.cipher = 0;
373 network.group_cipher = 0;
374 network.key_mode = 0;
376 parse_ie(network, info);
380 static void
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,
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;
392 network.authentication_mode = 0;
393 network.cipher = 0;
394 network.group_cipher = 0;
395 network.key_mode = 0;
397 parse_ie(network, result);
401 static status_t
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)
406 return B_BAD_VALUE;
408 const size_t kBufferSize = 65535;
409 uint8* buffer = (uint8*)malloc(kBufferSize);
410 if (buffer == NULL)
411 return B_NO_MEMORY;
413 MemoryDeleter deleter(buffer);
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;
421 int32 bytesLeft = length;
422 uint8* entry = buffer;
423 uint32 count = 0;
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,
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;
442 entry += result->isr_len;
443 bytesLeft -= result->isr_len;
444 count++;
447 return B_ENTRY_NOT_FOUND;
451 static status_t
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)
456 return B_BAD_VALUE;
458 const size_t kBufferSize = 65535;
459 uint8* buffer = (uint8*)malloc(kBufferSize);
460 if (buffer == NULL)
461 return B_NO_MEMORY;
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(),
468 IEEE80211_ADDR_LEN);
469 } else
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,
474 length);
475 if (status != B_OK)
476 return status;
478 int32 bytesLeft = length;
479 uint8* entry = (uint8*)&request.info[0];
480 uint32 count = 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);
490 return B_OK;
493 entry += info->isi_len;
494 bytesLeft -= info->isi_len;
495 count++;
498 return B_ENTRY_NOT_FOUND;
502 static status_t
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);
507 if (status != B_OK)
508 return get_scan_result(device, network, index, address, name);
510 return B_OK;
514 } // namespace
517 // #pragma mark -
520 BNetworkDevice::BNetworkDevice()
522 Unset();
526 BNetworkDevice::BNetworkDevice(const char* name)
528 SetTo(name);
532 BNetworkDevice::~BNetworkDevice()
537 void
538 BNetworkDevice::Unset()
540 fName[0] = '\0';
544 void
545 BNetworkDevice::SetTo(const char* name)
547 strlcpy(fName, name, IF_NAMESIZE);
551 const char*
552 BNetworkDevice::Name() const
554 return fName;
558 bool
559 BNetworkDevice::Exists() const
561 ifreq request;
562 return do_request(request, Name(), SIOCGIFINDEX) == B_OK;
566 uint32
567 BNetworkDevice::Index() const
569 ifreq request;
570 if (do_request(request, Name(), SIOCGIFINDEX) != B_OK)
571 return 0;
573 return request.ifr_index;
577 uint32
578 BNetworkDevice::Flags() const
580 ifreq request;
581 if (do_request(request, Name(), SIOCGIFFLAGS) != B_OK)
582 return 0;
584 return request.ifr_flags;
588 bool
589 BNetworkDevice::HasLink() const
591 return (Flags() & IFF_LINK) != 0;
595 int32
596 BNetworkDevice::CountMedia() const
598 ifmediareq request;
599 request.ifm_count = 0;
600 request.ifm_ulist = NULL;
602 if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK)
603 return -1;
605 return request.ifm_count;
609 int32
610 BNetworkDevice::Media() const
612 ifmediareq request;
613 request.ifm_count = 0;
614 request.ifm_ulist = NULL;
616 if (do_request(request, Name(), SIOCGIFMEDIA) != B_OK)
617 return -1;
619 return request.ifm_current;
623 int32
624 BNetworkDevice::GetMediaAt(int32 index) const
626 // TODO: this could do some caching
627 return 0;
631 status_t
632 BNetworkDevice::SetMedia(int32 media)
634 ifreq request;
635 request.ifr_media = media;
636 return do_request(request, Name(), SIOCSIFMEDIA);
640 status_t
641 BNetworkDevice::GetHardwareAddress(BNetworkAddress& address)
643 ifreq request;
644 status_t status = do_request(request, Name(), SIOCGIFADDR);
645 if (status != B_OK)
646 return status;
648 address.SetTo(request.ifr_addr);
649 return B_OK;
653 bool
654 BNetworkDevice::IsEthernet()
656 return IFM_TYPE(Media()) == IFM_ETHER;
660 bool
661 BNetworkDevice::IsWireless()
663 return IFM_TYPE(Media()) == IFM_IEEE80211;
667 status_t
668 BNetworkDevice::Control(int option, void* request)
670 switch (IFM_TYPE(Media())) {
671 case IFM_ETHER:
672 return do_request(*reinterpret_cast<ifreq*>(request),
673 &fName[0], option);
675 case IFM_IEEE80211:
676 return do_request(*reinterpret_cast<ieee80211req*>(request),
677 &fName[0], option);
679 default:
680 return B_ERROR;
685 status_t
686 BNetworkDevice::Scan(bool wait, bool forceRescan)
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);
697 #endif
698 return B_ERROR;
702 status_t
703 BNetworkDevice::GetNextNetwork(uint32& cookie, wireless_network& network)
705 status_t status = get_scan_result(Name(), network, cookie, NULL, NULL);
706 if (status != B_OK)
707 return status;
709 cookie++;
710 return B_OK;
714 status_t
715 BNetworkDevice::GetNetwork(const char* name, wireless_network& network)
717 if (name == NULL || name[0] == '\0')
718 return B_BAD_VALUE;
720 return get_network(Name(), network, UINT32_MAX, NULL, name);
724 status_t
725 BNetworkDevice::GetNetwork(const BNetworkAddress& address,
726 wireless_network& network)
728 if (address.Family() != AF_LINK)
729 return B_BAD_VALUE;
731 return get_network(Name(), network, UINT32_MAX, &address, NULL);
735 status_t
736 BNetworkDevice::JoinNetwork(const char* name, const char* password)
738 if (name == NULL || name[0] == '\0')
739 return B_BAD_VALUE;
741 BMessage message(kMsgJoinNetwork);
742 status_t status = message.AddString("device", Name());
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;
751 // Send message to the net_server
753 BMessenger networkServer(kNetServerSignature);
754 BMessage reply;
755 status = networkServer.SendMessage(&message, &reply);
756 if (status == B_OK)
757 reply.FindInt32("status", &status);
759 return status;
763 status_t
764 BNetworkDevice::JoinNetwork(const wireless_network& network,
765 const char* password)
767 return JoinNetwork(network.address, password);
771 status_t
772 BNetworkDevice::JoinNetwork(const BNetworkAddress& address,
773 const char* password)
775 if (address.InitCheck() != B_OK)
776 return B_BAD_VALUE;
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);
787 if (status != B_OK)
788 return status;
790 // Send message to the net_server
792 BMessenger networkServer(kNetServerSignature);
793 BMessage reply;
794 status = networkServer.SendMessage(&message, &reply);
795 if (status == B_OK)
796 reply.FindInt32("status", &status);
798 return status;
802 status_t
803 BNetworkDevice::LeaveNetwork(const char* name)
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;
814 BMessenger networkServer(kNetServerSignature);
815 BMessage reply;
816 status = networkServer.SendMessage(&message, &reply);
817 if (status == B_OK)
818 reply.FindInt32("status", &status);
820 return status;
824 status_t
825 BNetworkDevice::LeaveNetwork(const wireless_network& network)
827 return LeaveNetwork(network.address);
831 status_t
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));
840 if (status == B_OK)
841 status = message.AddInt32("reason", IEEE80211_REASON_UNSPECIFIED);
842 if (status != B_OK)
843 return status;
845 BMessenger networkServer(kNetServerSignature);
846 BMessage reply;
847 status = networkServer.SendMessage(&message, &reply);
848 if (status == B_OK)
849 reply.FindInt32("status", &status);
851 return status;
855 status_t
856 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
857 wireless_network& network)
859 BNetworkAddress address;
860 status_t status = GetNextAssociatedNetwork(cookie, address);
861 if (status != B_OK)
862 return status;
864 return GetNetwork(address, network);
868 status_t
869 BNetworkDevice::GetNextAssociatedNetwork(uint32& cookie,
870 BNetworkAddress& address)
872 // We currently support only a single associated network
873 if (cookie != 0)
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);
879 if (status != B_OK)
880 return status;
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;
887 address.SetToLinkLevel(mac, IEEE80211_ADDR_LEN);
888 cookie++;
889 return B_OK;