Source code

Revision control

Other Tools

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