]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * WPA Supplicant / dbus-based control interface | |
3 | * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "includes.h" | |
16 | ||
17 | #include "common.h" | |
18 | #include "config.h" | |
19 | #include "wpa_supplicant_i.h" | |
2d5b792d | 20 | #include "driver_i.h" |
6fc6879b JM |
21 | #include "ctrl_iface_dbus.h" |
22 | #include "ctrl_iface_dbus_handlers.h" | |
8bac466b | 23 | #include "notify.h" |
6fc6879b JM |
24 | #include "eap_peer/eap_methods.h" |
25 | #include "dbus_dict_helpers.h" | |
90973fb2 | 26 | #include "common/ieee802_11_defs.h" |
e403be0b DS |
27 | #include "wpas_glue.h" |
28 | #include "eapol_supp/eapol_supp_sm.h" | |
e8fa6039 | 29 | #include "wps_supplicant.h" |
d7199342 | 30 | #include "wpa.h" |
6fc6879b | 31 | |
01a569e8 HS |
32 | extern int wpa_debug_level; |
33 | extern int wpa_debug_show_keys; | |
34 | extern int wpa_debug_timestamp; | |
6fc6879b JM |
35 | |
36 | /** | |
37 | * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message | |
38 | * @message: Pointer to incoming dbus message this error refers to | |
39 | * Returns: a dbus error message | |
40 | * | |
41 | * Convenience function to create and return an invalid options error | |
42 | */ | |
43 | static DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, | |
44 | const char *arg) | |
45 | { | |
46 | DBusMessage *reply; | |
47 | ||
48 | reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS, | |
8fc2fb56 WS |
49 | "Did not receive correct message " |
50 | "arguments."); | |
6fc6879b JM |
51 | if (arg != NULL) |
52 | dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, | |
53 | DBUS_TYPE_INVALID); | |
54 | ||
55 | return reply; | |
56 | } | |
57 | ||
58 | ||
59 | /** | |
60 | * wpas_dbus_new_success_reply - Return a new success reply message | |
61 | * @message: Pointer to incoming dbus message this reply refers to | |
62 | * Returns: a dbus message containing a single UINT32 that indicates | |
63 | * success (ie, a value of 1) | |
64 | * | |
65 | * Convenience function to create and return a success reply message | |
66 | */ | |
67 | static DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message) | |
68 | { | |
69 | DBusMessage *reply; | |
70 | unsigned int success = 1; | |
71 | ||
72 | reply = dbus_message_new_method_return(message); | |
73 | dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success, | |
74 | DBUS_TYPE_INVALID); | |
75 | return reply; | |
76 | } | |
77 | ||
78 | ||
79 | static void wpas_dbus_free_wpa_interface(struct wpa_interface *iface) | |
80 | { | |
8fc2fb56 WS |
81 | os_free((char *) iface->driver); |
82 | os_free((char *) iface->driver_param); | |
83 | os_free((char *) iface->confname); | |
84 | os_free((char *) iface->bridge_ifname); | |
6fc6879b JM |
85 | } |
86 | ||
87 | ||
88 | /** | |
89 | * wpas_dbus_global_add_interface - Request registration of a network interface | |
90 | * @message: Pointer to incoming dbus message | |
91 | * @global: %wpa_supplicant global data structure | |
92 | * Returns: The object path of the new interface object, | |
93 | * or a dbus error message with more information | |
94 | * | |
95 | * Handler function for "addInterface" method call. Handles requests | |
96 | * by dbus clients to register a network interface that wpa_supplicant | |
97 | * will manage. | |
98 | */ | |
99 | DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, | |
100 | struct wpa_global *global) | |
101 | { | |
102 | struct wpa_interface iface; | |
103 | char *ifname = NULL; | |
104 | DBusMessage *reply = NULL; | |
105 | DBusMessageIter iter; | |
106 | ||
8fc2fb56 | 107 | os_memset(&iface, 0, sizeof(iface)); |
6fc6879b JM |
108 | |
109 | dbus_message_iter_init(message, &iter); | |
110 | ||
111 | /* First argument: interface name (DBUS_TYPE_STRING) | |
112 | * Required; must be non-zero length | |
113 | */ | |
114 | if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) | |
115 | goto error; | |
116 | dbus_message_iter_get_basic(&iter, &ifname); | |
8fc2fb56 | 117 | if (!os_strlen(ifname)) |
6fc6879b JM |
118 | goto error; |
119 | iface.ifname = ifname; | |
120 | ||
121 | /* Second argument: dict of options */ | |
122 | if (dbus_message_iter_next(&iter)) { | |
123 | DBusMessageIter iter_dict; | |
124 | struct wpa_dbus_dict_entry entry; | |
125 | ||
126 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) | |
127 | goto error; | |
128 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
129 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
130 | goto error; | |
131 | if (!strcmp(entry.key, "driver") && | |
132 | (entry.type == DBUS_TYPE_STRING)) { | |
133 | iface.driver = strdup(entry.str_value); | |
134 | if (iface.driver == NULL) | |
135 | goto error; | |
136 | } else if (!strcmp(entry.key, "driver-params") && | |
137 | (entry.type == DBUS_TYPE_STRING)) { | |
138 | iface.driver_param = strdup(entry.str_value); | |
139 | if (iface.driver_param == NULL) | |
140 | goto error; | |
141 | } else if (!strcmp(entry.key, "config-file") && | |
142 | (entry.type == DBUS_TYPE_STRING)) { | |
143 | iface.confname = strdup(entry.str_value); | |
144 | if (iface.confname == NULL) | |
145 | goto error; | |
146 | } else if (!strcmp(entry.key, "bridge-ifname") && | |
147 | (entry.type == DBUS_TYPE_STRING)) { | |
148 | iface.bridge_ifname = strdup(entry.str_value); | |
149 | if (iface.bridge_ifname == NULL) | |
150 | goto error; | |
151 | } else { | |
152 | wpa_dbus_dict_entry_clear(&entry); | |
153 | goto error; | |
154 | } | |
155 | wpa_dbus_dict_entry_clear(&entry); | |
156 | } | |
157 | } | |
158 | ||
159 | /* | |
160 | * Try to get the wpa_supplicant record for this iface, return | |
161 | * an error if we already control it. | |
162 | */ | |
dcc03dbe | 163 | if (wpa_supplicant_get_iface(global, iface.ifname) != NULL) { |
6fc6879b JM |
164 | reply = dbus_message_new_error(message, |
165 | WPAS_ERROR_EXISTS_ERROR, | |
166 | "wpa_supplicant already " | |
167 | "controls this interface."); | |
168 | } else { | |
169 | struct wpa_supplicant *wpa_s; | |
170 | /* Otherwise, have wpa_supplicant attach to it. */ | |
171 | if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { | |
172 | const char *path = wpa_supplicant_get_dbus_path(wpa_s); | |
173 | reply = dbus_message_new_method_return(message); | |
174 | dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, | |
175 | &path, DBUS_TYPE_INVALID); | |
176 | } else { | |
177 | reply = dbus_message_new_error(message, | |
178 | WPAS_ERROR_ADD_ERROR, | |
179 | "wpa_supplicant " | |
180 | "couldn't grab this " | |
181 | "interface."); | |
182 | } | |
183 | } | |
184 | wpas_dbus_free_wpa_interface(&iface); | |
185 | return reply; | |
186 | ||
187 | error: | |
188 | wpas_dbus_free_wpa_interface(&iface); | |
189 | return wpas_dbus_new_invalid_opts_error(message, NULL); | |
190 | } | |
191 | ||
192 | ||
193 | /** | |
194 | * wpas_dbus_global_remove_interface - Request deregistration of an interface | |
195 | * @message: Pointer to incoming dbus message | |
196 | * @global: wpa_supplicant global data structure | |
197 | * Returns: a dbus message containing a UINT32 indicating success (1) or | |
198 | * failure (0), or returns a dbus error message with more information | |
199 | * | |
200 | * Handler function for "removeInterface" method call. Handles requests | |
201 | * by dbus clients to deregister a network interface that wpa_supplicant | |
202 | * currently manages. | |
203 | */ | |
204 | DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, | |
205 | struct wpa_global *global) | |
206 | { | |
207 | struct wpa_supplicant *wpa_s; | |
208 | char *path; | |
209 | DBusMessage *reply = NULL; | |
210 | ||
211 | if (!dbus_message_get_args(message, NULL, | |
212 | DBUS_TYPE_OBJECT_PATH, &path, | |
213 | DBUS_TYPE_INVALID)) { | |
214 | reply = wpas_dbus_new_invalid_opts_error(message, NULL); | |
215 | goto out; | |
216 | } | |
217 | ||
218 | wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path); | |
219 | if (wpa_s == NULL) { | |
220 | reply = wpas_dbus_new_invalid_iface_error(message); | |
221 | goto out; | |
222 | } | |
223 | ||
224 | if (!wpa_supplicant_remove_iface(global, wpa_s)) { | |
225 | reply = wpas_dbus_new_success_reply(message); | |
226 | } else { | |
227 | reply = dbus_message_new_error(message, | |
228 | WPAS_ERROR_REMOVE_ERROR, | |
229 | "wpa_supplicant couldn't " | |
230 | "remove this interface."); | |
231 | } | |
232 | ||
233 | out: | |
234 | return reply; | |
235 | } | |
236 | ||
237 | ||
238 | /** | |
239 | * wpas_dbus_global_get_interface - Get the object path for an interface name | |
240 | * @message: Pointer to incoming dbus message | |
241 | * @global: %wpa_supplicant global data structure | |
242 | * Returns: The object path of the interface object, | |
243 | * or a dbus error message with more information | |
244 | * | |
245 | * Handler function for "getInterface" method call. Handles requests | |
246 | * by dbus clients for the object path of an specific network interface. | |
247 | */ | |
248 | DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, | |
249 | struct wpa_global *global) | |
250 | { | |
251 | DBusMessage *reply = NULL; | |
252 | const char *ifname; | |
253 | const char *path; | |
254 | struct wpa_supplicant *wpa_s; | |
255 | ||
256 | if (!dbus_message_get_args(message, NULL, | |
257 | DBUS_TYPE_STRING, &ifname, | |
258 | DBUS_TYPE_INVALID)) { | |
259 | reply = wpas_dbus_new_invalid_opts_error(message, NULL); | |
260 | goto out; | |
261 | } | |
262 | ||
263 | wpa_s = wpa_supplicant_get_iface(global, ifname); | |
264 | if (wpa_s == NULL) { | |
265 | reply = wpas_dbus_new_invalid_iface_error(message); | |
266 | goto out; | |
267 | } | |
268 | ||
269 | path = wpa_supplicant_get_dbus_path(wpa_s); | |
270 | if (path == NULL) { | |
271 | reply = dbus_message_new_error(message, | |
272 | WPAS_ERROR_INTERNAL_ERROR, | |
273 | "an internal error occurred " | |
274 | "getting the interface."); | |
275 | goto out; | |
276 | } | |
277 | ||
278 | reply = dbus_message_new_method_return(message); | |
279 | dbus_message_append_args(reply, | |
280 | DBUS_TYPE_OBJECT_PATH, &path, | |
281 | DBUS_TYPE_INVALID); | |
282 | ||
283 | out: | |
284 | return reply; | |
285 | } | |
286 | ||
8fc2fb56 | 287 | |
01a569e8 HS |
288 | /** |
289 | * wpas_dbus_global_set_debugparams- Set the debug params | |
290 | * @message: Pointer to incoming dbus message | |
291 | * @global: %wpa_supplicant global data structure | |
292 | * Returns: a dbus message containing a UINT32 indicating success (1) or | |
293 | * failure (0), or returns a dbus error message with more information | |
294 | * | |
295 | * Handler function for "setDebugParams" method call. Handles requests | |
296 | * by dbus clients for the object path of an specific network interface. | |
297 | */ | |
298 | DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, | |
299 | struct wpa_global *global) | |
300 | { | |
301 | DBusMessage *reply = NULL; | |
302 | int debug_level; | |
303 | dbus_bool_t debug_timestamp; | |
304 | dbus_bool_t debug_show_keys; | |
305 | ||
306 | if (!dbus_message_get_args(message, NULL, | |
307 | DBUS_TYPE_INT32, &debug_level, | |
308 | DBUS_TYPE_BOOLEAN, &debug_timestamp, | |
309 | DBUS_TYPE_BOOLEAN, &debug_show_keys, | |
310 | DBUS_TYPE_INVALID)) { | |
8fc2fb56 | 311 | return wpas_dbus_new_invalid_opts_error(message, NULL); |
01a569e8 HS |
312 | } |
313 | ||
86b89452 WS |
314 | if (wpa_supplicant_set_debug_params(global, debug_level, |
315 | debug_timestamp ? 1 : 0, | |
316 | debug_show_keys ? 1 : 0)) { | |
8fc2fb56 | 317 | return wpas_dbus_new_invalid_opts_error(message, NULL); |
01a569e8 HS |
318 | } |
319 | ||
01a569e8 HS |
320 | reply = wpas_dbus_new_success_reply(message); |
321 | ||
01a569e8 HS |
322 | return reply; |
323 | } | |
6fc6879b | 324 | |
8fc2fb56 | 325 | |
6fc6879b JM |
326 | /** |
327 | * wpas_dbus_iface_scan - Request a wireless scan on an interface | |
328 | * @message: Pointer to incoming dbus message | |
329 | * @wpa_s: wpa_supplicant structure for a network interface | |
330 | * Returns: a dbus message containing a UINT32 indicating success (1) or | |
331 | * failure (0) | |
332 | * | |
333 | * Handler function for "scan" method call of a network device. Requests | |
334 | * that wpa_supplicant perform a wireless scan as soon as possible | |
335 | * on a particular wireless interface. | |
336 | */ | |
337 | DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, | |
338 | struct wpa_supplicant *wpa_s) | |
339 | { | |
340 | wpa_s->scan_req = 2; | |
341 | wpa_supplicant_req_scan(wpa_s, 0, 0); | |
342 | return wpas_dbus_new_success_reply(message); | |
343 | } | |
344 | ||
345 | ||
346 | /** | |
347 | * wpas_dbus_iface_scan_results - Get the results of a recent scan request | |
348 | * @message: Pointer to incoming dbus message | |
349 | * @wpa_s: wpa_supplicant structure for a network interface | |
350 | * Returns: a dbus message containing a dbus array of objects paths, or returns | |
351 | * a dbus error message if not scan results could be found | |
352 | * | |
353 | * Handler function for "scanResults" method call of a network device. Returns | |
354 | * a dbus message containing the object paths of wireless networks found. | |
355 | */ | |
356 | DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, | |
357 | struct wpa_supplicant *wpa_s) | |
358 | { | |
359 | DBusMessage *reply = NULL; | |
360 | DBusMessageIter iter; | |
361 | DBusMessageIter sub_iter; | |
362 | size_t i; | |
363 | ||
364 | /* Ensure we've actually got scan results to return */ | |
365 | if (wpa_s->scan_res == NULL && | |
366 | wpa_supplicant_get_scan_results(wpa_s) < 0) { | |
367 | reply = dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR, | |
368 | "An error ocurred getting scan " | |
369 | "results."); | |
370 | goto out; | |
371 | } | |
372 | ||
373 | /* Create and initialize the return message */ | |
374 | reply = dbus_message_new_method_return(message); | |
375 | dbus_message_iter_init_append(reply, &iter); | |
376 | dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, | |
377 | DBUS_TYPE_OBJECT_PATH_AS_STRING, | |
378 | &sub_iter); | |
379 | ||
380 | /* Loop through scan results and append each result's object path */ | |
381 | for (i = 0; i < wpa_s->scan_res->num; i++) { | |
382 | struct wpa_scan_res *res = wpa_s->scan_res->res[i]; | |
383 | char *path; | |
384 | ||
385 | path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); | |
386 | if (path == NULL) { | |
387 | perror("wpas_dbus_iface_scan_results[dbus]: out of " | |
388 | "memory."); | |
389 | wpa_printf(MSG_ERROR, "dbus control interface: not " | |
390 | "enough memory to send scan results " | |
391 | "signal."); | |
392 | break; | |
393 | } | |
394 | /* Construct the object path for this network. Note that ':' | |
395 | * is not a valid character in dbus object paths. | |
396 | */ | |
8fc2fb56 WS |
397 | os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, |
398 | "%s/" WPAS_DBUS_BSSIDS_PART "/" | |
399 | WPAS_DBUS_BSSID_FORMAT, | |
400 | wpa_supplicant_get_dbus_path(wpa_s), | |
401 | MAC2STR(res->bssid)); | |
6fc6879b JM |
402 | dbus_message_iter_append_basic(&sub_iter, |
403 | DBUS_TYPE_OBJECT_PATH, &path); | |
8fc2fb56 | 404 | os_free(path); |
6fc6879b JM |
405 | } |
406 | ||
407 | dbus_message_iter_close_container(&iter, &sub_iter); | |
408 | ||
409 | out: | |
410 | return reply; | |
411 | } | |
412 | ||
413 | ||
414 | /** | |
415 | * wpas_dbus_bssid_properties - Return the properties of a scanned network | |
416 | * @message: Pointer to incoming dbus message | |
417 | * @wpa_s: wpa_supplicant structure for a network interface | |
418 | * @res: wpa_supplicant scan result for which to get properties | |
419 | * Returns: a dbus message containing the properties for the requested network | |
420 | * | |
421 | * Handler function for "properties" method call of a scanned network. | |
422 | * Returns a dbus message containing the the properties. | |
423 | */ | |
424 | DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, | |
425 | struct wpa_supplicant *wpa_s, | |
426 | struct wpa_scan_res *res) | |
427 | { | |
428 | DBusMessage *reply = NULL; | |
429 | DBusMessageIter iter, iter_dict; | |
430 | const u8 *ie; | |
431 | ||
432 | /* Dump the properties into a dbus message */ | |
433 | reply = dbus_message_new_method_return(message); | |
434 | ||
435 | dbus_message_iter_init_append(reply, &iter); | |
436 | if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) | |
437 | goto error; | |
438 | ||
439 | if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid", | |
440 | (const char *) res->bssid, | |
441 | ETH_ALEN)) | |
442 | goto error; | |
443 | ||
444 | ie = wpa_scan_get_ie(res, WLAN_EID_SSID); | |
445 | if (ie) { | |
446 | if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid", | |
447 | (const char *) (ie + 2), | |
448 | ie[1])) | |
449 | goto error; | |
450 | } | |
451 | ||
452 | ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); | |
453 | if (ie) { | |
454 | if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie", | |
455 | (const char *) ie, | |
456 | ie[1] + 2)) | |
457 | goto error; | |
458 | } | |
459 | ||
460 | ie = wpa_scan_get_ie(res, WLAN_EID_RSN); | |
461 | if (ie) { | |
462 | if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie", | |
463 | (const char *) ie, | |
ad08c363 JM |
464 | ie[1] + 2)) |
465 | goto error; | |
466 | } | |
467 | ||
468 | ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE); | |
469 | if (ie) { | |
470 | if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie", | |
471 | (const char *) ie, | |
6fc6879b JM |
472 | ie[1] + 2)) |
473 | goto error; | |
474 | } | |
475 | ||
476 | if (res->freq) { | |
477 | if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency", | |
478 | res->freq)) | |
479 | goto error; | |
480 | } | |
481 | if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities", | |
482 | res->caps)) | |
483 | goto error; | |
7c2849d2 JM |
484 | if (!(res->flags & WPA_SCAN_QUAL_INVALID) && |
485 | !wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual)) | |
6fc6879b | 486 | goto error; |
7c2849d2 JM |
487 | if (!(res->flags & WPA_SCAN_NOISE_INVALID) && |
488 | !wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise)) | |
6fc6879b | 489 | goto error; |
7c2849d2 JM |
490 | if (!(res->flags & WPA_SCAN_LEVEL_INVALID) && |
491 | !wpa_dbus_dict_append_int32(&iter_dict, "level", res->level)) | |
6fc6879b JM |
492 | goto error; |
493 | if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate", | |
93ef879f | 494 | wpa_scan_get_max_rate(res) * 500000)) |
6fc6879b JM |
495 | goto error; |
496 | ||
497 | if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) | |
498 | goto error; | |
499 | ||
500 | return reply; | |
501 | ||
502 | error: | |
503 | if (reply) | |
504 | dbus_message_unref(reply); | |
505 | return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, | |
506 | "an internal error occurred returning " | |
507 | "BSSID properties."); | |
508 | } | |
509 | ||
510 | ||
511 | /** | |
512 | * wpas_dbus_iface_capabilities - Return interface capabilities | |
513 | * @message: Pointer to incoming dbus message | |
514 | * @wpa_s: wpa_supplicant structure for a network interface | |
515 | * Returns: A dbus message containing a dict of strings | |
516 | * | |
517 | * Handler function for "capabilities" method call of an interface. | |
518 | */ | |
519 | DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, | |
520 | struct wpa_supplicant *wpa_s) | |
521 | { | |
522 | DBusMessage *reply = NULL; | |
523 | struct wpa_driver_capa capa; | |
524 | int res; | |
525 | DBusMessageIter iter, iter_dict; | |
526 | char **eap_methods; | |
527 | size_t num_items; | |
528 | dbus_bool_t strict = FALSE; | |
529 | DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; | |
530 | ||
531 | if (!dbus_message_get_args(message, NULL, | |
532 | DBUS_TYPE_BOOLEAN, &strict, | |
533 | DBUS_TYPE_INVALID)) | |
534 | strict = FALSE; | |
535 | ||
536 | reply = dbus_message_new_method_return(message); | |
537 | ||
538 | dbus_message_iter_init_append(reply, &iter); | |
539 | if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) | |
540 | goto error; | |
541 | ||
542 | /* EAP methods */ | |
543 | eap_methods = eap_get_names_as_string_array(&num_items); | |
544 | if (eap_methods) { | |
545 | dbus_bool_t success = FALSE; | |
546 | size_t i = 0; | |
547 | ||
548 | success = wpa_dbus_dict_append_string_array( | |
549 | &iter_dict, "eap", (const char **) eap_methods, | |
550 | num_items); | |
551 | ||
552 | /* free returned method array */ | |
553 | while (eap_methods[i]) | |
8fc2fb56 WS |
554 | os_free(eap_methods[i++]); |
555 | os_free(eap_methods); | |
6fc6879b JM |
556 | |
557 | if (!success) | |
558 | goto error; | |
559 | } | |
560 | ||
561 | res = wpa_drv_get_capa(wpa_s, &capa); | |
562 | ||
563 | /***** pairwise cipher */ | |
564 | if (res < 0) { | |
565 | if (!strict) { | |
566 | const char *args[] = {"CCMP", "TKIP", "NONE"}; | |
567 | if (!wpa_dbus_dict_append_string_array( | |
568 | &iter_dict, "pairwise", args, | |
569 | sizeof(args) / sizeof(char*))) | |
570 | goto error; | |
571 | } | |
572 | } else { | |
573 | if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise", | |
574 | &iter_dict_entry, | |
575 | &iter_dict_val, | |
576 | &iter_array)) | |
577 | goto error; | |
578 | ||
579 | if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { | |
580 | if (!wpa_dbus_dict_string_array_add_element( | |
581 | &iter_array, "CCMP")) | |
582 | goto error; | |
583 | } | |
584 | ||
585 | if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { | |
586 | if (!wpa_dbus_dict_string_array_add_element( | |
587 | &iter_array, "TKIP")) | |
588 | goto error; | |
589 | } | |
590 | ||
591 | if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { | |
592 | if (!wpa_dbus_dict_string_array_add_element( | |
593 | &iter_array, "NONE")) | |
594 | goto error; | |
595 | } | |
596 | ||
597 | if (!wpa_dbus_dict_end_string_array(&iter_dict, | |
598 | &iter_dict_entry, | |
599 | &iter_dict_val, | |
600 | &iter_array)) | |
601 | goto error; | |
602 | } | |
603 | ||
604 | /***** group cipher */ | |
605 | if (res < 0) { | |
606 | if (!strict) { | |
607 | const char *args[] = { | |
608 | "CCMP", "TKIP", "WEP104", "WEP40" | |
609 | }; | |
610 | if (!wpa_dbus_dict_append_string_array( | |
611 | &iter_dict, "group", args, | |
612 | sizeof(args) / sizeof(char*))) | |
613 | goto error; | |
614 | } | |
615 | } else { | |
616 | if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group", | |
617 | &iter_dict_entry, | |
618 | &iter_dict_val, | |
619 | &iter_array)) | |
620 | goto error; | |
621 | ||
622 | if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { | |
623 | if (!wpa_dbus_dict_string_array_add_element( | |
624 | &iter_array, "CCMP")) | |
625 | goto error; | |
626 | } | |
627 | ||
628 | if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { | |
629 | if (!wpa_dbus_dict_string_array_add_element( | |
630 | &iter_array, "TKIP")) | |
631 | goto error; | |
632 | } | |
633 | ||
634 | if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { | |
635 | if (!wpa_dbus_dict_string_array_add_element( | |
636 | &iter_array, "WEP104")) | |
637 | goto error; | |
638 | } | |
639 | ||
640 | if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { | |
641 | if (!wpa_dbus_dict_string_array_add_element( | |
642 | &iter_array, "WEP40")) | |
643 | goto error; | |
644 | } | |
645 | ||
646 | if (!wpa_dbus_dict_end_string_array(&iter_dict, | |
647 | &iter_dict_entry, | |
648 | &iter_dict_val, | |
649 | &iter_array)) | |
650 | goto error; | |
651 | } | |
652 | ||
653 | /***** key management */ | |
654 | if (res < 0) { | |
655 | if (!strict) { | |
656 | const char *args[] = { | |
657 | "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE", | |
658 | "NONE" | |
659 | }; | |
660 | if (!wpa_dbus_dict_append_string_array( | |
661 | &iter_dict, "key_mgmt", args, | |
662 | sizeof(args) / sizeof(char*))) | |
663 | goto error; | |
664 | } | |
665 | } else { | |
666 | if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt", | |
667 | &iter_dict_entry, | |
668 | &iter_dict_val, | |
669 | &iter_array)) | |
670 | goto error; | |
671 | ||
672 | if (!wpa_dbus_dict_string_array_add_element(&iter_array, | |
673 | "NONE")) | |
674 | goto error; | |
675 | ||
676 | if (!wpa_dbus_dict_string_array_add_element(&iter_array, | |
677 | "IEEE8021X")) | |
678 | goto error; | |
679 | ||
680 | if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | | |
681 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { | |
682 | if (!wpa_dbus_dict_string_array_add_element( | |
683 | &iter_array, "WPA-EAP")) | |
684 | goto error; | |
685 | } | |
686 | ||
687 | if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | | |
688 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { | |
689 | if (!wpa_dbus_dict_string_array_add_element( | |
690 | &iter_array, "WPA-PSK")) | |
691 | goto error; | |
692 | } | |
693 | ||
694 | if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { | |
695 | if (!wpa_dbus_dict_string_array_add_element( | |
696 | &iter_array, "WPA-NONE")) | |
697 | goto error; | |
698 | } | |
699 | ||
700 | if (!wpa_dbus_dict_end_string_array(&iter_dict, | |
701 | &iter_dict_entry, | |
702 | &iter_dict_val, | |
703 | &iter_array)) | |
704 | goto error; | |
705 | } | |
706 | ||
707 | /***** WPA protocol */ | |
708 | if (res < 0) { | |
709 | if (!strict) { | |
710 | const char *args[] = { "RSN", "WPA" }; | |
711 | if (!wpa_dbus_dict_append_string_array( | |
712 | &iter_dict, "proto", args, | |
713 | sizeof(args) / sizeof(char*))) | |
714 | goto error; | |
715 | } | |
716 | } else { | |
717 | if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto", | |
718 | &iter_dict_entry, | |
719 | &iter_dict_val, | |
720 | &iter_array)) | |
721 | goto error; | |
722 | ||
723 | if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | | |
724 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { | |
725 | if (!wpa_dbus_dict_string_array_add_element( | |
726 | &iter_array, "RSN")) | |
727 | goto error; | |
728 | } | |
729 | ||
730 | if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | | |
731 | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { | |
732 | if (!wpa_dbus_dict_string_array_add_element( | |
733 | &iter_array, "WPA")) | |
734 | goto error; | |
735 | } | |
736 | ||
737 | if (!wpa_dbus_dict_end_string_array(&iter_dict, | |
738 | &iter_dict_entry, | |
739 | &iter_dict_val, | |
740 | &iter_array)) | |
741 | goto error; | |
742 | } | |
743 | ||
744 | /***** auth alg */ | |
745 | if (res < 0) { | |
746 | if (!strict) { | |
747 | const char *args[] = { "OPEN", "SHARED", "LEAP" }; | |
748 | if (!wpa_dbus_dict_append_string_array( | |
749 | &iter_dict, "auth_alg", args, | |
750 | sizeof(args) / sizeof(char*))) | |
751 | goto error; | |
752 | } | |
753 | } else { | |
754 | if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg", | |
755 | &iter_dict_entry, | |
756 | &iter_dict_val, | |
757 | &iter_array)) | |
758 | goto error; | |
759 | ||
760 | if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { | |
761 | if (!wpa_dbus_dict_string_array_add_element( | |
762 | &iter_array, "OPEN")) | |
763 | goto error; | |
764 | } | |
765 | ||
766 | if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { | |
767 | if (!wpa_dbus_dict_string_array_add_element( | |
768 | &iter_array, "SHARED")) | |
769 | goto error; | |
770 | } | |
771 | ||
772 | if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { | |
773 | if (!wpa_dbus_dict_string_array_add_element( | |
774 | &iter_array, "LEAP")) | |
775 | goto error; | |
776 | } | |
777 | ||
778 | if (!wpa_dbus_dict_end_string_array(&iter_dict, | |
779 | &iter_dict_entry, | |
780 | &iter_dict_val, | |
781 | &iter_array)) | |
782 | goto error; | |
783 | } | |
784 | ||
785 | if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) | |
786 | goto error; | |
787 | ||
788 | return reply; | |
789 | ||
790 | error: | |
791 | if (reply) | |
792 | dbus_message_unref(reply); | |
793 | return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, | |
794 | "an internal error occurred returning " | |
795 | "interface capabilities."); | |
796 | } | |
797 | ||
798 | ||
799 | /** | |
800 | * wpas_dbus_iface_add_network - Add a new configured network | |
801 | * @message: Pointer to incoming dbus message | |
802 | * @wpa_s: wpa_supplicant structure for a network interface | |
803 | * Returns: A dbus message containing the object path of the new network | |
804 | * | |
805 | * Handler function for "addNetwork" method call of a network interface. | |
806 | */ | |
807 | DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, | |
808 | struct wpa_supplicant *wpa_s) | |
809 | { | |
810 | DBusMessage *reply = NULL; | |
811 | struct wpa_ssid *ssid; | |
812 | char *path = NULL; | |
813 | ||
814 | path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); | |
815 | if (path == NULL) { | |
816 | perror("wpas_dbus_iface_scan_results[dbus]: out of " | |
817 | "memory."); | |
818 | wpa_printf(MSG_ERROR, "dbus control interface: not " | |
819 | "enough memory to send scan results " | |
820 | "signal."); | |
821 | goto out; | |
822 | } | |
823 | ||
824 | ssid = wpa_config_add_network(wpa_s->conf); | |
825 | if (ssid == NULL) { | |
826 | reply = dbus_message_new_error(message, | |
827 | WPAS_ERROR_ADD_NETWORK_ERROR, | |
828 | "wpa_supplicant could not add " | |
829 | "a network on this interface."); | |
830 | goto out; | |
831 | } | |
8bac466b | 832 | wpas_notify_network_added(wpa_s, ssid); |
6fc6879b JM |
833 | ssid->disabled = 1; |
834 | wpa_config_set_network_defaults(ssid); | |
835 | ||
836 | /* Construct the object path for this network. */ | |
8fc2fb56 WS |
837 | os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, |
838 | "%s/" WPAS_DBUS_NETWORKS_PART "/%d", | |
839 | wpa_supplicant_get_dbus_path(wpa_s), | |
840 | ssid->id); | |
6fc6879b JM |
841 | |
842 | reply = dbus_message_new_method_return(message); | |
843 | dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, | |
844 | &path, DBUS_TYPE_INVALID); | |
845 | ||
846 | out: | |
8fc2fb56 | 847 | os_free(path); |
6fc6879b JM |
848 | return reply; |
849 | } | |
850 | ||
851 | ||
852 | /** | |
853 | * wpas_dbus_iface_remove_network - Remove a configured network | |
854 | * @message: Pointer to incoming dbus message | |
855 | * @wpa_s: wpa_supplicant structure for a network interface | |
856 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
857 | * failure (0) | |
858 | * | |
859 | * Handler function for "removeNetwork" method call of a network interface. | |
860 | */ | |
861 | DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, | |
862 | struct wpa_supplicant *wpa_s) | |
863 | { | |
864 | DBusMessage *reply = NULL; | |
865 | const char *op; | |
866 | char *iface = NULL, *net_id = NULL; | |
867 | int id; | |
868 | struct wpa_ssid *ssid; | |
869 | ||
870 | if (!dbus_message_get_args(message, NULL, | |
871 | DBUS_TYPE_OBJECT_PATH, &op, | |
872 | DBUS_TYPE_INVALID)) { | |
873 | reply = wpas_dbus_new_invalid_opts_error(message, NULL); | |
874 | goto out; | |
875 | } | |
876 | ||
877 | /* Extract the network ID */ | |
878 | iface = wpas_dbus_decompose_object_path(op, &net_id, NULL); | |
879 | if (iface == NULL) { | |
880 | reply = wpas_dbus_new_invalid_network_error(message); | |
881 | goto out; | |
882 | } | |
8fc2fb56 | 883 | |
6fc6879b JM |
884 | /* Ensure the network is actually a child of this interface */ |
885 | if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) { | |
886 | reply = wpas_dbus_new_invalid_network_error(message); | |
887 | goto out; | |
888 | } | |
889 | ||
890 | id = strtoul(net_id, NULL, 10); | |
891 | ssid = wpa_config_get_network(wpa_s->conf, id); | |
892 | if (ssid == NULL) { | |
893 | reply = wpas_dbus_new_invalid_network_error(message); | |
894 | goto out; | |
895 | } | |
896 | ||
8bac466b JM |
897 | wpas_notify_network_removed(wpa_s, ssid); |
898 | ||
6fc6879b JM |
899 | if (wpa_config_remove_network(wpa_s->conf, id) < 0) { |
900 | reply = dbus_message_new_error(message, | |
901 | WPAS_ERROR_REMOVE_NETWORK_ERROR, | |
902 | "error removing the specified " | |
903 | "on this interface."); | |
904 | goto out; | |
905 | } | |
906 | ||
907 | if (ssid == wpa_s->current_ssid) | |
908 | wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); | |
909 | reply = wpas_dbus_new_success_reply(message); | |
910 | ||
911 | out: | |
8fc2fb56 WS |
912 | os_free(iface); |
913 | os_free(net_id); | |
6fc6879b JM |
914 | return reply; |
915 | } | |
916 | ||
917 | ||
918 | static const char *dont_quote[] = { | |
919 | "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", | |
920 | "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", | |
921 | "bssid", NULL | |
922 | }; | |
923 | ||
8fc2fb56 | 924 | |
6fc6879b JM |
925 | static dbus_bool_t should_quote_opt(const char *key) |
926 | { | |
927 | int i = 0; | |
928 | while (dont_quote[i] != NULL) { | |
929 | if (strcmp(key, dont_quote[i]) == 0) | |
930 | return FALSE; | |
931 | i++; | |
932 | } | |
933 | return TRUE; | |
934 | } | |
935 | ||
8fc2fb56 | 936 | |
6fc6879b JM |
937 | /** |
938 | * wpas_dbus_iface_set_network - Set options for a configured network | |
939 | * @message: Pointer to incoming dbus message | |
940 | * @wpa_s: wpa_supplicant structure for a network interface | |
941 | * @ssid: wpa_ssid structure for a configured network | |
942 | * Returns: a dbus message containing a UINT32 indicating success (1) or | |
943 | * failure (0) | |
944 | * | |
945 | * Handler function for "set" method call of a configured network. | |
946 | */ | |
947 | DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, | |
948 | struct wpa_supplicant *wpa_s, | |
949 | struct wpa_ssid *ssid) | |
950 | { | |
951 | DBusMessage *reply = NULL; | |
952 | struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; | |
953 | DBusMessageIter iter, iter_dict; | |
954 | ||
955 | dbus_message_iter_init(message, &iter); | |
956 | ||
957 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) { | |
958 | reply = wpas_dbus_new_invalid_opts_error(message, NULL); | |
959 | goto out; | |
960 | } | |
961 | ||
962 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
963 | char *value = NULL; | |
964 | size_t size = 50; | |
965 | int ret; | |
966 | ||
967 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { | |
968 | reply = wpas_dbus_new_invalid_opts_error(message, | |
969 | NULL); | |
970 | goto out; | |
971 | } | |
972 | ||
973 | /* Type conversions, since wpa_supplicant wants strings */ | |
974 | if (entry.type == DBUS_TYPE_ARRAY && | |
975 | entry.array_type == DBUS_TYPE_BYTE) { | |
976 | if (entry.array_len <= 0) | |
977 | goto error; | |
978 | ||
979 | size = entry.array_len * 2 + 1; | |
980 | value = os_zalloc(size); | |
981 | if (value == NULL) | |
982 | goto error; | |
983 | ret = wpa_snprintf_hex(value, size, | |
8fc2fb56 WS |
984 | (u8 *) entry.bytearray_value, |
985 | entry.array_len); | |
6fc6879b JM |
986 | if (ret <= 0) |
987 | goto error; | |
988 | } else if (entry.type == DBUS_TYPE_STRING) { | |
989 | if (should_quote_opt(entry.key)) { | |
8fc2fb56 | 990 | size = os_strlen(entry.str_value); |
6fc6879b JM |
991 | /* Zero-length option check */ |
992 | if (size <= 0) | |
993 | goto error; | |
994 | size += 3; /* For quotes and terminator */ | |
995 | value = os_zalloc(size); | |
996 | if (value == NULL) | |
997 | goto error; | |
8fc2fb56 WS |
998 | ret = os_snprintf(value, size, "\"%s\"", |
999 | entry.str_value); | |
6fc6879b JM |
1000 | if (ret < 0 || (size_t) ret != (size - 1)) |
1001 | goto error; | |
1002 | } else { | |
8fc2fb56 | 1003 | value = os_strdup(entry.str_value); |
6fc6879b JM |
1004 | if (value == NULL) |
1005 | goto error; | |
1006 | } | |
1007 | } else if (entry.type == DBUS_TYPE_UINT32) { | |
1008 | value = os_zalloc(size); | |
1009 | if (value == NULL) | |
1010 | goto error; | |
8fc2fb56 WS |
1011 | ret = os_snprintf(value, size, "%u", |
1012 | entry.uint32_value); | |
6fc6879b JM |
1013 | if (ret <= 0) |
1014 | goto error; | |
1015 | } else if (entry.type == DBUS_TYPE_INT32) { | |
1016 | value = os_zalloc(size); | |
1017 | if (value == NULL) | |
1018 | goto error; | |
8fc2fb56 WS |
1019 | ret = os_snprintf(value, size, "%d", |
1020 | entry.int32_value); | |
6fc6879b JM |
1021 | if (ret <= 0) |
1022 | goto error; | |
1023 | } else | |
1024 | goto error; | |
1025 | ||
1026 | if (wpa_config_set(ssid, entry.key, value, 0) < 0) | |
1027 | goto error; | |
1028 | ||
8fc2fb56 | 1029 | if ((os_strcmp(entry.key, "psk") == 0 && |
6fc6879b | 1030 | value[0] == '"' && ssid->ssid_len) || |
8fc2fb56 | 1031 | (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) |
6fc6879b JM |
1032 | wpa_config_update_psk(ssid); |
1033 | ||
8fc2fb56 | 1034 | os_free(value); |
6fc6879b JM |
1035 | wpa_dbus_dict_entry_clear(&entry); |
1036 | continue; | |
1037 | ||
1038 | error: | |
8fc2fb56 | 1039 | os_free(value); |
6fc6879b JM |
1040 | reply = wpas_dbus_new_invalid_opts_error(message, entry.key); |
1041 | wpa_dbus_dict_entry_clear(&entry); | |
1042 | break; | |
1043 | } | |
1044 | ||
1045 | if (!reply) | |
1046 | reply = wpas_dbus_new_success_reply(message); | |
1047 | ||
1048 | out: | |
1049 | return reply; | |
1050 | } | |
1051 | ||
1052 | ||
1053 | /** | |
1054 | * wpas_dbus_iface_enable_network - Mark a configured network as enabled | |
1055 | * @message: Pointer to incoming dbus message | |
1056 | * @wpa_s: wpa_supplicant structure for a network interface | |
1057 | * @ssid: wpa_ssid structure for a configured network | |
1058 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1059 | * failure (0) | |
1060 | * | |
1061 | * Handler function for "enable" method call of a configured network. | |
1062 | */ | |
1063 | DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, | |
1064 | struct wpa_supplicant *wpa_s, | |
1065 | struct wpa_ssid *ssid) | |
1066 | { | |
86b89452 | 1067 | wpa_supplicant_enable_network(wpa_s, ssid); |
6fc6879b JM |
1068 | return wpas_dbus_new_success_reply(message); |
1069 | } | |
1070 | ||
1071 | ||
1072 | /** | |
1073 | * wpas_dbus_iface_disable_network - Mark a configured network as disabled | |
1074 | * @message: Pointer to incoming dbus message | |
1075 | * @wpa_s: wpa_supplicant structure for a network interface | |
1076 | * @ssid: wpa_ssid structure for a configured network | |
1077 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1078 | * failure (0) | |
1079 | * | |
1080 | * Handler function for "disable" method call of a configured network. | |
1081 | */ | |
1082 | DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, | |
1083 | struct wpa_supplicant *wpa_s, | |
1084 | struct wpa_ssid *ssid) | |
1085 | { | |
86b89452 | 1086 | wpa_supplicant_disable_network(wpa_s, ssid); |
6fc6879b JM |
1087 | return wpas_dbus_new_success_reply(message); |
1088 | } | |
1089 | ||
1090 | ||
1091 | /** | |
1092 | * wpas_dbus_iface_select_network - Attempt association with a configured network | |
1093 | * @message: Pointer to incoming dbus message | |
1094 | * @wpa_s: wpa_supplicant structure for a network interface | |
1095 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1096 | * failure (0) | |
1097 | * | |
1098 | * Handler function for "selectNetwork" method call of network interface. | |
1099 | */ | |
1100 | DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, | |
1101 | struct wpa_supplicant *wpa_s) | |
1102 | { | |
1103 | DBusMessage *reply = NULL; | |
1104 | const char *op; | |
1105 | struct wpa_ssid *ssid; | |
1106 | char *iface_obj_path = NULL; | |
1107 | char *network = NULL; | |
1108 | ||
8fc2fb56 | 1109 | if (os_strlen(dbus_message_get_signature(message)) == 0) { |
6fc6879b | 1110 | /* Any network */ |
86b89452 | 1111 | ssid = NULL; |
6fc6879b JM |
1112 | } else { |
1113 | const char *obj_path; | |
1114 | int nid; | |
1115 | ||
1116 | if (!dbus_message_get_args(message, NULL, | |
1117 | DBUS_TYPE_OBJECT_PATH, &op, | |
1118 | DBUS_TYPE_INVALID)) { | |
1119 | reply = wpas_dbus_new_invalid_opts_error(message, | |
1120 | NULL); | |
1121 | goto out; | |
1122 | } | |
1123 | ||
1124 | /* Extract the network number */ | |
1125 | iface_obj_path = wpas_dbus_decompose_object_path(op, | |
1126 | &network, | |
1127 | NULL); | |
1128 | if (iface_obj_path == NULL) { | |
1129 | reply = wpas_dbus_new_invalid_iface_error(message); | |
1130 | goto out; | |
1131 | } | |
1132 | /* Ensure the object path really points to this interface */ | |
1133 | obj_path = wpa_supplicant_get_dbus_path(wpa_s); | |
8fc2fb56 | 1134 | if (os_strcmp(iface_obj_path, obj_path) != 0) { |
6fc6879b JM |
1135 | reply = wpas_dbus_new_invalid_network_error(message); |
1136 | goto out; | |
1137 | } | |
1138 | ||
1139 | nid = strtoul(network, NULL, 10); | |
1140 | if (errno == EINVAL) { | |
1141 | reply = wpas_dbus_new_invalid_network_error(message); | |
1142 | goto out; | |
1143 | } | |
1144 | ||
1145 | ssid = wpa_config_get_network(wpa_s->conf, nid); | |
1146 | if (ssid == NULL) { | |
1147 | reply = wpas_dbus_new_invalid_network_error(message); | |
1148 | goto out; | |
1149 | } | |
6fc6879b JM |
1150 | } |
1151 | ||
86b89452 WS |
1152 | /* Finally, associate with the network */ |
1153 | wpa_supplicant_select_network(wpa_s, ssid); | |
1154 | ||
6fc6879b JM |
1155 | reply = wpas_dbus_new_success_reply(message); |
1156 | ||
1157 | out: | |
8fc2fb56 WS |
1158 | os_free(iface_obj_path); |
1159 | os_free(network); | |
6fc6879b JM |
1160 | return reply; |
1161 | } | |
1162 | ||
1163 | ||
1164 | /** | |
1165 | * wpas_dbus_iface_disconnect - Terminate the current connection | |
1166 | * @message: Pointer to incoming dbus message | |
1167 | * @wpa_s: wpa_supplicant structure for a network interface | |
1168 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1169 | * failure (0) | |
1170 | * | |
1171 | * Handler function for "disconnect" method call of network interface. | |
1172 | */ | |
1173 | DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, | |
1174 | struct wpa_supplicant *wpa_s) | |
1175 | { | |
1176 | wpa_s->disconnected = 1; | |
1177 | wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); | |
1178 | ||
1179 | return wpas_dbus_new_success_reply(message); | |
1180 | } | |
1181 | ||
1182 | ||
1183 | /** | |
1184 | * wpas_dbus_iface_set_ap_scan - Control roaming mode | |
1185 | * @message: Pointer to incoming dbus message | |
1186 | * @wpa_s: wpa_supplicant structure for a network interface | |
1187 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1188 | * failure (0) | |
1189 | * | |
1190 | * Handler function for "setAPScan" method call. | |
1191 | */ | |
1192 | DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, | |
1193 | struct wpa_supplicant *wpa_s) | |
1194 | { | |
1195 | DBusMessage *reply = NULL; | |
1196 | dbus_uint32_t ap_scan = 1; | |
1197 | ||
1198 | if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan, | |
1199 | DBUS_TYPE_INVALID)) { | |
1200 | reply = wpas_dbus_new_invalid_opts_error(message, NULL); | |
1201 | goto out; | |
1202 | } | |
1203 | ||
86b89452 | 1204 | if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { |
6fc6879b JM |
1205 | reply = wpas_dbus_new_invalid_opts_error(message, NULL); |
1206 | goto out; | |
1207 | } | |
86b89452 | 1208 | |
6fc6879b JM |
1209 | reply = wpas_dbus_new_success_reply(message); |
1210 | ||
1211 | out: | |
1212 | return reply; | |
1213 | } | |
1214 | ||
1215 | ||
e403be0b DS |
1216 | /** |
1217 | * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths | |
1218 | * @message: Pointer to incoming dbus message | |
1219 | * @wpa_s: wpa_supplicant structure for a network interface | |
1220 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1221 | * failure (0) | |
1222 | * | |
1223 | * Handler function for "setSmartcardModules" method call. | |
1224 | */ | |
1225 | DBusMessage * wpas_dbus_iface_set_smartcard_modules( | |
1226 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
1227 | { | |
1228 | DBusMessageIter iter, iter_dict; | |
1229 | char *opensc_engine_path = NULL; | |
1230 | char *pkcs11_engine_path = NULL; | |
1231 | char *pkcs11_module_path = NULL; | |
1232 | struct wpa_dbus_dict_entry entry; | |
1233 | ||
1234 | if (!dbus_message_iter_init(message, &iter)) | |
1235 | goto error; | |
1236 | ||
1237 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) | |
1238 | goto error; | |
1239 | ||
1240 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
1241 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
1242 | goto error; | |
1243 | if (!strcmp(entry.key, "opensc_engine_path") && | |
1244 | (entry.type == DBUS_TYPE_STRING)) { | |
1245 | opensc_engine_path = os_strdup(entry.str_value); | |
1246 | if (opensc_engine_path == NULL) | |
1247 | goto error; | |
1248 | } else if (!strcmp(entry.key, "pkcs11_engine_path") && | |
1249 | (entry.type == DBUS_TYPE_STRING)) { | |
1250 | pkcs11_engine_path = os_strdup(entry.str_value); | |
1251 | if (pkcs11_engine_path == NULL) | |
1252 | goto error; | |
1253 | } else if (!strcmp(entry.key, "pkcs11_module_path") && | |
1254 | (entry.type == DBUS_TYPE_STRING)) { | |
1255 | pkcs11_module_path = os_strdup(entry.str_value); | |
1256 | if (pkcs11_module_path == NULL) | |
1257 | goto error; | |
1258 | } else { | |
1259 | wpa_dbus_dict_entry_clear(&entry); | |
1260 | goto error; | |
1261 | } | |
1262 | wpa_dbus_dict_entry_clear(&entry); | |
1263 | } | |
1264 | ||
b5aebee4 | 1265 | #ifdef EAP_TLS_OPENSSL |
e403be0b DS |
1266 | os_free(wpa_s->conf->opensc_engine_path); |
1267 | wpa_s->conf->opensc_engine_path = opensc_engine_path; | |
1268 | os_free(wpa_s->conf->pkcs11_engine_path); | |
1269 | wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path; | |
1270 | os_free(wpa_s->conf->pkcs11_module_path); | |
1271 | wpa_s->conf->pkcs11_module_path = pkcs11_module_path; | |
b5aebee4 | 1272 | #endif /* EAP_TLS_OPENSSL */ |
e403be0b | 1273 | |
d7199342 | 1274 | wpa_sm_set_eapol(wpa_s->wpa, NULL); |
e403be0b | 1275 | eapol_sm_deinit(wpa_s->eapol); |
d7199342 | 1276 | wpa_s->eapol = NULL; |
e403be0b | 1277 | wpa_supplicant_init_eapol(wpa_s); |
d7199342 | 1278 | wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); |
e403be0b DS |
1279 | |
1280 | return wpas_dbus_new_success_reply(message); | |
1281 | ||
1282 | error: | |
1283 | os_free(opensc_engine_path); | |
1284 | os_free(pkcs11_engine_path); | |
1285 | os_free(pkcs11_module_path); | |
1286 | return wpas_dbus_new_invalid_opts_error(message, NULL); | |
1287 | } | |
1288 | ||
8fc2fb56 | 1289 | |
6fc6879b JM |
1290 | /** |
1291 | * wpas_dbus_iface_get_state - Get interface state | |
1292 | * @message: Pointer to incoming dbus message | |
1293 | * @wpa_s: wpa_supplicant structure for a network interface | |
1294 | * Returns: A dbus message containing a STRING representing the current | |
1295 | * interface state | |
1296 | * | |
1297 | * Handler function for "state" method call. | |
1298 | */ | |
1299 | DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, | |
1300 | struct wpa_supplicant *wpa_s) | |
1301 | { | |
1302 | DBusMessage *reply = NULL; | |
1303 | const char *str_state; | |
1304 | ||
1305 | reply = dbus_message_new_method_return(message); | |
1306 | if (reply != NULL) { | |
1307 | str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); | |
1308 | dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state, | |
1309 | DBUS_TYPE_INVALID); | |
1310 | } | |
1311 | ||
1312 | return reply; | |
1313 | } | |
1314 | ||
1315 | ||
cb8564b1 DW |
1316 | /** |
1317 | * wpas_dbus_iface_get_scanning - Get interface scanning state | |
1318 | * @message: Pointer to incoming dbus message | |
1319 | * @wpa_s: wpa_supplicant structure for a network interface | |
1320 | * Returns: A dbus message containing whether the interface is scanning | |
1321 | * | |
1322 | * Handler function for "scanning" method call. | |
1323 | */ | |
1324 | DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message, | |
1325 | struct wpa_supplicant *wpa_s) | |
1326 | { | |
1327 | DBusMessage *reply = NULL; | |
1328 | dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; | |
1329 | ||
1330 | reply = dbus_message_new_method_return(message); | |
1331 | if (reply != NULL) { | |
1332 | dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning, | |
1333 | DBUS_TYPE_INVALID); | |
1334 | } else { | |
1335 | perror("wpas_dbus_iface_get_scanning[dbus]: out of " | |
1336 | "memory."); | |
1337 | wpa_printf(MSG_ERROR, "dbus control interface: not enough " | |
1338 | "memory to return scanning state."); | |
1339 | } | |
1340 | ||
1341 | return reply; | |
1342 | } | |
1343 | ||
1344 | ||
6fc6879b JM |
1345 | /** |
1346 | * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates) | |
1347 | * @message: Pointer to incoming dbus message | |
a17df5fb | 1348 | * @wpa_s: %wpa_supplicant data structure |
6fc6879b JM |
1349 | * Returns: A dbus message containing a UINT32 indicating success (1) or |
1350 | * failure (0) | |
1351 | * | |
1352 | * Asks wpa_supplicant to internally store a one or more binary blobs. | |
1353 | */ | |
1354 | DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, | |
1355 | struct wpa_supplicant *wpa_s) | |
1356 | { | |
1357 | DBusMessage *reply = NULL; | |
1358 | struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; | |
1359 | DBusMessageIter iter, iter_dict; | |
1360 | ||
1361 | dbus_message_iter_init(message, &iter); | |
1362 | ||
1363 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) | |
1364 | return wpas_dbus_new_invalid_opts_error(message, NULL); | |
1365 | ||
1366 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
1367 | struct wpa_config_blob *blob; | |
1368 | ||
1369 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { | |
1370 | reply = wpas_dbus_new_invalid_opts_error(message, | |
1371 | NULL); | |
1372 | break; | |
1373 | } | |
1374 | ||
1375 | if (entry.type != DBUS_TYPE_ARRAY || | |
1376 | entry.array_type != DBUS_TYPE_BYTE) { | |
1377 | reply = wpas_dbus_new_invalid_opts_error( | |
1378 | message, "Byte array expected."); | |
1379 | break; | |
1380 | } | |
1381 | ||
1382 | if ((entry.array_len <= 0) || (entry.array_len > 65536) || | |
1383 | !strlen(entry.key)) { | |
1384 | reply = wpas_dbus_new_invalid_opts_error( | |
1385 | message, "Invalid array size."); | |
1386 | break; | |
1387 | } | |
1388 | ||
1389 | blob = os_zalloc(sizeof(*blob)); | |
1390 | if (blob == NULL) { | |
1391 | reply = dbus_message_new_error( | |
1392 | message, WPAS_ERROR_ADD_ERROR, | |
1393 | "Not enough memory to add blob."); | |
1394 | break; | |
1395 | } | |
1396 | blob->data = os_zalloc(entry.array_len); | |
1397 | if (blob->data == NULL) { | |
1398 | reply = dbus_message_new_error( | |
1399 | message, WPAS_ERROR_ADD_ERROR, | |
1400 | "Not enough memory to add blob data."); | |
1401 | os_free(blob); | |
1402 | break; | |
1403 | } | |
1404 | ||
1405 | blob->name = os_strdup(entry.key); | |
1406 | blob->len = entry.array_len; | |
1407 | os_memcpy(blob->data, (u8 *) entry.bytearray_value, | |
1408 | entry.array_len); | |
1409 | if (blob->name == NULL || blob->data == NULL) { | |
1410 | wpa_config_free_blob(blob); | |
1411 | reply = dbus_message_new_error( | |
1412 | message, WPAS_ERROR_ADD_ERROR, | |
1413 | "Error adding blob."); | |
1414 | break; | |
1415 | } | |
1416 | ||
1417 | /* Success */ | |
8bac466b JM |
1418 | if (!wpa_config_remove_blob(wpa_s->conf, blob->name)) |
1419 | wpas_notify_blob_removed(wpa_s, blob->name); | |
6fc6879b | 1420 | wpa_config_set_blob(wpa_s->conf, blob); |
8bac466b JM |
1421 | wpas_notify_blob_added(wpa_s, blob->name); |
1422 | ||
6fc6879b JM |
1423 | wpa_dbus_dict_entry_clear(&entry); |
1424 | } | |
1425 | wpa_dbus_dict_entry_clear(&entry); | |
1426 | ||
1427 | return reply ? reply : wpas_dbus_new_success_reply(message); | |
1428 | } | |
1429 | ||
1430 | ||
1431 | /** | |
1432 | * wpas_dbus_iface_remove_blob - Remove named binary blobs | |
1433 | * @message: Pointer to incoming dbus message | |
a17df5fb | 1434 | * @wpa_s: %wpa_supplicant data structure |
6fc6879b JM |
1435 | * Returns: A dbus message containing a UINT32 indicating success (1) or |
1436 | * failure (0) | |
1437 | * | |
1438 | * Asks wpa_supplicant to remove one or more previously stored binary blobs. | |
1439 | */ | |
1440 | DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, | |
8fc2fb56 | 1441 | struct wpa_supplicant *wpa_s) |
6fc6879b JM |
1442 | { |
1443 | DBusMessageIter iter, array; | |
1444 | char *err_msg = NULL; | |
1445 | ||
1446 | dbus_message_iter_init(message, &iter); | |
1447 | ||
1448 | if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) || | |
1449 | (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING)) | |
1450 | return wpas_dbus_new_invalid_opts_error(message, NULL); | |
1451 | ||
1452 | dbus_message_iter_recurse(&iter, &array); | |
1453 | while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { | |
1454 | const char *name; | |
1455 | ||
1456 | dbus_message_iter_get_basic(&array, &name); | |
8fc2fb56 | 1457 | if (!os_strlen(name)) |
6fc6879b JM |
1458 | err_msg = "Invalid blob name."; |
1459 | ||
1460 | if (wpa_config_remove_blob(wpa_s->conf, name) != 0) | |
1461 | err_msg = "Error removing blob."; | |
8bac466b JM |
1462 | else |
1463 | wpas_notify_blob_removed(wpa_s, name); | |
6fc6879b JM |
1464 | dbus_message_iter_next(&array); |
1465 | } | |
1466 | ||
8fc2fb56 | 1467 | if (err_msg) |
6fc6879b JM |
1468 | return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR, |
1469 | err_msg); | |
6fc6879b JM |
1470 | |
1471 | return wpas_dbus_new_success_reply(message); | |
1472 | } | |
e8fa6039 JSP |
1473 | |
1474 | ||
1475 | #ifdef CONFIG_WPS | |
1476 | ||
1477 | /** | |
1478 | * wpas_dbus_iface_wps_pbc - Request credentials using WPS PBC method | |
1479 | * @message: Pointer to incoming dbus message | |
1480 | * @wpa_s: %wpa_supplicant data structure | |
1481 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1482 | * failure (0) | |
1483 | * | |
1484 | * Handler function for "wpsPbc" method call | |
1485 | */ | |
1486 | DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message, | |
1487 | struct wpa_supplicant *wpa_s) | |
1488 | { | |
1489 | char *arg_bssid = NULL; | |
1490 | u8 bssid[ETH_ALEN]; | |
1491 | int ret = 0; | |
1492 | ||
1493 | if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, | |
1494 | DBUS_TYPE_INVALID)) | |
1495 | return wpas_dbus_new_invalid_opts_error(message, NULL); | |
1496 | ||
1497 | if (!os_strcmp(arg_bssid, "any")) | |
1498 | ret = wpas_wps_start_pbc(wpa_s, NULL); | |
1499 | else if (!hwaddr_aton(arg_bssid, bssid)) | |
1500 | ret = wpas_wps_start_pbc(wpa_s, bssid); | |
1501 | else { | |
1502 | return wpas_dbus_new_invalid_opts_error(message, | |
1503 | "Invalid BSSID"); | |
1504 | } | |
1505 | ||
1506 | if (ret < 0) { | |
1507 | return dbus_message_new_error(message, | |
1508 | WPAS_ERROR_WPS_PBC_ERROR, | |
1509 | "Could not start PBC " | |
1510 | "negotiation"); | |
1511 | } | |
1512 | ||
1513 | return wpas_dbus_new_success_reply(message); | |
1514 | } | |
1515 | ||
1516 | ||
1517 | /** | |
1518 | * wpas_dbus_iface_wps_pin - Establish the PIN number of the enrollee | |
1519 | * @message: Pointer to incoming dbus message | |
1520 | * @wpa_s: %wpa_supplicant data structure | |
1521 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1522 | * failure (0) | |
1523 | * | |
1524 | * Handler function for "wpsPin" method call | |
1525 | */ | |
1526 | DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message, | |
1527 | struct wpa_supplicant *wpa_s) | |
1528 | { | |
1529 | DBusMessage *reply = NULL; | |
1530 | char *arg_bssid; | |
1531 | char *pin = NULL; | |
1532 | u8 bssid[ETH_ALEN], *_bssid = NULL; | |
1533 | int ret = 0; | |
1534 | ||
1535 | if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, | |
1536 | DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) | |
1537 | return wpas_dbus_new_invalid_opts_error(message, NULL); | |
1538 | ||
1539 | if (!os_strcmp(arg_bssid, "any")) | |
1540 | _bssid = NULL; | |
1541 | else if (!hwaddr_aton(arg_bssid, bssid)) | |
1542 | _bssid = bssid; | |
1543 | else { | |
1544 | return wpas_dbus_new_invalid_opts_error(message, | |
1545 | "Invalid BSSID"); | |
1546 | } | |
1547 | ||
1548 | if (os_strlen(pin) > 0) | |
1549 | ret = wpas_wps_start_pin(wpa_s, _bssid, pin); | |
1550 | else | |
1551 | ret = wpas_wps_start_pin(wpa_s, _bssid, NULL); | |
1552 | ||
1553 | if (ret < 0) { | |
1554 | return dbus_message_new_error(message, | |
1555 | WPAS_ERROR_WPS_PIN_ERROR, | |
1556 | "Could not init PIN"); | |
1557 | } | |
1558 | ||
1559 | reply = dbus_message_new_method_return(message); | |
1560 | if (reply == NULL) | |
1561 | return NULL; | |
1562 | ||
1563 | if (ret == 0) { | |
1564 | dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin, | |
1565 | DBUS_TYPE_INVALID); | |
1566 | } else { | |
1567 | char npin[9]; | |
8fc2fb56 | 1568 | os_snprintf(npin, sizeof(npin), "%08d", ret); |
e8fa6039 JSP |
1569 | dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin, |
1570 | DBUS_TYPE_INVALID); | |
1571 | } | |
1572 | return reply; | |
1573 | } | |
1574 | ||
1575 | ||
1576 | /** | |
1577 | * wpas_dbus_iface_wps_reg - Request credentials using the PIN of the AP | |
1578 | * @message: Pointer to incoming dbus message | |
1579 | * @wpa_s: %wpa_supplicant data structure | |
1580 | * Returns: A dbus message containing a UINT32 indicating success (1) or | |
1581 | * failure (0) | |
1582 | * | |
1583 | * Handler function for "wpsReg" method call | |
1584 | */ | |
1585 | DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message, | |
1586 | struct wpa_supplicant *wpa_s) | |
1587 | { | |
1588 | char *arg_bssid; | |
1589 | char *pin = NULL; | |
1590 | u8 bssid[ETH_ALEN]; | |
1591 | int ret = 0; | |
1592 | ||
1593 | if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, | |
1594 | DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) | |
1595 | return wpas_dbus_new_invalid_opts_error(message, NULL); | |
1596 | ||
1597 | if (!os_strcmp(arg_bssid, "any")) | |
52eb293d | 1598 | ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL); |
e8fa6039 | 1599 | else if (!hwaddr_aton(arg_bssid, bssid)) |
52eb293d | 1600 | ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL); |
e8fa6039 JSP |
1601 | else { |
1602 | return wpas_dbus_new_invalid_opts_error(message, | |
1603 | "Invalid BSSID"); | |
1604 | } | |
1605 | ||
1606 | if (ret < 0) { | |
1607 | return dbus_message_new_error(message, | |
1608 | WPAS_ERROR_WPS_PBC_ERROR, | |
1609 | "Could not request credentials"); | |
1610 | } | |
1611 | ||
1612 | return wpas_dbus_new_success_reply(message); | |
1613 | } | |
1614 | ||
1615 | #endif /* CONFIG_WPS */ |