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>
15 #include <net/if_media.h>
17 # include <netproto/802_11/ieee80211_ioctl.h>
19 # include <net80211/ieee80211_ioctl.h>
26 #include "nsWifiAccessPoint.h"
28 using namespace mozilla
;
30 static nsresult
FreeBSDGetAccessPointData(
31 nsCOMArray
<nsWifiAccessPoint
>& accessPoints
) {
32 // get list of interfaces
34 if (getifaddrs(&ifal
) < 0) {
35 return NS_ERROR_FAILURE
;
40 // loop through the interfaces
41 nsresult rv
= NS_ERROR_FAILURE
;
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
) {
49 // store interface name in socket structure
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);
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) {
72 // check interface is a WiFi interface
73 if (IFM_TYPE(ifmr
.ifm_active
) != IFM_IEEE80211
) {
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) {
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
104 if (isr
->isr_meshid_len
) {
105 id
= vsr
+ isr
->isr_ie_off
+ isr
->isr_ssid_len
;
106 idlen
= isr
->isr_meshid_len
;
108 id
= vsr
+ isr
->isr_ie_off
;
109 idlen
= isr
->isr_ssid_len
;
113 char ssid
[IEEE80211_NWID_LEN
+ 1];
114 strncpy(ssid
, id
, idlen
);
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
);
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
143 nsresult
nsWifiMonitor::DoScan() {
144 // Regularly get the access point data.
146 nsCOMArray
<nsWifiAccessPoint
> lastAccessPoints
;
147 nsCOMArray
<nsWifiAccessPoint
> accessPoints
;
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
);