|
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/. */ |
|
4 |
|
5 #include "nsWifiMonitor.h" |
|
6 #include "nsWifiAccessPoint.h" |
|
7 |
|
8 #include "nsServiceManagerUtils.h" |
|
9 #include "nsComponentManagerUtils.h" |
|
10 #include "nsIMutableArray.h" |
|
11 |
|
12 #include "plstr.h" |
|
13 #include <glib.h> |
|
14 |
|
15 #define DLADM_STRSIZE 256 |
|
16 #define DLADM_SECTIONS 3 |
|
17 |
|
18 using namespace mozilla; |
|
19 |
|
20 struct val_strength_t { |
|
21 const char *strength_name; |
|
22 int signal_value; |
|
23 }; |
|
24 |
|
25 static val_strength_t strength_vals[] = { |
|
26 { "very weak", -112 }, |
|
27 { "weak", -88 }, |
|
28 { "good", -68 }, |
|
29 { "very good", -40 }, |
|
30 { "excellent", -16 } |
|
31 }; |
|
32 |
|
33 static nsWifiAccessPoint * |
|
34 do_parse_str(char *bssid_str, char *essid_str, char *strength) |
|
35 { |
|
36 unsigned char mac_as_int[6] = { 0 }; |
|
37 sscanf(bssid_str, "%x:%x:%x:%x:%x:%x", &mac_as_int[0], &mac_as_int[1], |
|
38 &mac_as_int[2], &mac_as_int[3], &mac_as_int[4], &mac_as_int[5]); |
|
39 |
|
40 int signal = 0; |
|
41 uint32_t strength_vals_count = sizeof(strength_vals) / sizeof (val_strength_t); |
|
42 for (uint32_t i = 0; i < strength_vals_count; i++) { |
|
43 if (!strncasecmp(strength, strength_vals[i].strength_name, DLADM_STRSIZE)) { |
|
44 signal = strength_vals[i].signal_value; |
|
45 break; |
|
46 } |
|
47 } |
|
48 |
|
49 nsWifiAccessPoint *ap = new nsWifiAccessPoint(); |
|
50 if (ap) { |
|
51 ap->setMac(mac_as_int); |
|
52 ap->setSignal(signal); |
|
53 ap->setSSID(essid_str, PL_strnlen(essid_str, DLADM_STRSIZE)); |
|
54 } |
|
55 return ap; |
|
56 } |
|
57 |
|
58 static void |
|
59 do_dladm(nsCOMArray<nsWifiAccessPoint> &accessPoints) |
|
60 { |
|
61 GError *err = nullptr; |
|
62 char *sout = nullptr; |
|
63 char *serr = nullptr; |
|
64 int exit_status = 0; |
|
65 char * dladm_args[] = { "/usr/bin/pfexec", "/usr/sbin/dladm", |
|
66 "scan-wifi", "-p", "-o", "BSSID,ESSID,STRENGTH" }; |
|
67 |
|
68 gboolean rv = g_spawn_sync("/", dladm_args, nullptr, (GSpawnFlags)0, nullptr, |
|
69 nullptr, &sout, &serr, &exit_status, &err); |
|
70 if (rv && !exit_status) { |
|
71 char wlan[DLADM_SECTIONS][DLADM_STRSIZE+1]; |
|
72 uint32_t section = 0; |
|
73 uint32_t sout_scan = 0; |
|
74 uint32_t wlan_put = 0; |
|
75 bool escape = false; |
|
76 nsWifiAccessPoint* ap; |
|
77 char sout_char; |
|
78 do { |
|
79 sout_char = sout[sout_scan++]; |
|
80 if (escape) { |
|
81 escape = false; |
|
82 if (sout_char != '\0') { |
|
83 wlan[section][wlan_put++] = sout_char; |
|
84 continue; |
|
85 } |
|
86 } |
|
87 |
|
88 if (sout_char =='\\') { |
|
89 escape = true; |
|
90 continue; |
|
91 } |
|
92 |
|
93 if (sout_char == ':') { |
|
94 wlan[section][wlan_put] = '\0'; |
|
95 section++; |
|
96 wlan_put = 0; |
|
97 continue; |
|
98 } |
|
99 |
|
100 if ((sout_char == '\0') || (sout_char == '\n')) { |
|
101 wlan[section][wlan_put] = '\0'; |
|
102 if (section == DLADM_SECTIONS - 1) { |
|
103 ap = do_parse_str(wlan[0], wlan[1], wlan[2]); |
|
104 if (ap) { |
|
105 accessPoints.AppendObject(ap); |
|
106 } |
|
107 } |
|
108 section = 0; |
|
109 wlan_put = 0; |
|
110 continue; |
|
111 } |
|
112 |
|
113 wlan[section][wlan_put++] = sout_char; |
|
114 |
|
115 } while ((wlan_put <= DLADM_STRSIZE) && (section < DLADM_SECTIONS) && |
|
116 (sout_char != '\0')); |
|
117 } |
|
118 |
|
119 g_free(sout); |
|
120 g_free(serr); |
|
121 } |
|
122 |
|
123 nsresult |
|
124 nsWifiMonitor::DoScan() |
|
125 { |
|
126 // Regularly get the access point data. |
|
127 |
|
128 nsCOMArray<nsWifiAccessPoint> lastAccessPoints; |
|
129 nsCOMArray<nsWifiAccessPoint> accessPoints; |
|
130 |
|
131 while (mKeepGoing) { |
|
132 |
|
133 accessPoints.Clear(); |
|
134 do_dladm(accessPoints); |
|
135 |
|
136 bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints); |
|
137 ReplaceArray(lastAccessPoints, accessPoints); |
|
138 |
|
139 nsresult rv = CallWifiListeners(lastAccessPoints, accessPointsChanged); |
|
140 NS_ENSURE_SUCCESS(rv, rv); |
|
141 |
|
142 LOG(("waiting on monitor\n")); |
|
143 |
|
144 ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
145 mon.Wait(PR_SecondsToInterval(60)); |
|
146 } |
|
147 |
|
148 return NS_OK; |
|
149 } |