summaryrefslogtreecommitdiffstats
path: root/netwerk/wifi/nsWifiScannerFreeBSD.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--netwerk/wifi/nsWifiScannerFreeBSD.cpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/netwerk/wifi/nsWifiScannerFreeBSD.cpp b/netwerk/wifi/nsWifiScannerFreeBSD.cpp
new file mode 100644
index 0000000000..83ec847bdf
--- /dev/null
+++ b/netwerk/wifi/nsWifiScannerFreeBSD.cpp
@@ -0,0 +1,168 @@
+/* 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;
+}