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 "nsWifiAccessPoint.h"
10 nsWifiScannerDBus::nsWifiScannerDBus(nsCOMArray
<nsWifiAccessPoint
> *aAccessPoints
)
11 : mAccessPoints(aAccessPoints
)
13 MOZ_ASSERT(mAccessPoints
);
15 mConnection
= dbus_bus_get(DBUS_BUS_SYSTEM
, nullptr);
16 MOZ_ASSERT(mConnection
);
17 dbus_connection_set_exit_on_disconnect(mConnection
, false);
19 MOZ_COUNT_CTOR(nsWifiScannerDBus
);
22 nsWifiScannerDBus::~nsWifiScannerDBus()
25 dbus_connection_unref(mConnection
);
27 MOZ_COUNT_DTOR(nsWifiScannerDBus
);
31 nsWifiScannerDBus::Scan()
33 return SendMessage("org.freedesktop.NetworkManager",
34 "/org/freedesktop/NetworkManager",
39 nsWifiScannerDBus::SendMessage(const char* aInterface
,
41 const char* aFuncCall
)
44 dbus_message_new_method_call("org.freedesktop.NetworkManager",
45 aPath
, aInterface
, aFuncCall
);
47 return NS_ERROR_FAILURE
;
50 DBusMessageIter argsIter
;
51 dbus_message_iter_init_append(msg
, &argsIter
);
53 if (!strcmp(aFuncCall
, "Get")) {
54 const char* paramInterface
= "org.freedesktop.NetworkManager.Device";
55 if (!dbus_message_iter_append_basic(&argsIter
, DBUS_TYPE_STRING
,
57 return NS_ERROR_FAILURE
;
60 const char* paramDeviceType
= "DeviceType";
61 if (!dbus_message_iter_append_basic(&argsIter
, DBUS_TYPE_STRING
,
63 return NS_ERROR_FAILURE
;
65 } else if (!strcmp(aFuncCall
, "GetAll")) {
66 const char* param
= "";
67 if (!dbus_message_iter_append_basic(&argsIter
, DBUS_TYPE_STRING
, ¶m
)) {
68 return NS_ERROR_FAILURE
;
73 dbus_error_init(&err
);
75 // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
76 // Refer to function dbus_connection_send_with_reply_and_block.
77 const uint32_t DBUS_DEFAULT_TIMEOUT
= -1;
78 DBusMessage
* reply
= nullptr;
79 reply
= dbus_connection_send_with_reply_and_block(mConnection
, msg
,
80 DBUS_DEFAULT_TIMEOUT
, &err
);
81 if (dbus_error_is_set(&err
)) {
82 dbus_error_free(&err
);
84 // In the GetAccessPoints case, if there are no access points, error is set.
85 // We don't want to error out here.
86 if (!strcmp(aFuncCall
, "GetAccessPoints")) {
89 return NS_ERROR_FAILURE
;
93 if (!strcmp(aFuncCall
, "GetDevices")) {
94 rv
= IdentifyDevices(reply
);
95 } else if (!strcmp(aFuncCall
, "Get")) {
96 rv
= IdentifyDeviceType(reply
, aPath
);
97 } else if (!strcmp(aFuncCall
, "GetAccessPoints")) {
98 rv
= IdentifyAccessPoints(reply
);
99 } else if (!strcmp(aFuncCall
, "GetAll")) {
100 rv
= IdentifyAPProperties(reply
);
102 rv
= NS_ERROR_FAILURE
;
104 dbus_message_unref(reply
);
109 nsWifiScannerDBus::IdentifyDevices(DBusMessage
* aMsg
)
111 DBusMessageIter iter
;
112 nsresult rv
= GetDBusIterator(aMsg
, &iter
);
113 NS_ENSURE_SUCCESS(rv
, rv
);
115 const char* devicePath
;
117 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_OBJECT_PATH
) {
118 return NS_ERROR_FAILURE
;
121 dbus_message_iter_get_basic(&iter
, &devicePath
);
123 return NS_ERROR_FAILURE
;
126 rv
= SendMessage("org.freedesktop.DBus.Properties", devicePath
, "Get");
127 NS_ENSURE_SUCCESS(rv
, rv
);
128 } while (dbus_message_iter_next(&iter
));
134 nsWifiScannerDBus::IdentifyDeviceType(DBusMessage
* aMsg
, const char* aDevicePath
)
136 DBusMessageIter args
;
137 if (!dbus_message_iter_init(aMsg
, &args
)) {
138 return NS_ERROR_FAILURE
;
141 if (dbus_message_iter_get_arg_type(&args
) != DBUS_TYPE_VARIANT
) {
142 return NS_ERROR_FAILURE
;
145 DBusMessageIter variantIter
;
146 dbus_message_iter_recurse(&args
, &variantIter
);
147 if (dbus_message_iter_get_arg_type(&variantIter
) != DBUS_TYPE_UINT32
) {
148 return NS_ERROR_FAILURE
;
152 dbus_message_iter_get_basic(&variantIter
, &deviceType
);
154 // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html
155 // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE.
156 const uint32_t NM_DEVICE_TYPE_WIFI
= 2;
158 if (deviceType
== NM_DEVICE_TYPE_WIFI
) {
159 rv
= SendMessage("org.freedesktop.NetworkManager.Device.Wireless",
160 aDevicePath
, "GetAccessPoints");
167 nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage
* aMsg
)
169 DBusMessageIter iter
;
170 nsresult rv
= GetDBusIterator(aMsg
, &iter
);
171 NS_ENSURE_SUCCESS(rv
, rv
);
175 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_OBJECT_PATH
) {
176 return NS_ERROR_FAILURE
;
178 dbus_message_iter_get_basic(&iter
, &path
);
180 return NS_ERROR_FAILURE
;
183 rv
= SendMessage("org.freedesktop.DBus.Properties", path
, "GetAll");
184 NS_ENSURE_SUCCESS(rv
, rv
);
185 } while (dbus_message_iter_next(&iter
));
191 nsWifiScannerDBus::IdentifyAPProperties(DBusMessage
* aMsg
)
194 nsresult rv
= GetDBusIterator(aMsg
, &arr
);
195 NS_ENSURE_SUCCESS(rv
, rv
);
197 nsRefPtr
<nsWifiAccessPoint
> ap
= new nsWifiAccessPoint();
199 DBusMessageIter dict
;
200 dbus_message_iter_recurse(&arr
, &dict
);
204 dbus_message_iter_get_basic(&dict
, &key
);
206 return NS_ERROR_FAILURE
;
208 dbus_message_iter_next(&dict
);
210 DBusMessageIter variant
;
211 dbus_message_iter_recurse(&dict
, &variant
);
213 if (!strncmp(key
, "Ssid", strlen("Ssid"))) {
214 nsresult rv
= StoreSsid(&variant
, ap
);
215 NS_ENSURE_SUCCESS(rv
, rv
);
219 if (!strncmp(key
, "HwAddress", strlen("HwAddress"))) {
220 nsresult rv
= SetMac(&variant
, ap
);
221 NS_ENSURE_SUCCESS(rv
, rv
);
225 if (!strncmp(key
, "Strength", strlen("Strength"))) {
226 if (dbus_message_iter_get_arg_type(&variant
) != DBUS_TYPE_BYTE
) {
227 return NS_ERROR_FAILURE
;
231 dbus_message_iter_get_basic(&variant
, &strength
);
232 ap
->setSignal(strength
);
234 } while (dbus_message_iter_next(&dict
));
235 } while (dbus_message_iter_next(&arr
));
237 mAccessPoints
->AppendObject(ap
);
242 nsWifiScannerDBus::StoreSsid(DBusMessageIter
* aVariant
, nsWifiAccessPoint
* aAp
)
244 if (dbus_message_iter_get_arg_type(aVariant
) != DBUS_TYPE_ARRAY
) {
245 return NS_ERROR_FAILURE
;
248 DBusMessageIter variantMember
;
249 dbus_message_iter_recurse(aVariant
, &variantMember
);
251 const uint32_t MAX_SSID_LEN
= 32;
252 char ssid
[MAX_SSID_LEN
];
253 memset(ssid
, '\0', ArrayLength(ssid
));
256 if (dbus_message_iter_get_arg_type(&variantMember
) != DBUS_TYPE_BYTE
) {
257 return NS_ERROR_FAILURE
;
260 dbus_message_iter_get_basic(&variantMember
, &ssid
[i
]);
262 } while (dbus_message_iter_next(&variantMember
) && i
< MAX_SSID_LEN
);
264 aAp
->setSSID(ssid
, i
);
269 nsWifiScannerDBus::SetMac(DBusMessageIter
* aVariant
, nsWifiAccessPoint
* aAp
)
271 if (dbus_message_iter_get_arg_type(aVariant
) != DBUS_TYPE_STRING
) {
272 return NS_ERROR_FAILURE
;
275 // hwAddress format is XX:XX:XX:XX:XX:XX. Need to convert to XXXXXX format.
277 dbus_message_iter_get_basic(aVariant
, &hwAddress
);
279 return NS_ERROR_FAILURE
;
282 const uint32_t MAC_LEN
= 6;
283 uint8_t macAddress
[MAC_LEN
];
284 char* token
= strtok(hwAddress
, ":");
285 for (uint32_t i
= 0; i
< ArrayLength(macAddress
); i
++) {
287 return NS_ERROR_FAILURE
;
289 macAddress
[i
] = strtoul(token
, nullptr, 16);
290 token
= strtok(nullptr, ":");
292 aAp
->setMac(macAddress
);
297 nsWifiScannerDBus::GetDBusIterator(DBusMessage
* aMsg
,
298 DBusMessageIter
* aIterArray
)
300 DBusMessageIter iter
;
301 if (!dbus_message_iter_init(aMsg
, &iter
)) {
302 return NS_ERROR_FAILURE
;
305 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
) {
306 return NS_ERROR_FAILURE
;
309 dbus_message_iter_recurse(&iter
, aIterArray
);
316 nsWifiMonitor::DoScan()
318 nsCOMArray
<nsWifiAccessPoint
> accessPoints
;
319 mozilla::nsWifiScannerDBus
wifiScanner(&accessPoints
);
320 nsCOMArray
<nsWifiAccessPoint
> lastAccessPoints
;
323 accessPoints
.Clear();
324 nsresult rv
= wifiScanner
.Scan();
325 NS_ENSURE_SUCCESS(rv
, rv
);
326 bool accessPointsChanged
= !AccessPointsEqual(accessPoints
,
328 ReplaceArray(lastAccessPoints
, accessPoints
);
330 rv
= CallWifiListeners(lastAccessPoints
, accessPointsChanged
);
331 NS_ENSURE_SUCCESS(rv
, rv
);
333 LOG(("waiting on monitor\n"));
334 mozilla::ReentrantMonitorAutoEnter
mon(mReentrantMonitor
);
335 mon
.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval
));