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