netwerk/wifi/nsWifiScannerFreeBSD.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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>
    14 #include <net/if.h>
    15 #include <net/if_media.h>
    16 #include <net80211/ieee80211_ioctl.h>
    18 #include <ifaddrs.h>
    19 #include <string.h>
    20 #include <unistd.h>
    22 #include "nsWifiAccessPoint.h"
    24 using namespace mozilla;
    26 static nsresult
    27 FreeBSDGetAccessPointData(nsCOMArray<nsWifiAccessPoint> &accessPoints)
    28 {
    29   // get list of interfaces
    30   struct ifaddrs *ifal;
    31   if (getifaddrs(&ifal) < 0) {
    32     return NS_ERROR_FAILURE;
    33   }
    35   accessPoints.Clear();
    37   // loop through the interfaces
    38   nsresult rv = NS_ERROR_FAILURE;
    39   struct ifaddrs *ifa;
    40   for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
    41     // limit to one interface per address
    42     if (ifa->ifa_addr->sa_family != AF_LINK) {
    43       continue;
    44     }
    46     // store interface name in socket structure
    47     struct ifreq ifr;
    48     memset(&ifr, 0, sizeof(ifr));
    49     strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
    50     ifr.ifr_addr.sa_family = AF_LOCAL;
    52     // open socket to interface
    53     int s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
    54     if (s < 0) {
    55       continue;
    56     }
    58     // clear interface media structure
    59     struct ifmediareq ifmr;
    60     memset(&ifmr, 0, sizeof(ifmr));
    61     strncpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name));
    63     // get interface media information
    64     if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
    65       close(s);
    66       continue;
    67     }
    69     // check interface is a WiFi interface
    70     if (IFM_TYPE(ifmr.ifm_active) != IFM_IEEE80211) {
    71       close(s);
    72       continue;
    73     }
    75     // perform WiFi scan
    76     struct ieee80211req i802r;
    77     char iscanbuf[32*1024];
    78     memset(&i802r, 0, sizeof(i802r));
    79     strncpy(i802r.i_name, ifa->ifa_name, sizeof(i802r.i_name));
    80     i802r.i_type = IEEE80211_IOC_SCAN_RESULTS;
    81     i802r.i_data = iscanbuf;
    82     i802r.i_len = sizeof(iscanbuf);
    83     if (ioctl(s, SIOCG80211, &i802r) < 0) {
    84       close(s);
    85       continue;
    86     }
    88     // close socket
    89     close(s);
    91     // loop through WiFi networks and build geoloc-lookup structure
    92     char *vsr = (char *) i802r.i_data;
    93     unsigned len = i802r.i_len;
    94     while (len >= sizeof(struct ieee80211req_scan_result)) {
    95       struct ieee80211req_scan_result *isr =
    96         (struct ieee80211req_scan_result *) vsr;
    98       // determine size of this entry
    99       char *id;
   100       int idlen;
   101       if (isr->isr_meshid_len) {
   102         id = vsr + isr->isr_ie_off + isr->isr_ssid_len;
   103         idlen = isr->isr_meshid_len;
   104       } else {
   105         id = vsr + isr->isr_ie_off;
   106         idlen = isr->isr_ssid_len;
   107       }
   109       // copy network data
   110       char ssid[IEEE80211_NWID_LEN+1];
   111       strncpy(ssid, id, idlen);
   112       ssid[idlen] = '\0';
   113       nsWifiAccessPoint *ap = new nsWifiAccessPoint();
   114       ap->setSSID(ssid, strlen(ssid));
   115       ap->setMac(isr->isr_bssid);
   116       ap->setSignal(isr->isr_rssi);
   117       accessPoints.AppendObject(ap);
   118       rv = NS_OK;
   120       // log the data
   121       LOG(( "FreeBSD access point: "
   122             "SSID: %s, MAC: %02x-%02x-%02x-%02x-%02x-%02x, "
   123             "Strength: %d, Channel: %dMHz\n",
   124             ssid, isr->isr_bssid[0], isr->isr_bssid[1], isr->isr_bssid[2],
   125             isr->isr_bssid[3], isr->isr_bssid[4], isr->isr_bssid[5],
   126             isr->isr_rssi, isr->isr_freq));
   128       // increment pointers
   129       len -= isr->isr_len;
   130       vsr += isr->isr_len;
   131     }
   132   }
   134   freeifaddrs(ifal);
   136   return rv;
   137 }
   139 nsresult
   140 nsWifiMonitor::DoScan()
   141 {
   142   // Regularly get the access point data.
   144   nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
   145   nsCOMArray<nsWifiAccessPoint> accessPoints;
   147   do {
   148     nsresult rv = FreeBSDGetAccessPointData(accessPoints);
   149     if (NS_FAILED(rv))
   150       return rv;
   152     bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints);
   153     ReplaceArray(lastAccessPoints, accessPoints);
   155     rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
   156     NS_ENSURE_SUCCESS(rv, rv);
   158     // wait for some reasonable amount of time. pref?
   159     LOG(("waiting on monitor\n"));
   161     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   162     mon.Wait(PR_SecondsToInterval(60));
   163   }
   164   while (mKeepGoing);
   166   return NS_OK;
   167 }

mercurial