Bug 893397 - Add FreeBSD support for NeckoWifi. r=ted, r=jdm
authorJ.R. Oldroyd <fbsd@opal.com>
Wed, 02 Apr 2014 09:02:06 -0400
changeset 196276 1c8e0eb500e434aae4bb5b9f80961b8c7258088d
parent 196275 91c9a327f2246b7da74a4c6265d4f2197b6a8507
child 196277 8b4c324e81e8d49c0393d5e1961a0d0040891497
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted, jdm
bugs893397
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 893397 - Add FreeBSD support for NeckoWifi. r=ted, r=jdm
configure.in
netwerk/wifi/moz.build
netwerk/wifi/nsWifiScannerFreeBSD.cpp
--- a/configure.in
+++ b/configure.in
@@ -8276,17 +8276,17 @@ dnl option to disable necko's wifi scann
 dnl
 
 case "$OS_TARGET" in
   Android)
     if test -n "$gonkdir"; then
       NECKO_WIFI=1
     fi
     ;;
-  Darwin|SunOS|WINNT)
+  Darwin|FreeBSD|SunOS|WINNT)
     NECKO_WIFI=1
     ;;
   Linux)
     NECKO_WIFI=1
     NECKO_WIFI_DBUS=1
     ;;
 esac
 
--- a/netwerk/wifi/moz.build
+++ b/netwerk/wifi/moz.build
@@ -30,16 +30,20 @@ FAIL_ON_WARNINGS = CONFIG['OS_ARCH'] != 
 
 if CONFIG['OS_ARCH'] == 'Darwin':
     UNIFIED_SOURCES += [
         'nsWifiScannerMac.cpp',
     ]
     UNIFIED_SOURCES += [
         'osx_corewlan.mm',
     ]
+elif CONFIG['OS_ARCH'] == 'FreeBSD':
+    UNIFIED_SOURCES += [
+        'nsWifiScannerFreeBSD.cpp',
+    ]
 elif CONFIG['OS_ARCH'] == 'WINNT':
     UNIFIED_SOURCES += [
         'nsWifiScannerWin.cpp',
     ]
 elif CONFIG['OS_ARCH'] == 'SunOS':
     UNIFIED_SOURCES += [
         'nsWifiScannerSolaris.cpp',
     ]
new file mode 100644
--- /dev/null
+++ b/netwerk/wifi/nsWifiScannerFreeBSD.cpp
@@ -0,0 +1,167 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Developed by J.R. Oldroyd <fbsd@opal.com>, December 2012.
+
+// For FreeBSD we use the getifaddrs(3) to obtain the list of interfaces
+// and then check for those with an 802.11 media type and able to return
+// a list of stations. This is similar to ifconfig(8).
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net80211/ieee80211_ioctl.h>
+
+#include <ifaddrs.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nsWifiAccessPoint.h"
+
+using namespace mozilla;
+
+static nsresult
+FreeBSDGetAccessPointData(nsCOMArray<nsWifiAccessPoint> &accessPoints)
+{
+  // get list of interfaces
+  struct ifaddrs *ifal;
+  if (getifaddrs(&ifal) < 0) {
+    return NS_ERROR_FAILURE;
+  }
+
+  accessPoints.Clear();
+
+  // loop through the interfaces
+  nsresult rv = NS_ERROR_FAILURE;
+  struct ifaddrs *ifa;
+  for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
+    // limit to one interface per address
+    if (ifa->ifa_addr->sa_family != AF_LINK) {
+      continue;
+    }
+
+    // store interface name in socket structure
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
+    ifr.ifr_addr.sa_family = AF_LOCAL;
+
+    // open socket to interface
+    int s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
+    if (s < 0) {
+      continue;
+    }
+
+    // clear interface media structure
+    struct ifmediareq ifmr;
+    memset(&ifmr, 0, sizeof(ifmr));
+    strncpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name));
+
+    // get interface media information
+    if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+      close(s);
+      continue;
+    }
+
+    // check interface is a WiFi interface
+    if (IFM_TYPE(ifmr.ifm_active) != IFM_IEEE80211) {
+      close(s);
+      continue;
+    }
+
+    // perform WiFi scan
+    struct ieee80211req i802r;
+    char iscanbuf[32*1024];
+    memset(&i802r, 0, sizeof(i802r));
+    strncpy(i802r.i_name, ifa->ifa_name, sizeof(i802r.i_name));
+    i802r.i_type = IEEE80211_IOC_SCAN_RESULTS;
+    i802r.i_data = iscanbuf;
+    i802r.i_len = sizeof(iscanbuf);
+    if (ioctl(s, SIOCG80211, &i802r) < 0) {
+      close(s);
+      continue;
+    }
+
+    // close socket
+    close(s);
+
+    // loop through WiFi networks and build geoloc-lookup structure
+    char *vsr = (char *) i802r.i_data;
+    unsigned len = i802r.i_len;
+    while (len >= sizeof(struct ieee80211req_scan_result)) {
+      struct ieee80211req_scan_result *isr =
+        (struct ieee80211req_scan_result *) vsr;
+
+      // determine size of this entry
+      char *id;
+      int idlen;
+      if (isr->isr_meshid_len) {
+        id = vsr + isr->isr_ie_off + isr->isr_ssid_len;
+        idlen = isr->isr_meshid_len;
+      } else {
+        id = vsr + isr->isr_ie_off;
+        idlen = isr->isr_ssid_len;
+      }
+
+      // copy network data
+      char ssid[IEEE80211_NWID_LEN+1];
+      strncpy(ssid, id, idlen);
+      ssid[idlen] = '\0';
+      nsWifiAccessPoint *ap = new nsWifiAccessPoint();
+      ap->setSSID(ssid, strlen(ssid));
+      ap->setMac(isr->isr_bssid);
+      ap->setSignal(isr->isr_rssi);
+      accessPoints.AppendObject(ap);
+      rv = NS_OK;
+
+      // log the data
+      LOG(( "FreeBSD access point: "
+            "SSID: %s, MAC: %02x-%02x-%02x-%02x-%02x-%02x, "
+            "Strength: %d, Channel: %dMHz\n",
+            ssid, isr->isr_bssid[0], isr->isr_bssid[1], isr->isr_bssid[2],
+            isr->isr_bssid[3], isr->isr_bssid[4], isr->isr_bssid[5],
+            isr->isr_rssi, isr->isr_freq));
+
+      // increment pointers
+      len -= isr->isr_len;
+      vsr += isr->isr_len;
+    }
+  }
+
+  freeifaddrs(ifal);
+
+  return rv;
+}
+
+nsresult
+nsWifiMonitor::DoScan()
+{
+  // Regularly get the access point data.
+
+  nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
+  nsCOMArray<nsWifiAccessPoint> accessPoints;
+
+  do {
+    nsresult rv = FreeBSDGetAccessPointData(accessPoints);
+    if (NS_FAILED(rv))
+      return rv;
+
+    bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints);
+    ReplaceArray(lastAccessPoints, accessPoints);
+
+    rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // wait for some reasonable amount of time. pref?
+    LOG(("waiting on monitor\n"));
+
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+    mon.Wait(PR_SecondsToInterval(60));
+  }
+  while (mKeepGoing);
+
+  return NS_OK;
+}