michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Developed by J.R. Oldroyd , December 2012. michael@0: michael@0: // For FreeBSD we use the getifaddrs(3) to obtain the list of interfaces michael@0: // and then check for those with an 802.11 media type and able to return michael@0: // a list of stations. This is similar to ifconfig(8). michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "nsWifiAccessPoint.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: static nsresult michael@0: FreeBSDGetAccessPointData(nsCOMArray &accessPoints) michael@0: { michael@0: // get list of interfaces michael@0: struct ifaddrs *ifal; michael@0: if (getifaddrs(&ifal) < 0) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: accessPoints.Clear(); michael@0: michael@0: // loop through the interfaces michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: struct ifaddrs *ifa; michael@0: for (ifa = ifal; ifa; ifa = ifa->ifa_next) { michael@0: // limit to one interface per address michael@0: if (ifa->ifa_addr->sa_family != AF_LINK) { michael@0: continue; michael@0: } michael@0: michael@0: // store interface name in socket structure michael@0: struct ifreq ifr; michael@0: memset(&ifr, 0, sizeof(ifr)); michael@0: strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name)); michael@0: ifr.ifr_addr.sa_family = AF_LOCAL; michael@0: michael@0: // open socket to interface michael@0: int s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); michael@0: if (s < 0) { michael@0: continue; michael@0: } michael@0: michael@0: // clear interface media structure michael@0: struct ifmediareq ifmr; michael@0: memset(&ifmr, 0, sizeof(ifmr)); michael@0: strncpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name)); michael@0: michael@0: // get interface media information michael@0: if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { michael@0: close(s); michael@0: continue; michael@0: } michael@0: michael@0: // check interface is a WiFi interface michael@0: if (IFM_TYPE(ifmr.ifm_active) != IFM_IEEE80211) { michael@0: close(s); michael@0: continue; michael@0: } michael@0: michael@0: // perform WiFi scan michael@0: struct ieee80211req i802r; michael@0: char iscanbuf[32*1024]; michael@0: memset(&i802r, 0, sizeof(i802r)); michael@0: strncpy(i802r.i_name, ifa->ifa_name, sizeof(i802r.i_name)); michael@0: i802r.i_type = IEEE80211_IOC_SCAN_RESULTS; michael@0: i802r.i_data = iscanbuf; michael@0: i802r.i_len = sizeof(iscanbuf); michael@0: if (ioctl(s, SIOCG80211, &i802r) < 0) { michael@0: close(s); michael@0: continue; michael@0: } michael@0: michael@0: // close socket michael@0: close(s); michael@0: michael@0: // loop through WiFi networks and build geoloc-lookup structure michael@0: char *vsr = (char *) i802r.i_data; michael@0: unsigned len = i802r.i_len; michael@0: while (len >= sizeof(struct ieee80211req_scan_result)) { michael@0: struct ieee80211req_scan_result *isr = michael@0: (struct ieee80211req_scan_result *) vsr; michael@0: michael@0: // determine size of this entry michael@0: char *id; michael@0: int idlen; michael@0: if (isr->isr_meshid_len) { michael@0: id = vsr + isr->isr_ie_off + isr->isr_ssid_len; michael@0: idlen = isr->isr_meshid_len; michael@0: } else { michael@0: id = vsr + isr->isr_ie_off; michael@0: idlen = isr->isr_ssid_len; michael@0: } michael@0: michael@0: // copy network data michael@0: char ssid[IEEE80211_NWID_LEN+1]; michael@0: strncpy(ssid, id, idlen); michael@0: ssid[idlen] = '\0'; michael@0: nsWifiAccessPoint *ap = new nsWifiAccessPoint(); michael@0: ap->setSSID(ssid, strlen(ssid)); michael@0: ap->setMac(isr->isr_bssid); michael@0: ap->setSignal(isr->isr_rssi); michael@0: accessPoints.AppendObject(ap); michael@0: rv = NS_OK; michael@0: michael@0: // log the data michael@0: LOG(( "FreeBSD access point: " michael@0: "SSID: %s, MAC: %02x-%02x-%02x-%02x-%02x-%02x, " michael@0: "Strength: %d, Channel: %dMHz\n", michael@0: ssid, isr->isr_bssid[0], isr->isr_bssid[1], isr->isr_bssid[2], michael@0: isr->isr_bssid[3], isr->isr_bssid[4], isr->isr_bssid[5], michael@0: isr->isr_rssi, isr->isr_freq)); michael@0: michael@0: // increment pointers michael@0: len -= isr->isr_len; michael@0: vsr += isr->isr_len; michael@0: } michael@0: } michael@0: michael@0: freeifaddrs(ifal); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiMonitor::DoScan() michael@0: { michael@0: // Regularly get the access point data. michael@0: michael@0: nsCOMArray lastAccessPoints; michael@0: nsCOMArray accessPoints; michael@0: michael@0: do { michael@0: nsresult rv = FreeBSDGetAccessPointData(accessPoints); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints); michael@0: ReplaceArray(lastAccessPoints, accessPoints); michael@0: michael@0: rv = CallWifiListeners(lastAccessPoints, accessPointsChanged); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // wait for some reasonable amount of time. pref? michael@0: LOG(("waiting on monitor\n")); michael@0: michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: mon.Wait(PR_SecondsToInterval(60)); michael@0: } michael@0: while (mKeepGoing); michael@0: michael@0: return NS_OK; michael@0: }