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/. */
5 #include "nsWifiScannerDBus.h"
6 #include "mozilla/DBusHelpers.h"
7 #include "nsWifiAccessPoint.h"
11 nsWifiScannerDBus::nsWifiScannerDBus(
12 nsCOMArray
<nsWifiAccessPoint
>* aAccessPoints
)
13 : mAccessPoints(aAccessPoints
) {
14 MOZ_ASSERT(mAccessPoints
);
17 already_AddRefed
<DBusConnection
>(dbus_bus_get(DBUS_BUS_SYSTEM
, nullptr));
20 dbus_connection_setup_with_g_main(mConnection
, nullptr);
21 dbus_connection_set_exit_on_disconnect(mConnection
, false);
24 MOZ_COUNT_CTOR(nsWifiScannerDBus
);
27 nsWifiScannerDBus::~nsWifiScannerDBus() { MOZ_COUNT_DTOR(nsWifiScannerDBus
); }
29 nsresult
nsWifiScannerDBus::Scan() {
31 return NS_ERROR_NOT_AVAILABLE
;
33 return SendGetDevices();
36 // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
37 // Refer to function dbus_connection_send_with_reply_and_block.
38 static const uint32_t DBUS_DEFAULT_TIMEOUT
= -1;
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"));
46 return NS_ERROR_FAILURE
;
50 dbus_error_init(&err
);
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
;
60 return IdentifyDevices(reply
);
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"));
68 return NS_ERROR_FAILURE
;
71 DBusMessageIter argsIter
;
72 dbus_message_iter_init_append(msg
, &argsIter
);
74 const char* paramInterface
= "org.freedesktop.NetworkManager.Device";
75 if (!dbus_message_iter_append_basic(&argsIter
, DBUS_TYPE_STRING
,
77 return NS_ERROR_FAILURE
;
80 const char* paramDeviceType
= "DeviceType";
81 if (!dbus_message_iter_append_basic(&argsIter
, DBUS_TYPE_STRING
,
83 return NS_ERROR_FAILURE
;
87 dbus_error_init(&err
);
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
;
97 return IdentifyDeviceType(reply
, aPath
);
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"));
106 return NS_ERROR_FAILURE
;
110 dbus_error_init(&err
);
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.
122 return IdentifyAccessPoints(reply
);
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"));
131 return NS_ERROR_FAILURE
;
134 DBusMessageIter argsIter
;
135 dbus_message_iter_init_append(msg
, &argsIter
);
137 const char* param
= "org.freedesktop.NetworkManager.AccessPoint";
138 if (!dbus_message_iter_append_basic(&argsIter
, DBUS_TYPE_STRING
, ¶m
)) {
139 return NS_ERROR_FAILURE
;
143 dbus_error_init(&err
);
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
;
153 return IdentifyAPProperties(reply
);
156 nsresult
nsWifiScannerDBus::IdentifyDevices(DBusMessage
* aMsg
) {
157 DBusMessageIter iter
;
158 nsresult rv
= GetDBusIterator(aMsg
, &iter
);
159 NS_ENSURE_SUCCESS(rv
, rv
);
161 const char* devicePath
;
163 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_OBJECT_PATH
) {
164 return NS_ERROR_FAILURE
;
167 dbus_message_iter_get_basic(&iter
, &devicePath
);
169 return NS_ERROR_FAILURE
;
172 rv
= SendGetDeviceType(devicePath
);
173 NS_ENSURE_SUCCESS(rv
, rv
);
174 } while (dbus_message_iter_next(&iter
));
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
;
186 if (dbus_message_iter_get_arg_type(&args
) != DBUS_TYPE_VARIANT
) {
187 return NS_ERROR_FAILURE
;
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
;
197 dbus_message_iter_get_basic(&variantIter
, &deviceType
);
199 // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html
200 // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE.
201 const uint32_t NM_DEVICE_TYPE_WIFI
= 2;
203 if (deviceType
== NM_DEVICE_TYPE_WIFI
) {
204 rv
= SendGetAccessPoints(aDevicePath
);
210 nsresult
nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage
* aMsg
) {
211 DBusMessageIter iter
;
212 nsresult rv
= GetDBusIterator(aMsg
, &iter
);
213 NS_ENSURE_SUCCESS(rv
, rv
);
217 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_OBJECT_PATH
) {
218 return NS_ERROR_FAILURE
;
220 dbus_message_iter_get_basic(&iter
, &path
);
222 return NS_ERROR_FAILURE
;
225 rv
= SendGetAPProperties(path
);
226 NS_ENSURE_SUCCESS(rv
, rv
);
227 } while (dbus_message_iter_next(&iter
));
232 nsresult
nsWifiScannerDBus::IdentifyAPProperties(DBusMessage
* aMsg
) {
234 nsresult rv
= GetDBusIterator(aMsg
, &arr
);
235 NS_ENSURE_SUCCESS(rv
, rv
);
237 RefPtr
<nsWifiAccessPoint
> ap
= new nsWifiAccessPoint();
239 DBusMessageIter dict
;
240 dbus_message_iter_recurse(&arr
, &dict
);
244 dbus_message_iter_get_basic(&dict
, &key
);
246 return NS_ERROR_FAILURE
;
248 dbus_message_iter_next(&dict
);
250 DBusMessageIter variant
;
251 dbus_message_iter_recurse(&dict
, &variant
);
253 if (!strncmp(key
, "Ssid", strlen("Ssid"))) {
254 nsresult rv
= StoreSsid(&variant
, ap
);
255 NS_ENSURE_SUCCESS(rv
, rv
);
259 if (!strncmp(key
, "HwAddress", strlen("HwAddress"))) {
260 nsresult rv
= SetMac(&variant
, ap
);
261 NS_ENSURE_SUCCESS(rv
, rv
);
265 if (!strncmp(key
, "Strength", strlen("Strength"))) {
266 if (dbus_message_iter_get_arg_type(&variant
) != DBUS_TYPE_BYTE
) {
267 return NS_ERROR_FAILURE
;
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
);
275 } while (dbus_message_iter_next(&dict
));
276 } while (dbus_message_iter_next(&arr
));
278 mAccessPoints
->AppendObject(ap
);
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
;
288 DBusMessageIter variantMember
;
289 dbus_message_iter_recurse(aVariant
, &variantMember
);
291 const uint32_t MAX_SSID_LEN
= 32;
292 char ssid
[MAX_SSID_LEN
];
293 memset(ssid
, '\0', ArrayLength(ssid
));
296 if (dbus_message_iter_get_arg_type(&variantMember
) != DBUS_TYPE_BYTE
) {
297 return NS_ERROR_FAILURE
;
300 dbus_message_iter_get_basic(&variantMember
, &ssid
[i
]);
302 } while (dbus_message_iter_next(&variantMember
) && i
< MAX_SSID_LEN
);
304 aAp
->setSSID(ssid
, i
);
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
;
314 // hwAddress format is XX:XX:XX:XX:XX:XX. Need to convert to XXXXXX format.
316 dbus_message_iter_get_basic(aVariant
, &hwAddress
);
318 return NS_ERROR_FAILURE
;
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
++) {
326 return NS_ERROR_FAILURE
;
328 macAddress
[i
] = strtoul(token
, nullptr, 16);
329 token
= strtok(nullptr, ":");
331 aAp
->setMac(macAddress
);
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
;
342 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
) {
343 return NS_ERROR_FAILURE
;
346 dbus_message_iter_recurse(&iter
, aIterArray
);
350 } // namespace mozilla
352 nsresult
nsWifiMonitor::DoScan() {
353 nsCOMArray
<nsWifiAccessPoint
> accessPoints
;
354 mozilla::nsWifiScannerDBus
wifiScanner(&accessPoints
);
355 nsCOMArray
<nsWifiAccessPoint
> lastAccessPoints
;
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
);
365 rv
= CallWifiListeners(lastAccessPoints
, accessPointsChanged
);
366 NS_ENSURE_SUCCESS(rv
, rv
);
368 LOG(("waiting on monitor\n"));
369 mozilla::ReentrantMonitorAutoEnter
mon(mReentrantMonitor
);
370 mon
.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval
));