Line data Source code
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 "nsWifiScannerDBus.h"
6 : #include "mozilla/ipc/DBusMessageRefPtr.h"
7 : #include "nsWifiAccessPoint.h"
8 :
9 : namespace mozilla {
10 :
11 0 : nsWifiScannerDBus::nsWifiScannerDBus(nsCOMArray<nsWifiAccessPoint> *aAccessPoints)
12 0 : : mAccessPoints(aAccessPoints)
13 : {
14 0 : MOZ_ASSERT(mAccessPoints);
15 :
16 : mConnection =
17 0 : already_AddRefed<DBusConnection>(dbus_bus_get(DBUS_BUS_SYSTEM, nullptr));
18 :
19 0 : if (mConnection) {
20 0 : dbus_connection_set_exit_on_disconnect(mConnection, false);
21 : }
22 :
23 0 : MOZ_COUNT_CTOR(nsWifiScannerDBus);
24 0 : }
25 :
26 0 : nsWifiScannerDBus::~nsWifiScannerDBus()
27 : {
28 0 : MOZ_COUNT_DTOR(nsWifiScannerDBus);
29 0 : }
30 :
31 : nsresult
32 0 : nsWifiScannerDBus::Scan()
33 : {
34 0 : if (!mConnection) {
35 0 : return NS_ERROR_NOT_AVAILABLE;
36 : }
37 : return SendMessage("org.freedesktop.NetworkManager",
38 : "/org/freedesktop/NetworkManager",
39 0 : "GetDevices");
40 : }
41 :
42 : nsresult
43 0 : nsWifiScannerDBus::SendMessage(const char* aInterface,
44 : const char* aPath,
45 : const char* aFuncCall)
46 : {
47 0 : RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
48 : dbus_message_new_method_call("org.freedesktop.NetworkManager",
49 0 : aPath, aInterface, aFuncCall));
50 0 : if (!msg) {
51 0 : return NS_ERROR_FAILURE;
52 : }
53 :
54 : DBusMessageIter argsIter;
55 0 : dbus_message_iter_init_append(msg, &argsIter);
56 :
57 0 : if (!strcmp(aFuncCall, "Get")) {
58 0 : const char* paramInterface = "org.freedesktop.NetworkManager.Device";
59 0 : if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
60 : ¶mInterface)) {
61 0 : return NS_ERROR_FAILURE;
62 : }
63 :
64 0 : const char* paramDeviceType = "DeviceType";
65 0 : if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
66 : ¶mDeviceType)) {
67 0 : return NS_ERROR_FAILURE;
68 : }
69 0 : } else if (!strcmp(aFuncCall, "GetAll")) {
70 0 : const char* param = "";
71 0 : if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, ¶m)) {
72 0 : return NS_ERROR_FAILURE;
73 : }
74 : }
75 :
76 : DBusError err;
77 0 : dbus_error_init(&err);
78 :
79 : // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
80 : // Refer to function dbus_connection_send_with_reply_and_block.
81 0 : const uint32_t DBUS_DEFAULT_TIMEOUT = -1;
82 0 : RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
83 : dbus_connection_send_with_reply_and_block(mConnection, msg,
84 0 : DBUS_DEFAULT_TIMEOUT, &err));
85 0 : if (dbus_error_is_set(&err)) {
86 0 : dbus_error_free(&err);
87 :
88 : // In the GetAccessPoints case, if there are no access points, error is set.
89 : // We don't want to error out here.
90 0 : if (!strcmp(aFuncCall, "GetAccessPoints")) {
91 0 : return NS_OK;
92 : }
93 0 : return NS_ERROR_FAILURE;
94 : }
95 :
96 : nsresult rv;
97 0 : if (!strcmp(aFuncCall, "GetDevices")) {
98 0 : rv = IdentifyDevices(reply);
99 0 : } else if (!strcmp(aFuncCall, "Get")) {
100 0 : rv = IdentifyDeviceType(reply, aPath);
101 0 : } else if (!strcmp(aFuncCall, "GetAccessPoints")) {
102 0 : rv = IdentifyAccessPoints(reply);
103 0 : } else if (!strcmp(aFuncCall, "GetAll")) {
104 0 : rv = IdentifyAPProperties(reply);
105 : } else {
106 0 : rv = NS_ERROR_FAILURE;
107 : }
108 0 : return rv;
109 : }
110 :
111 : nsresult
112 0 : nsWifiScannerDBus::IdentifyDevices(DBusMessage* aMsg)
113 : {
114 : DBusMessageIter iter;
115 0 : nsresult rv = GetDBusIterator(aMsg, &iter);
116 0 : NS_ENSURE_SUCCESS(rv, rv);
117 :
118 : const char* devicePath;
119 0 : do {
120 0 : if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
121 0 : return NS_ERROR_FAILURE;
122 : }
123 :
124 0 : dbus_message_iter_get_basic(&iter, &devicePath);
125 0 : if (!devicePath) {
126 0 : return NS_ERROR_FAILURE;
127 : }
128 :
129 0 : rv = SendMessage("org.freedesktop.DBus.Properties", devicePath, "Get");
130 0 : NS_ENSURE_SUCCESS(rv, rv);
131 0 : } while (dbus_message_iter_next(&iter));
132 :
133 0 : return NS_OK;
134 : }
135 :
136 : nsresult
137 0 : nsWifiScannerDBus::IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath)
138 : {
139 : DBusMessageIter args;
140 0 : if (!dbus_message_iter_init(aMsg, &args)) {
141 0 : return NS_ERROR_FAILURE;
142 : }
143 :
144 0 : if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) {
145 0 : return NS_ERROR_FAILURE;
146 : }
147 :
148 : DBusMessageIter variantIter;
149 0 : dbus_message_iter_recurse(&args, &variantIter);
150 0 : if (dbus_message_iter_get_arg_type(&variantIter) != DBUS_TYPE_UINT32) {
151 0 : return NS_ERROR_FAILURE;
152 : }
153 :
154 : uint32_t deviceType;
155 0 : dbus_message_iter_get_basic(&variantIter, &deviceType);
156 :
157 : // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html
158 : // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE.
159 0 : const uint32_t NM_DEVICE_TYPE_WIFI = 2;
160 0 : nsresult rv = NS_OK;
161 0 : if (deviceType == NM_DEVICE_TYPE_WIFI) {
162 : rv = SendMessage("org.freedesktop.NetworkManager.Device.Wireless",
163 0 : aDevicePath, "GetAccessPoints");
164 : }
165 :
166 0 : return rv;
167 : }
168 :
169 : nsresult
170 0 : nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage* aMsg)
171 : {
172 : DBusMessageIter iter;
173 0 : nsresult rv = GetDBusIterator(aMsg, &iter);
174 0 : NS_ENSURE_SUCCESS(rv, rv);
175 :
176 : const char* path;
177 0 : do {
178 0 : if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
179 0 : return NS_ERROR_FAILURE;
180 : }
181 0 : dbus_message_iter_get_basic(&iter, &path);
182 0 : if (!path) {
183 0 : return NS_ERROR_FAILURE;
184 : }
185 :
186 0 : rv = SendMessage("org.freedesktop.DBus.Properties", path, "GetAll");
187 0 : NS_ENSURE_SUCCESS(rv, rv);
188 0 : } while (dbus_message_iter_next(&iter));
189 :
190 0 : return NS_OK;
191 : }
192 :
193 : nsresult
194 0 : nsWifiScannerDBus::IdentifyAPProperties(DBusMessage* aMsg)
195 : {
196 : DBusMessageIter arr;
197 0 : nsresult rv = GetDBusIterator(aMsg, &arr);
198 0 : NS_ENSURE_SUCCESS(rv, rv);
199 :
200 0 : RefPtr<nsWifiAccessPoint> ap = new nsWifiAccessPoint();
201 0 : do {
202 : DBusMessageIter dict;
203 0 : dbus_message_iter_recurse(&arr, &dict);
204 :
205 0 : do {
206 : const char* key;
207 0 : dbus_message_iter_get_basic(&dict, &key);
208 0 : if (!key) {
209 0 : return NS_ERROR_FAILURE;
210 : }
211 0 : dbus_message_iter_next(&dict);
212 :
213 : DBusMessageIter variant;
214 0 : dbus_message_iter_recurse(&dict, &variant);
215 :
216 0 : if (!strncmp(key, "Ssid", strlen("Ssid"))) {
217 0 : nsresult rv = StoreSsid(&variant, ap);
218 0 : NS_ENSURE_SUCCESS(rv, rv);
219 0 : break;
220 : }
221 :
222 0 : if (!strncmp(key, "HwAddress", strlen("HwAddress"))) {
223 0 : nsresult rv = SetMac(&variant, ap);
224 0 : NS_ENSURE_SUCCESS(rv, rv);
225 0 : break;
226 : }
227 :
228 0 : if (!strncmp(key, "Strength", strlen("Strength"))) {
229 0 : if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_BYTE) {
230 0 : return NS_ERROR_FAILURE;
231 : }
232 :
233 : uint8_t strength;
234 0 : dbus_message_iter_get_basic(&variant, &strength);
235 0 : ap->setSignal(strength);
236 : }
237 0 : } while (dbus_message_iter_next(&dict));
238 0 : } while (dbus_message_iter_next(&arr));
239 :
240 0 : mAccessPoints->AppendObject(ap);
241 0 : return NS_OK;
242 : }
243 :
244 : nsresult
245 0 : nsWifiScannerDBus::StoreSsid(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp)
246 : {
247 0 : if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_ARRAY) {
248 0 : return NS_ERROR_FAILURE;
249 : }
250 :
251 : DBusMessageIter variantMember;
252 0 : dbus_message_iter_recurse(aVariant, &variantMember);
253 :
254 0 : const uint32_t MAX_SSID_LEN = 32;
255 : char ssid[MAX_SSID_LEN];
256 0 : memset(ssid, '\0', ArrayLength(ssid));
257 0 : uint32_t i = 0;
258 0 : do {
259 0 : if (dbus_message_iter_get_arg_type(&variantMember) != DBUS_TYPE_BYTE) {
260 0 : return NS_ERROR_FAILURE;
261 : }
262 :
263 0 : dbus_message_iter_get_basic(&variantMember, &ssid[i]);
264 0 : i++;
265 0 : } while (dbus_message_iter_next(&variantMember) && i < MAX_SSID_LEN);
266 :
267 0 : aAp->setSSID(ssid, i);
268 0 : return NS_OK;
269 : }
270 :
271 : nsresult
272 0 : nsWifiScannerDBus::SetMac(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp)
273 : {
274 0 : if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_STRING) {
275 0 : return NS_ERROR_FAILURE;
276 : }
277 :
278 : // hwAddress format is XX:XX:XX:XX:XX:XX. Need to convert to XXXXXX format.
279 : char* hwAddress;
280 0 : dbus_message_iter_get_basic(aVariant, &hwAddress);
281 0 : if (!hwAddress) {
282 0 : return NS_ERROR_FAILURE;
283 : }
284 :
285 0 : const uint32_t MAC_LEN = 6;
286 : uint8_t macAddress[MAC_LEN];
287 0 : char* token = strtok(hwAddress, ":");
288 0 : for (uint32_t i = 0; i < ArrayLength(macAddress); i++) {
289 0 : if (!token) {
290 0 : return NS_ERROR_FAILURE;
291 : }
292 0 : macAddress[i] = strtoul(token, nullptr, 16);
293 0 : token = strtok(nullptr, ":");
294 : }
295 0 : aAp->setMac(macAddress);
296 0 : return NS_OK;
297 : }
298 :
299 : nsresult
300 0 : nsWifiScannerDBus::GetDBusIterator(DBusMessage* aMsg,
301 : DBusMessageIter* aIterArray)
302 : {
303 : DBusMessageIter iter;
304 0 : if (!dbus_message_iter_init(aMsg, &iter)) {
305 0 : return NS_ERROR_FAILURE;
306 : }
307 :
308 0 : if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
309 0 : return NS_ERROR_FAILURE;
310 : }
311 :
312 0 : dbus_message_iter_recurse(&iter, aIterArray);
313 0 : return NS_OK;
314 : }
315 :
316 : } // mozilla
317 :
318 : nsresult
319 0 : nsWifiMonitor::DoScan()
320 : {
321 0 : nsCOMArray<nsWifiAccessPoint> accessPoints;
322 0 : mozilla::nsWifiScannerDBus wifiScanner(&accessPoints);
323 0 : nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
324 :
325 0 : while (mKeepGoing) {
326 0 : accessPoints.Clear();
327 0 : nsresult rv = wifiScanner.Scan();
328 0 : NS_ENSURE_SUCCESS(rv, rv);
329 0 : bool accessPointsChanged = !AccessPointsEqual(accessPoints,
330 0 : lastAccessPoints);
331 0 : ReplaceArray(lastAccessPoints, accessPoints);
332 :
333 0 : rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
334 0 : NS_ENSURE_SUCCESS(rv, rv);
335 :
336 0 : LOG(("waiting on monitor\n"));
337 0 : mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
338 0 : mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
339 : }
340 :
341 0 : return NS_OK;
342 : }
|