Source code

Revision control

Other Tools

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/. */
4
5
// Developed by J.R. Oldroyd <fbsd@opal.com>, December 2012.
6
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).
10
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
21
22
#include <ifaddrs.h>
23
#include <string.h>
24
#include <unistd.h>
25
26
#include "nsWifiAccessPoint.h"
27
28
using namespace mozilla;
29
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;
36
}
37
38
accessPoints.Clear();
39
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;
47
}
48
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;
54
55
// open socket to interface
56
int s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
57
if (s < 0) {
58
continue;
59
}
60
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));
65
66
// get interface media information
67
if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
68
close(s);
69
continue;
70
}
71
72
// check interface is a WiFi interface
73
if (IFM_TYPE(ifmr.ifm_active) != IFM_IEEE80211) {
74
close(s);
75
continue;
76
}
77
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;
89
}
90
91
// close socket
92
close(s);
93
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;
100
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;
110
}
111
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;
122
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));
131
132
// increment pointers
133
len -= isr->isr_len;
134
vsr += isr->isr_len;
135
}
136
}
137
138
freeifaddrs(ifal);
139
140
return rv;
141
}
142
143
nsresult nsWifiMonitor::DoScan() {
144
// Regularly get the access point data.
145
146
nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
147
nsCOMArray<nsWifiAccessPoint> accessPoints;
148
149
do {
150
nsresult rv = FreeBSDGetAccessPointData(accessPoints);
151
if (NS_FAILED(rv)) return rv;
152
153
bool accessPointsChanged =
154
!AccessPointsEqual(accessPoints, lastAccessPoints);
155
ReplaceArray(lastAccessPoints, accessPoints);
156
157
rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
158
NS_ENSURE_SUCCESS(rv, rv);
159
160
// wait for some reasonable amount of time. pref?
161
LOG(("waiting on monitor\n"));
162
163
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
164
mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
165
} while (mKeepGoing);
166
167
return NS_OK;
168
}