Bug 1760181 [wpt PR 33182] - Update wpt metadata, a=testonly
[gecko.git] / netwerk / wifi / nsWifiScannerFreeBSD.cpp
blob83ec847bdfe7af5548fd8f3b5f08884ba25877b3
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // Developed by J.R. Oldroyd <fbsd@opal.com>, December 2012.
7 // For FreeBSD we use the getifaddrs(3) to obtain the list of interfaces
8 // and then check for those with an 802.11 media type and able to return
9 // a list of stations. This is similar to ifconfig(8).
11 #include <sys/types.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
14 #include <net/if.h>
15 #include <net/if_media.h>
16 #ifdef __DragonFly__
17 # include <netproto/802_11/ieee80211_ioctl.h>
18 #else
19 # include <net80211/ieee80211_ioctl.h>
20 #endif
22 #include <ifaddrs.h>
23 #include <string.h>
24 #include <unistd.h>
26 #include "nsWifiAccessPoint.h"
28 using namespace mozilla;
30 static nsresult FreeBSDGetAccessPointData(
31 nsCOMArray<nsWifiAccessPoint>& accessPoints) {
32 // get list of interfaces
33 struct ifaddrs* ifal;
34 if (getifaddrs(&ifal) < 0) {
35 return NS_ERROR_FAILURE;
38 accessPoints.Clear();
40 // loop through the interfaces
41 nsresult rv = NS_ERROR_FAILURE;
42 struct ifaddrs* ifa;
43 for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
44 // limit to one interface per address
45 if (ifa->ifa_addr->sa_family != AF_LINK) {
46 continue;
49 // store interface name in socket structure
50 struct ifreq ifr;
51 memset(&ifr, 0, sizeof(ifr));
52 strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
53 ifr.ifr_addr.sa_family = AF_LOCAL;
55 // open socket to interface
56 int s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
57 if (s < 0) {
58 continue;
61 // clear interface media structure
62 struct ifmediareq ifmr;
63 memset(&ifmr, 0, sizeof(ifmr));
64 strncpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name));
66 // get interface media information
67 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
68 close(s);
69 continue;
72 // check interface is a WiFi interface
73 if (IFM_TYPE(ifmr.ifm_active) != IFM_IEEE80211) {
74 close(s);
75 continue;
78 // perform WiFi scan
79 struct ieee80211req i802r;
80 char iscanbuf[32 * 1024];
81 memset(&i802r, 0, sizeof(i802r));
82 strncpy(i802r.i_name, ifa->ifa_name, sizeof(i802r.i_name));
83 i802r.i_type = IEEE80211_IOC_SCAN_RESULTS;
84 i802r.i_data = iscanbuf;
85 i802r.i_len = sizeof(iscanbuf);
86 if (ioctl(s, SIOCG80211, &i802r) < 0) {
87 close(s);
88 continue;
91 // close socket
92 close(s);
94 // loop through WiFi networks and build geoloc-lookup structure
95 char* vsr = (char*)i802r.i_data;
96 unsigned len = i802r.i_len;
97 while (len >= sizeof(struct ieee80211req_scan_result)) {
98 struct ieee80211req_scan_result* isr =
99 (struct ieee80211req_scan_result*)vsr;
101 // determine size of this entry
102 char* id;
103 int idlen;
104 if (isr->isr_meshid_len) {
105 id = vsr + isr->isr_ie_off + isr->isr_ssid_len;
106 idlen = isr->isr_meshid_len;
107 } else {
108 id = vsr + isr->isr_ie_off;
109 idlen = isr->isr_ssid_len;
112 // copy network data
113 char ssid[IEEE80211_NWID_LEN + 1];
114 strncpy(ssid, id, idlen);
115 ssid[idlen] = '\0';
116 nsWifiAccessPoint* ap = new nsWifiAccessPoint();
117 ap->setSSID(ssid, strlen(ssid));
118 ap->setMac(isr->isr_bssid);
119 ap->setSignal(isr->isr_rssi);
120 accessPoints.AppendObject(ap);
121 rv = NS_OK;
123 // log the data
124 LOG(
125 ("FreeBSD access point: "
126 "SSID: %s, MAC: %02x-%02x-%02x-%02x-%02x-%02x, "
127 "Strength: %d, Channel: %dMHz\n",
128 ssid, isr->isr_bssid[0], isr->isr_bssid[1], isr->isr_bssid[2],
129 isr->isr_bssid[3], isr->isr_bssid[4], isr->isr_bssid[5],
130 isr->isr_rssi, isr->isr_freq));
132 // increment pointers
133 len -= isr->isr_len;
134 vsr += isr->isr_len;
138 freeifaddrs(ifal);
140 return rv;
143 nsresult nsWifiMonitor::DoScan() {
144 // Regularly get the access point data.
146 nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
147 nsCOMArray<nsWifiAccessPoint> accessPoints;
149 do {
150 nsresult rv = FreeBSDGetAccessPointData(accessPoints);
151 if (NS_FAILED(rv)) return rv;
153 bool accessPointsChanged =
154 !AccessPointsEqual(accessPoints, lastAccessPoints);
155 ReplaceArray(lastAccessPoints, accessPoints);
157 rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
158 NS_ENSURE_SUCCESS(rv, rv);
160 // wait for some reasonable amount of time. pref?
161 LOG(("waiting on monitor\n"));
163 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
164 mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
165 } while (mKeepGoing);
167 return NS_OK;