Coverage Report

Created: 2018-09-25 14:53

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