forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			171 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* 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>
 | |
| #ifdef __DragonFly__
 | |
| #include <netproto/802_11/ieee80211_ioctl.h>
 | |
| #else
 | |
| #include <net80211/ieee80211_ioctl.h>
 | |
| #endif
 | |
| 
 | |
| #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(kDefaultWifiScanInterval));
 | |
|   }
 | |
|   while (mKeepGoing);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | 
