]>
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 "eloop.h" | |
19 | #include "config.h" | |
20 | #include "wpa_supplicant_i.h" | |
2d5b792d | 21 | #include "drivers/driver.h" |
47662164 | 22 | #include "wps/wps.h" |
6fc6879b JM |
23 | #include "ctrl_iface_dbus.h" |
24 | #include "ctrl_iface_dbus_handlers.h" | |
25 | ||
c673c5fc | 26 | #define _DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR) |
6fc6879b JM |
27 | #define DBUS_VER(major, minor) ((major) << 8 | (minor)) |
28 | ||
c673c5fc | 29 | #if _DBUS_VERSION < DBUS_VER(1,1) |
6fc6879b JM |
30 | #define dbus_watch_get_unix_fd dbus_watch_get_fd |
31 | #endif | |
32 | ||
33 | ||
34 | struct ctrl_iface_dbus_priv { | |
35 | DBusConnection *con; | |
36 | int should_dispatch; | |
37 | struct wpa_global *global; | |
38 | ||
39 | u32 next_objid; | |
40 | }; | |
41 | ||
42 | ||
43 | static void process_watch(struct ctrl_iface_dbus_priv *iface, | |
44 | DBusWatch *watch, eloop_event_type type) | |
45 | { | |
46 | dbus_connection_ref(iface->con); | |
47 | ||
48 | iface->should_dispatch = 0; | |
49 | ||
50 | if (type == EVENT_TYPE_READ) | |
51 | dbus_watch_handle(watch, DBUS_WATCH_READABLE); | |
52 | else if (type == EVENT_TYPE_WRITE) | |
53 | dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); | |
54 | else if (type == EVENT_TYPE_EXCEPTION) | |
55 | dbus_watch_handle(watch, DBUS_WATCH_ERROR); | |
56 | ||
57 | if (iface->should_dispatch) { | |
58 | while (dbus_connection_get_dispatch_status(iface->con) == | |
59 | DBUS_DISPATCH_DATA_REMAINS) | |
60 | dbus_connection_dispatch(iface->con); | |
61 | iface->should_dispatch = 0; | |
62 | } | |
63 | ||
64 | dbus_connection_unref(iface->con); | |
65 | } | |
66 | ||
67 | ||
68 | static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx) | |
69 | { | |
70 | process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION); | |
71 | } | |
72 | ||
73 | ||
74 | static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx) | |
75 | { | |
76 | process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ); | |
77 | } | |
78 | ||
79 | ||
80 | static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx) | |
81 | { | |
82 | process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE); | |
83 | } | |
84 | ||
85 | ||
86 | static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface, | |
87 | DBusWatch *watch) | |
88 | { | |
89 | unsigned int flags; | |
90 | int fd; | |
91 | ||
92 | if (!dbus_watch_get_enabled(watch)) | |
93 | return; | |
94 | ||
95 | flags = dbus_watch_get_flags(watch); | |
96 | fd = dbus_watch_get_unix_fd(watch); | |
97 | ||
98 | eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, | |
99 | iface, watch); | |
100 | ||
101 | if (flags & DBUS_WATCH_READABLE) { | |
102 | eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, | |
103 | iface, watch); | |
104 | } | |
105 | if (flags & DBUS_WATCH_WRITABLE) { | |
106 | eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, | |
107 | iface, watch); | |
108 | } | |
109 | ||
110 | dbus_watch_set_data(watch, iface, NULL); | |
111 | } | |
112 | ||
113 | ||
114 | static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface, | |
115 | DBusWatch *watch) | |
116 | { | |
117 | unsigned int flags; | |
118 | int fd; | |
119 | ||
120 | flags = dbus_watch_get_flags(watch); | |
121 | fd = dbus_watch_get_unix_fd(watch); | |
122 | ||
123 | eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); | |
124 | ||
125 | if (flags & DBUS_WATCH_READABLE) | |
126 | eloop_unregister_sock(fd, EVENT_TYPE_READ); | |
127 | if (flags & DBUS_WATCH_WRITABLE) | |
128 | eloop_unregister_sock(fd, EVENT_TYPE_WRITE); | |
129 | ||
130 | dbus_watch_set_data(watch, NULL, NULL); | |
131 | } | |
132 | ||
133 | ||
134 | static dbus_bool_t add_watch(DBusWatch *watch, void *data) | |
135 | { | |
136 | connection_setup_add_watch(data, watch); | |
137 | return TRUE; | |
138 | } | |
139 | ||
140 | ||
141 | static void remove_watch(DBusWatch *watch, void *data) | |
142 | { | |
143 | connection_setup_remove_watch(data, watch); | |
144 | } | |
145 | ||
146 | ||
147 | static void watch_toggled(DBusWatch *watch, void *data) | |
148 | { | |
149 | if (dbus_watch_get_enabled(watch)) | |
150 | add_watch(watch, data); | |
151 | else | |
152 | remove_watch(watch, data); | |
153 | } | |
154 | ||
155 | ||
156 | static void process_timeout(void *eloop_ctx, void *sock_ctx) | |
157 | { | |
158 | DBusTimeout *timeout = sock_ctx; | |
159 | ||
160 | dbus_timeout_handle(timeout); | |
161 | } | |
162 | ||
163 | ||
164 | static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface, | |
165 | DBusTimeout *timeout) | |
166 | { | |
167 | if (!dbus_timeout_get_enabled(timeout)) | |
168 | return; | |
169 | ||
170 | eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, | |
171 | process_timeout, iface, timeout); | |
172 | ||
173 | dbus_timeout_set_data(timeout, iface, NULL); | |
174 | } | |
175 | ||
176 | ||
177 | static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface, | |
178 | DBusTimeout *timeout) | |
179 | { | |
180 | eloop_cancel_timeout(process_timeout, iface, timeout); | |
181 | dbus_timeout_set_data(timeout, NULL, NULL); | |
182 | } | |
183 | ||
184 | ||
185 | static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) | |
186 | { | |
187 | if (!dbus_timeout_get_enabled(timeout)) | |
188 | return TRUE; | |
189 | ||
190 | connection_setup_add_timeout(data, timeout); | |
191 | ||
192 | return TRUE; | |
193 | } | |
194 | ||
195 | ||
196 | static void remove_timeout(DBusTimeout *timeout, void *data) | |
197 | { | |
198 | connection_setup_remove_timeout(data, timeout); | |
199 | } | |
200 | ||
201 | ||
202 | static void timeout_toggled(DBusTimeout *timeout, void *data) | |
203 | { | |
204 | if (dbus_timeout_get_enabled(timeout)) | |
205 | add_timeout(timeout, data); | |
206 | else | |
207 | remove_timeout(timeout, data); | |
208 | } | |
209 | ||
210 | ||
211 | static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx) | |
212 | { | |
213 | struct ctrl_iface_dbus_priv *iface = signal_ctx; | |
214 | ||
215 | if (sig != SIGPOLL || !iface->con) | |
216 | return; | |
217 | ||
218 | if (dbus_connection_get_dispatch_status(iface->con) != | |
219 | DBUS_DISPATCH_DATA_REMAINS) | |
220 | return; | |
221 | ||
222 | /* Only dispatch once - we do not want to starve other events */ | |
223 | dbus_connection_ref(iface->con); | |
224 | dbus_connection_dispatch(iface->con); | |
225 | dbus_connection_unref(iface->con); | |
226 | } | |
227 | ||
228 | ||
229 | /** | |
230 | * wakeup_main - Attempt to wake our mainloop up | |
231 | * @data: dbus control interface private data | |
232 | * | |
233 | * Try to wake up the main eloop so it will process | |
234 | * dbus events that may have happened. | |
235 | */ | |
236 | static void wakeup_main(void *data) | |
237 | { | |
238 | struct ctrl_iface_dbus_priv *iface = data; | |
239 | ||
240 | /* Use SIGPOLL to break out of the eloop select() */ | |
241 | raise(SIGPOLL); | |
242 | iface->should_dispatch = 1; | |
243 | } | |
244 | ||
245 | ||
246 | /** | |
247 | * connection_setup_wakeup_main - Tell dbus about our wakeup_main function | |
248 | * @iface: dbus control interface private data | |
249 | * Returns: 0 on success, -1 on failure | |
250 | * | |
251 | * Register our wakeup_main handler with dbus | |
252 | */ | |
253 | static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface) | |
254 | { | |
255 | if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface)) | |
256 | return -1; | |
257 | ||
258 | dbus_connection_set_wakeup_main_function(iface->con, wakeup_main, | |
259 | iface, NULL); | |
260 | ||
261 | return 0; | |
262 | } | |
263 | ||
264 | ||
265 | /** | |
266 | * wpa_supplicant_dbus_next_objid - Return next available object id | |
267 | * @iface: dbus control interface private data | |
268 | * Returns: Object id | |
269 | */ | |
270 | u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface) | |
271 | { | |
272 | return iface->next_objid++; | |
273 | } | |
274 | ||
275 | ||
276 | /** | |
277 | * wpas_dbus_decompose_object_path - Decompose an interface object path into parts | |
278 | * @path: The dbus object path | |
279 | * @network: (out) the configured network this object path refers to, if any | |
280 | * @bssid: (out) the scanned bssid this object path refers to, if any | |
281 | * Returns: The object path of the network interface this path refers to | |
282 | * | |
283 | * For a given object path, decomposes the object path into object id, network, | |
284 | * and BSSID parts, if those parts exist. | |
285 | */ | |
286 | char * wpas_dbus_decompose_object_path(const char *path, char **network, | |
287 | char **bssid) | |
288 | { | |
289 | const unsigned int dev_path_prefix_len = | |
290 | strlen(WPAS_DBUS_PATH_INTERFACES "/"); | |
291 | char *obj_path_only; | |
292 | char *next_sep; | |
293 | ||
294 | /* Be a bit paranoid about path */ | |
295 | if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", | |
296 | dev_path_prefix_len)) | |
297 | return NULL; | |
298 | ||
299 | /* Ensure there's something at the end of the path */ | |
300 | if ((path + dev_path_prefix_len)[0] == '\0') | |
301 | return NULL; | |
302 | ||
303 | obj_path_only = strdup(path); | |
304 | if (obj_path_only == NULL) | |
305 | return NULL; | |
306 | ||
307 | next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); | |
308 | if (next_sep != NULL) { | |
309 | const char *net_part = strstr(next_sep, | |
310 | WPAS_DBUS_NETWORKS_PART "/"); | |
311 | const char *bssid_part = strstr(next_sep, | |
312 | WPAS_DBUS_BSSIDS_PART "/"); | |
313 | ||
314 | if (network && net_part) { | |
315 | /* Deal with a request for a configured network */ | |
316 | const char *net_name = net_part + | |
317 | strlen(WPAS_DBUS_NETWORKS_PART "/"); | |
318 | *network = NULL; | |
319 | if (strlen(net_name)) | |
320 | *network = strdup(net_name); | |
321 | } else if (bssid && bssid_part) { | |
322 | /* Deal with a request for a scanned BSSID */ | |
323 | const char *bssid_name = bssid_part + | |
324 | strlen(WPAS_DBUS_BSSIDS_PART "/"); | |
325 | if (strlen(bssid_name)) | |
326 | *bssid = strdup(bssid_name); | |
327 | else | |
328 | *bssid = NULL; | |
329 | } | |
330 | ||
331 | /* Cut off interface object path before "/" */ | |
332 | *next_sep = '\0'; | |
333 | } | |
334 | ||
335 | return obj_path_only; | |
336 | } | |
337 | ||
338 | ||
339 | /** | |
340 | * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message | |
341 | * @message: Pointer to incoming dbus message this error refers to | |
342 | * Returns: A dbus error message | |
343 | * | |
344 | * Convenience function to create and return an invalid interface error | |
345 | */ | |
346 | DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) | |
347 | { | |
348 | return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, | |
349 | "wpa_supplicant knows nothing about " | |
350 | "this interface."); | |
351 | } | |
352 | ||
353 | ||
354 | /** | |
355 | * wpas_dbus_new_invalid_network_error - Return a new invalid network error message | |
356 | * @message: Pointer to incoming dbus message this error refers to | |
357 | * Returns: a dbus error message | |
358 | * | |
359 | * Convenience function to create and return an invalid network error | |
360 | */ | |
361 | DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) | |
362 | { | |
363 | return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, | |
364 | "The requested network does not exist."); | |
365 | } | |
366 | ||
367 | ||
368 | /** | |
369 | * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message | |
370 | * @message: Pointer to incoming dbus message this error refers to | |
371 | * Returns: a dbus error message | |
372 | * | |
373 | * Convenience function to create and return an invalid bssid error | |
374 | */ | |
375 | static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) | |
376 | { | |
377 | return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, | |
378 | "The BSSID requested was invalid."); | |
379 | } | |
380 | ||
381 | ||
382 | /** | |
383 | * wpas_dispatch_network_method - dispatch messages for configured networks | |
384 | * @message: the incoming dbus message | |
385 | * @wpa_s: a network interface's data | |
386 | * @network_id: id of the configured network we're interested in | |
387 | * Returns: a reply dbus message, or a dbus error message | |
388 | * | |
389 | * This function dispatches all incoming dbus messages for configured networks. | |
390 | */ | |
391 | static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, | |
392 | struct wpa_supplicant *wpa_s, | |
393 | int network_id) | |
394 | { | |
395 | DBusMessage *reply = NULL; | |
396 | const char *method = dbus_message_get_member(message); | |
397 | struct wpa_ssid *ssid; | |
398 | ||
399 | ssid = wpa_config_get_network(wpa_s->conf, network_id); | |
400 | if (ssid == NULL) | |
401 | return wpas_dbus_new_invalid_network_error(message); | |
402 | ||
403 | if (!strcmp(method, "set")) | |
404 | reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); | |
405 | else if (!strcmp(method, "enable")) | |
406 | reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); | |
407 | else if (!strcmp(method, "disable")) | |
408 | reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); | |
409 | ||
410 | return reply; | |
411 | } | |
412 | ||
413 | ||
414 | /** | |
415 | * wpas_dispatch_bssid_method - dispatch messages for scanned networks | |
416 | * @message: the incoming dbus message | |
417 | * @wpa_s: a network interface's data | |
418 | * @bssid: bssid of the scanned network we're interested in | |
419 | * Returns: a reply dbus message, or a dbus error message | |
420 | * | |
421 | * This function dispatches all incoming dbus messages for scanned networks. | |
422 | */ | |
423 | static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, | |
424 | struct wpa_supplicant *wpa_s, | |
425 | const char *bssid) | |
426 | { | |
427 | DBusMessage *reply = NULL; | |
428 | const char *method = dbus_message_get_member(message); | |
429 | struct wpa_scan_res *res = NULL; | |
430 | size_t i; | |
431 | ||
432 | /* Ensure we actually have scan data */ | |
433 | if (wpa_s->scan_res == NULL && | |
434 | wpa_supplicant_get_scan_results(wpa_s) < 0) { | |
435 | reply = wpas_dbus_new_invalid_bssid_error(message); | |
436 | goto out; | |
437 | } | |
438 | ||
439 | /* Find the bssid's scan data */ | |
440 | for (i = 0; i < wpa_s->scan_res->num; i++) { | |
441 | struct wpa_scan_res *search_res = wpa_s->scan_res->res[i]; | |
442 | char mac_str[18]; | |
443 | ||
444 | memset(mac_str, 0, sizeof(mac_str)); | |
445 | snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT, | |
446 | MAC2STR(search_res->bssid)); | |
447 | if (!strcmp(bssid, mac_str)) { | |
448 | res = search_res; | |
449 | break; | |
450 | } | |
451 | } | |
452 | ||
453 | if (!res) { | |
454 | reply = wpas_dbus_new_invalid_bssid_error(message); | |
455 | goto out; | |
456 | } | |
457 | ||
458 | /* Dispatch the method call against the scanned bssid */ | |
459 | if (!strcmp(method, "properties")) | |
460 | reply = wpas_dbus_bssid_properties(message, wpa_s, res); | |
461 | ||
462 | out: | |
463 | return reply; | |
464 | } | |
465 | ||
466 | ||
467 | /** | |
468 | * wpas_iface_message_handler - Dispatch messages for interfaces or networks | |
469 | * @connection: Connection to the system message bus | |
470 | * @message: An incoming dbus message | |
471 | * @user_data: A pointer to a dbus control interface data structure | |
472 | * Returns: Whether or not the message was handled | |
473 | * | |
474 | * This function dispatches all incoming dbus messages for network interfaces, | |
475 | * or objects owned by them, such as scanned BSSIDs and configured networks. | |
476 | */ | |
477 | static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, | |
478 | DBusMessage *message, | |
479 | void *user_data) | |
480 | { | |
481 | struct wpa_supplicant *wpa_s = user_data; | |
482 | const char *method = dbus_message_get_member(message); | |
483 | const char *path = dbus_message_get_path(message); | |
484 | const char *msg_interface = dbus_message_get_interface(message); | |
485 | char *iface_obj_path = NULL; | |
486 | char *network = NULL; | |
487 | char *bssid = NULL; | |
488 | DBusMessage *reply = NULL; | |
489 | ||
490 | /* Caller must specify a message interface */ | |
491 | if (!msg_interface) | |
492 | goto out; | |
493 | ||
494 | iface_obj_path = wpas_dbus_decompose_object_path(path, &network, | |
495 | &bssid); | |
496 | if (iface_obj_path == NULL) { | |
497 | reply = wpas_dbus_new_invalid_iface_error(message); | |
498 | goto out; | |
499 | } | |
500 | ||
501 | /* Make sure the message's object path actually refers to the | |
502 | * wpa_supplicant structure it's supposed to (which is wpa_s) | |
503 | */ | |
504 | if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, | |
505 | iface_obj_path) != wpa_s) { | |
506 | reply = wpas_dbus_new_invalid_iface_error(message); | |
507 | goto out; | |
508 | } | |
509 | ||
510 | if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { | |
511 | /* A method for one of this interface's configured networks */ | |
512 | int nid = strtoul(network, NULL, 10); | |
513 | if (errno != EINVAL) | |
514 | reply = wpas_dispatch_network_method(message, wpa_s, | |
515 | nid); | |
516 | else | |
517 | reply = wpas_dbus_new_invalid_network_error(message); | |
518 | } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { | |
519 | /* A method for one of this interface's scanned BSSIDs */ | |
520 | reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); | |
521 | } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { | |
522 | /* A method for an interface only. */ | |
523 | if (!strcmp(method, "scan")) | |
524 | reply = wpas_dbus_iface_scan(message, wpa_s); | |
525 | else if (!strcmp(method, "scanResults")) | |
526 | reply = wpas_dbus_iface_scan_results(message, wpa_s); | |
527 | else if (!strcmp(method, "addNetwork")) | |
528 | reply = wpas_dbus_iface_add_network(message, wpa_s); | |
529 | else if (!strcmp(method, "removeNetwork")) | |
530 | reply = wpas_dbus_iface_remove_network(message, wpa_s); | |
531 | else if (!strcmp(method, "selectNetwork")) | |
532 | reply = wpas_dbus_iface_select_network(message, wpa_s); | |
533 | else if (!strcmp(method, "capabilities")) | |
534 | reply = wpas_dbus_iface_capabilities(message, wpa_s); | |
535 | else if (!strcmp(method, "disconnect")) | |
536 | reply = wpas_dbus_iface_disconnect(message, wpa_s); | |
537 | else if (!strcmp(method, "setAPScan")) | |
538 | reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); | |
e403be0b DS |
539 | else if (!strcmp(method, "setSmartcardModules")) |
540 | reply = wpas_dbus_iface_set_smartcard_modules(message, | |
541 | wpa_s); | |
6fc6879b JM |
542 | else if (!strcmp(method, "state")) |
543 | reply = wpas_dbus_iface_get_state(message, wpa_s); | |
cb8564b1 DW |
544 | else if (!strcmp(method, "scanning")) |
545 | reply = wpas_dbus_iface_get_scanning(message, wpa_s); | |
6fc6879b JM |
546 | else if (!strcmp(method, "setBlobs")) |
547 | reply = wpas_dbus_iface_set_blobs(message, wpa_s); | |
548 | else if (!strcmp(method, "removeBlobs")) | |
549 | reply = wpas_dbus_iface_remove_blobs(message, wpa_s); | |
e8fa6039 JSP |
550 | #ifdef CONFIG_WPS |
551 | else if (!os_strcmp(method, "wpsPbc")) | |
552 | reply = wpas_dbus_iface_wps_pbc(message, wpa_s); | |
553 | else if (!os_strcmp(method, "wpsPin")) | |
554 | reply = wpas_dbus_iface_wps_pin(message, wpa_s); | |
555 | else if (!os_strcmp(method, "wpsReg")) | |
556 | reply = wpas_dbus_iface_wps_reg(message, wpa_s); | |
557 | #endif /* CONFIG_WPS */ | |
6fc6879b JM |
558 | } |
559 | ||
560 | /* If the message was handled, send back the reply */ | |
561 | if (reply) { | |
c3f5b1e1 HS |
562 | if (!dbus_message_get_no_reply(message)) |
563 | dbus_connection_send(connection, reply, NULL); | |
6fc6879b JM |
564 | dbus_message_unref(reply); |
565 | } | |
566 | ||
567 | out: | |
568 | free(iface_obj_path); | |
569 | free(network); | |
570 | free(bssid); | |
571 | return reply ? DBUS_HANDLER_RESULT_HANDLED : | |
572 | DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | |
573 | } | |
574 | ||
575 | ||
576 | /** | |
577 | * wpas_message_handler - dispatch incoming dbus messages | |
578 | * @connection: connection to the system message bus | |
579 | * @message: an incoming dbus message | |
580 | * @user_data: a pointer to a dbus control interface data structure | |
581 | * Returns: whether or not the message was handled | |
582 | * | |
583 | * This function dispatches all incoming dbus messages to the correct | |
584 | * handlers, depending on what the message's target object path is, | |
585 | * and what the method call is. | |
586 | */ | |
587 | static DBusHandlerResult wpas_message_handler(DBusConnection *connection, | |
588 | DBusMessage *message, void *user_data) | |
589 | { | |
590 | struct ctrl_iface_dbus_priv *ctrl_iface = user_data; | |
591 | const char *method; | |
592 | const char *path; | |
593 | const char *msg_interface; | |
594 | DBusMessage *reply = NULL; | |
595 | ||
596 | method = dbus_message_get_member(message); | |
597 | path = dbus_message_get_path(message); | |
598 | msg_interface = dbus_message_get_interface(message); | |
599 | if (!method || !path || !ctrl_iface || !msg_interface) | |
600 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | |
601 | ||
602 | /* Validate the method interface */ | |
603 | if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) | |
604 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | |
605 | ||
606 | if (!strcmp(path, WPAS_DBUS_PATH)) { | |
607 | /* dispatch methods against our global dbus interface here */ | |
608 | if (!strcmp(method, "addInterface")) { | |
609 | reply = wpas_dbus_global_add_interface( | |
610 | message, ctrl_iface->global); | |
611 | } else if (!strcmp(method, "removeInterface")) { | |
612 | reply = wpas_dbus_global_remove_interface( | |
613 | message, ctrl_iface->global); | |
614 | } else if (!strcmp(method, "getInterface")) { | |
615 | reply = wpas_dbus_global_get_interface( | |
616 | message, ctrl_iface->global); | |
01a569e8 HS |
617 | } else if (!strcmp(method, "setDebugParams")) { |
618 | reply = wpas_dbus_global_set_debugparams( | |
619 | message, ctrl_iface->global); | |
6fc6879b JM |
620 | } |
621 | } | |
622 | ||
623 | /* If the message was handled, send back the reply */ | |
624 | if (reply) { | |
c3f5b1e1 HS |
625 | if (!dbus_message_get_no_reply(message)) |
626 | dbus_connection_send(connection, reply, NULL); | |
6fc6879b JM |
627 | dbus_message_unref(reply); |
628 | } | |
629 | ||
630 | return reply ? DBUS_HANDLER_RESULT_HANDLED : | |
631 | DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | |
632 | } | |
633 | ||
634 | ||
635 | /** | |
636 | * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal | |
637 | * @wpa_s: %wpa_supplicant network interface data | |
638 | * Returns: 0 on success, -1 on failure | |
639 | * | |
640 | * Notify listeners that this interface has updated scan results. | |
641 | */ | |
642 | void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) | |
643 | { | |
644 | struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface; | |
645 | DBusMessage *_signal; | |
646 | const char *path; | |
647 | ||
648 | /* Do nothing if the control interface is not turned on */ | |
649 | if (iface == NULL) | |
650 | return; | |
651 | ||
652 | path = wpa_supplicant_get_dbus_path(wpa_s); | |
653 | if (path == NULL) { | |
654 | perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " | |
655 | "interface didn't have a dbus path"); | |
656 | wpa_printf(MSG_ERROR, | |
657 | "wpa_supplicant_dbus_notify_scan_results[dbus]: " | |
658 | "interface didn't have a dbus path; can't send " | |
659 | "scan result signal."); | |
660 | return; | |
661 | } | |
662 | _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, | |
663 | "ScanResultsAvailable"); | |
664 | if (_signal == NULL) { | |
665 | perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " | |
666 | "couldn't create dbus signal; likely out of memory"); | |
667 | wpa_printf(MSG_ERROR, "dbus control interface: not enough " | |
668 | "memory to send scan results signal."); | |
669 | return; | |
670 | } | |
671 | dbus_connection_send(iface->con, _signal, NULL); | |
672 | dbus_message_unref(_signal); | |
673 | } | |
674 | ||
675 | ||
676 | /** | |
677 | * wpa_supplicant_dbus_notify_state_change - Send a state change signal | |
678 | * @wpa_s: %wpa_supplicant network interface data | |
679 | * @new_state: new state wpa_supplicant is entering | |
680 | * @old_state: old state wpa_supplicant is leaving | |
681 | * Returns: 0 on success, -1 on failure | |
682 | * | |
683 | * Notify listeners that wpa_supplicant has changed state | |
684 | */ | |
685 | void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, | |
686 | wpa_states new_state, | |
687 | wpa_states old_state) | |
688 | { | |
689 | struct ctrl_iface_dbus_priv *iface; | |
690 | DBusMessage *_signal = NULL; | |
691 | const char *path; | |
692 | const char *new_state_str, *old_state_str; | |
693 | ||
694 | /* Do nothing if the control interface is not turned on */ | |
695 | if (wpa_s->global == NULL) | |
696 | return; | |
697 | iface = wpa_s->global->dbus_ctrl_iface; | |
698 | if (iface == NULL) | |
699 | return; | |
700 | ||
701 | /* Only send signal if state really changed */ | |
702 | if (new_state == old_state) | |
703 | return; | |
704 | ||
705 | path = wpa_supplicant_get_dbus_path(wpa_s); | |
706 | if (path == NULL) { | |
707 | perror("wpa_supplicant_dbus_notify_state_change[dbus]: " | |
708 | "interface didn't have a dbus path"); | |
709 | wpa_printf(MSG_ERROR, | |
710 | "wpa_supplicant_dbus_notify_state_change[dbus]: " | |
711 | "interface didn't have a dbus path; can't send " | |
712 | "signal."); | |
713 | return; | |
714 | } | |
715 | _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, | |
716 | "StateChange"); | |
717 | if (_signal == NULL) { | |
718 | perror("wpa_supplicant_dbus_notify_state_change[dbus]: " | |
719 | "couldn't create dbus signal; likely out of memory"); | |
720 | wpa_printf(MSG_ERROR, | |
721 | "wpa_supplicant_dbus_notify_state_change[dbus]: " | |
722 | "couldn't create dbus signal; likely out of " | |
723 | "memory."); | |
724 | return; | |
725 | } | |
726 | ||
727 | new_state_str = wpa_supplicant_state_txt(new_state); | |
728 | old_state_str = wpa_supplicant_state_txt(old_state); | |
729 | if (new_state_str == NULL || old_state_str == NULL) { | |
730 | perror("wpa_supplicant_dbus_notify_state_change[dbus]: " | |
731 | "couldn't convert state strings"); | |
732 | wpa_printf(MSG_ERROR, | |
733 | "wpa_supplicant_dbus_notify_state_change[dbus]: " | |
734 | "couldn't convert state strings."); | |
735 | goto out; | |
736 | } | |
737 | ||
738 | if (!dbus_message_append_args(_signal, | |
739 | DBUS_TYPE_STRING, &new_state_str, | |
740 | DBUS_TYPE_STRING, &old_state_str, | |
741 | DBUS_TYPE_INVALID)) { | |
742 | perror("wpa_supplicant_dbus_notify_state_change[dbus]: " | |
743 | "not enough memory to construct state change signal."); | |
744 | wpa_printf(MSG_ERROR, | |
745 | "wpa_supplicant_dbus_notify_state_change[dbus]: " | |
746 | "not enough memory to construct state change " | |
747 | "signal."); | |
748 | goto out; | |
749 | } | |
750 | ||
751 | dbus_connection_send(iface->con, _signal, NULL); | |
752 | ||
753 | out: | |
754 | dbus_message_unref(_signal); | |
755 | } | |
756 | ||
757 | ||
cb8564b1 DW |
758 | /** |
759 | * wpa_supplicant_dbus_notify_scanning - send scanning status | |
760 | * @wpa_s: %wpa_supplicant network interface data | |
761 | * Returns: 0 on success, -1 on failure | |
762 | * | |
763 | * Notify listeners of interface scanning state changes | |
764 | */ | |
765 | void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) | |
766 | { | |
767 | struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface; | |
768 | DBusMessage *_signal; | |
769 | const char *path; | |
770 | dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; | |
771 | ||
772 | /* Do nothing if the control interface is not turned on */ | |
773 | if (iface == NULL) | |
774 | return; | |
775 | ||
776 | path = wpa_supplicant_get_dbus_path(wpa_s); | |
777 | if (path == NULL) { | |
778 | perror("wpa_supplicant_dbus_notify_scanning[dbus]: interface " | |
779 | "didn't have a dbus path"); | |
780 | wpa_printf(MSG_ERROR, | |
781 | "%s[dbus]: interface didn't have a dbus path; " | |
782 | "can't send scanning signal.", __FUNCTION__); | |
783 | return; | |
784 | } | |
785 | _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, | |
786 | "Scanning"); | |
787 | if (_signal == NULL) { | |
788 | perror("wpa_supplicant_dbus_notify_scanning[dbus]: couldn't " | |
789 | "create dbus signal; likely out of memory"); | |
790 | wpa_printf(MSG_ERROR, "%s[dbus]: dbus control interface: not " | |
791 | "enough memory to send scan results signal.", | |
792 | __FUNCTION__); | |
793 | return; | |
794 | } | |
795 | ||
796 | if (dbus_message_append_args(_signal, | |
797 | DBUS_TYPE_BOOLEAN, &scanning, | |
798 | DBUS_TYPE_INVALID)) { | |
799 | dbus_connection_send(iface->con, _signal, NULL); | |
800 | } else { | |
801 | perror("wpa_supplicant_dbus_notify_scanning[dbus]: not enough " | |
802 | "memory to construct signal."); | |
803 | wpa_printf(MSG_ERROR, "%s[dbus]: not enough memory to " | |
804 | "construct signal.", __FUNCTION__); | |
805 | } | |
806 | dbus_message_unref(_signal); | |
807 | } | |
808 | ||
809 | ||
47662164 JM |
810 | #ifdef CONFIG_WPS |
811 | void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, | |
812 | const struct wps_credential *cred) | |
813 | { | |
814 | struct ctrl_iface_dbus_priv *iface; | |
815 | DBusMessage *_signal = NULL; | |
816 | const char *path; | |
817 | ||
818 | /* Do nothing if the control interface is not turned on */ | |
819 | if (wpa_s->global == NULL) | |
820 | return; | |
821 | iface = wpa_s->global->dbus_ctrl_iface; | |
822 | if (iface == NULL) | |
823 | return; | |
824 | ||
825 | path = wpa_supplicant_get_dbus_path(wpa_s); | |
826 | if (path == NULL) { | |
827 | perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " | |
828 | "interface didn't have a dbus path"); | |
829 | wpa_printf(MSG_ERROR, | |
830 | "wpa_supplicant_dbus_notify_wps_cred[dbus]: " | |
831 | "interface didn't have a dbus path; can't send " | |
832 | "signal."); | |
833 | return; | |
834 | } | |
835 | _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, | |
836 | "WpsCred"); | |
837 | if (_signal == NULL) { | |
838 | perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " | |
839 | "couldn't create dbus signal; likely out of memory"); | |
840 | wpa_printf(MSG_ERROR, | |
841 | "wpa_supplicant_dbus_notify_wps_cred[dbus]: " | |
842 | "couldn't create dbus signal; likely out of " | |
843 | "memory."); | |
844 | return; | |
845 | } | |
846 | ||
847 | if (!dbus_message_append_args(_signal, | |
848 | DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, | |
849 | &cred->cred_attr, cred->cred_attr_len, | |
850 | DBUS_TYPE_INVALID)) { | |
851 | perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " | |
852 | "not enough memory to construct signal."); | |
853 | wpa_printf(MSG_ERROR, | |
854 | "wpa_supplicant_dbus_notify_wps_cred[dbus]: " | |
855 | "not enough memory to construct signal."); | |
856 | goto out; | |
857 | } | |
858 | ||
859 | dbus_connection_send(iface->con, _signal, NULL); | |
860 | ||
861 | out: | |
862 | dbus_message_unref(_signal); | |
863 | } | |
864 | #endif /* CONFIG_WPS */ | |
865 | ||
866 | ||
6fc6879b JM |
867 | /** |
868 | * integrate_with_eloop - Register our mainloop integration with dbus | |
869 | * @connection: connection to the system message bus | |
870 | * @iface: a dbus control interface data structure | |
871 | * Returns: 0 on success, -1 on failure | |
872 | * | |
873 | * We register our mainloop integration functions with dbus here. | |
874 | */ | |
875 | static int integrate_with_eloop(DBusConnection *connection, | |
876 | struct ctrl_iface_dbus_priv *iface) | |
877 | { | |
878 | if (!dbus_connection_set_watch_functions(connection, add_watch, | |
879 | remove_watch, watch_toggled, | |
880 | iface, NULL)) { | |
881 | perror("dbus_connection_set_watch_functions[dbus]"); | |
882 | wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); | |
883 | return -1; | |
884 | } | |
885 | ||
886 | if (!dbus_connection_set_timeout_functions(connection, add_timeout, | |
887 | remove_timeout, | |
888 | timeout_toggled, iface, | |
889 | NULL)) { | |
890 | perror("dbus_connection_set_timeout_functions[dbus]"); | |
891 | wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); | |
892 | return -1; | |
893 | } | |
894 | ||
895 | if (connection_setup_wakeup_main(iface) < 0) { | |
896 | perror("connection_setup_wakeup_main[dbus]"); | |
897 | wpa_printf(MSG_ERROR, "Could not setup main wakeup function."); | |
898 | return -1; | |
899 | } | |
900 | ||
901 | return 0; | |
902 | } | |
903 | ||
904 | ||
905 | /** | |
906 | * dispatch_initial_dbus_messages - Dispatch initial dbus messages after | |
907 | * claiming bus name | |
908 | * @eloop_ctx: the DBusConnection to dispatch on | |
909 | * @timeout_ctx: unused | |
910 | * | |
911 | * If clients are quick to notice that wpa_supplicant claimed its bus name, | |
912 | * there may have been messages that came in before initialization was | |
913 | * all finished. Dispatch those here. | |
914 | */ | |
915 | static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx) | |
916 | { | |
917 | DBusConnection *con = eloop_ctx; | |
918 | ||
919 | while (dbus_connection_get_dispatch_status(con) == | |
920 | DBUS_DISPATCH_DATA_REMAINS) | |
921 | dbus_connection_dispatch(con); | |
922 | } | |
923 | ||
924 | ||
925 | /** | |
926 | * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface | |
927 | * @global: Pointer to global data from wpa_supplicant_init() | |
928 | * Returns: Pointer to dbus_ctrl_iface date or %NULL on failure | |
929 | * | |
930 | * Initialize the dbus control interface and start receiving commands from | |
931 | * external programs over the bus. | |
932 | */ | |
933 | struct ctrl_iface_dbus_priv * | |
934 | wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global) | |
935 | { | |
936 | struct ctrl_iface_dbus_priv *iface; | |
937 | DBusError error; | |
938 | int ret = -1; | |
939 | DBusObjectPathVTable wpas_vtable = { | |
940 | NULL, &wpas_message_handler, NULL, NULL, NULL, NULL | |
941 | }; | |
942 | ||
943 | iface = os_zalloc(sizeof(struct ctrl_iface_dbus_priv)); | |
944 | if (iface == NULL) | |
945 | return NULL; | |
946 | ||
947 | iface->global = global; | |
948 | ||
949 | /* Get a reference to the system bus */ | |
950 | dbus_error_init(&error); | |
951 | iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); | |
952 | dbus_error_free(&error); | |
953 | if (!iface->con) { | |
954 | perror("dbus_bus_get[ctrl_iface_dbus]"); | |
955 | wpa_printf(MSG_ERROR, "Could not acquire the system bus."); | |
956 | goto fail; | |
957 | } | |
958 | ||
959 | /* Tell dbus about our mainloop integration functions */ | |
960 | if (integrate_with_eloop(iface->con, iface)) | |
961 | goto fail; | |
962 | ||
963 | /* Register the message handler for the global dbus interface */ | |
964 | if (!dbus_connection_register_object_path(iface->con, | |
965 | WPAS_DBUS_PATH, &wpas_vtable, | |
966 | iface)) { | |
967 | perror("dbus_connection_register_object_path[dbus]"); | |
968 | wpa_printf(MSG_ERROR, "Could not set up DBus message " | |
969 | "handler."); | |
970 | goto fail; | |
971 | } | |
972 | ||
973 | /* Register our service with the message bus */ | |
974 | dbus_error_init(&error); | |
975 | switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, | |
976 | 0, &error)) { | |
977 | case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: | |
978 | ret = 0; | |
979 | break; | |
980 | case DBUS_REQUEST_NAME_REPLY_EXISTS: | |
981 | case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: | |
982 | case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: | |
983 | perror("dbus_bus_request_name[dbus]"); | |
984 | wpa_printf(MSG_ERROR, "Could not request DBus service name: " | |
985 | "already registered."); | |
986 | break; | |
987 | default: | |
988 | perror("dbus_bus_request_name[dbus]"); | |
989 | wpa_printf(MSG_ERROR, "Could not request DBus service name: " | |
990 | "%s %s.", error.name, error.message); | |
991 | break; | |
992 | } | |
993 | dbus_error_free(&error); | |
994 | ||
995 | if (ret != 0) | |
996 | goto fail; | |
997 | ||
998 | wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE | |
999 | "'."); | |
1000 | ||
1001 | /* | |
1002 | * Dispatch initial DBus messages that may have come in since the bus | |
1003 | * name was claimed above. Happens when clients are quick to notice the | |
1004 | * wpa_supplicant service. | |
1005 | * | |
1006 | * FIXME: is there a better solution to this problem? | |
1007 | */ | |
1008 | eloop_register_timeout(0, 50, dispatch_initial_dbus_messages, | |
1009 | iface->con, NULL); | |
1010 | ||
1011 | return iface; | |
1012 | ||
1013 | fail: | |
1014 | wpa_supplicant_dbus_ctrl_iface_deinit(iface); | |
1015 | return NULL; | |
1016 | } | |
1017 | ||
1018 | ||
1019 | /** | |
1020 | * wpa_supplicant_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface | |
1021 | * @iface: Pointer to dbus private data from | |
1022 | * wpa_supplicant_dbus_ctrl_iface_init() | |
1023 | * | |
1024 | * Deinitialize the dbus control interface that was initialized with | |
1025 | * wpa_supplicant_dbus_ctrl_iface_init(). | |
1026 | */ | |
1027 | void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface) | |
1028 | { | |
1029 | if (iface == NULL) | |
1030 | return; | |
1031 | ||
1032 | if (iface->con) { | |
1033 | eloop_cancel_timeout(dispatch_initial_dbus_messages, | |
1034 | iface->con, NULL); | |
1035 | dbus_connection_set_watch_functions(iface->con, NULL, NULL, | |
1036 | NULL, NULL, NULL); | |
1037 | dbus_connection_set_timeout_functions(iface->con, NULL, NULL, | |
1038 | NULL, NULL, NULL); | |
1039 | dbus_connection_unref(iface->con); | |
1040 | } | |
1041 | ||
1042 | memset(iface, 0, sizeof(struct ctrl_iface_dbus_priv)); | |
1043 | free(iface); | |
1044 | } | |
1045 | ||
1046 | ||
1047 | /** | |
1048 | * wpas_dbus_register_new_iface - Register a new interface with dbus | |
6fc6879b JM |
1049 | * @wpa_s: %wpa_supplicant interface description structure to register |
1050 | * Returns: 0 on success, -1 on error | |
1051 | * | |
1052 | * Registers a new interface with dbus and assigns it a dbus object path. | |
1053 | */ | |
1054 | int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) | |
1055 | { | |
1056 | struct ctrl_iface_dbus_priv *ctrl_iface = | |
1057 | wpa_s->global->dbus_ctrl_iface; | |
1058 | DBusConnection * con; | |
1059 | u32 next; | |
1060 | DBusObjectPathVTable vtable = { | |
1061 | NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL | |
1062 | }; | |
1063 | char *path; | |
1064 | int ret = -1; | |
1065 | ||
1066 | /* Do nothing if the control interface is not turned on */ | |
1067 | if (ctrl_iface == NULL) | |
1068 | return 0; | |
1069 | ||
1070 | con = ctrl_iface->con; | |
1071 | next = wpa_supplicant_dbus_next_objid(ctrl_iface); | |
1072 | ||
1073 | /* Create and set the interface's object path */ | |
1074 | path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); | |
1075 | if (path == NULL) | |
1076 | return -1; | |
1077 | snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, | |
1078 | WPAS_DBUS_PATH_INTERFACES "/%u", | |
1079 | next); | |
1080 | if (wpa_supplicant_set_dbus_path(wpa_s, path)) { | |
1081 | wpa_printf(MSG_DEBUG, | |
1082 | "Failed to set dbus path for interface %s", | |
1083 | wpa_s->ifname); | |
1084 | goto out; | |
1085 | } | |
1086 | ||
1087 | /* Register the message handler for the interface functions */ | |
1088 | if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) { | |
1089 | perror("wpas_dbus_register_iface [dbus]"); | |
1090 | wpa_printf(MSG_ERROR, "Could not set up DBus message " | |
1091 | "handler for interface %s.", wpa_s->ifname); | |
1092 | goto out; | |
1093 | } | |
1094 | ret = 0; | |
1095 | ||
1096 | out: | |
1097 | free(path); | |
1098 | return ret; | |
1099 | } | |
1100 | ||
1101 | ||
1102 | /** | |
1103 | * wpas_dbus_unregister_iface - Unregister an interface from dbus | |
1104 | * @wpa_s: wpa_supplicant interface structure | |
1105 | * Returns: 0 on success, -1 on failure | |
1106 | * | |
1107 | * Unregisters the interface with dbus | |
1108 | */ | |
1109 | int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) | |
1110 | { | |
1111 | struct ctrl_iface_dbus_priv *ctrl_iface; | |
1112 | DBusConnection *con; | |
1113 | const char *path; | |
1114 | ||
1115 | /* Do nothing if the control interface is not turned on */ | |
1116 | if (wpa_s == NULL || wpa_s->global == NULL) | |
1117 | return 0; | |
1118 | ctrl_iface = wpa_s->global->dbus_ctrl_iface; | |
1119 | if (ctrl_iface == NULL) | |
1120 | return 0; | |
1121 | ||
1122 | con = ctrl_iface->con; | |
1123 | path = wpa_supplicant_get_dbus_path(wpa_s); | |
1124 | ||
1125 | if (!dbus_connection_unregister_object_path(con, path)) | |
1126 | return -1; | |
1127 | ||
1128 | free(wpa_s->dbus_path); | |
1129 | wpa_s->dbus_path = NULL; | |
1130 | ||
1131 | return 0; | |
1132 | } | |
1133 | ||
1134 | ||
1135 | /** | |
1136 | * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface | |
1137 | * @global: Pointer to global data from wpa_supplicant_init() | |
1138 | * @path: Pointer to a dbus object path representing an interface | |
1139 | * Returns: Pointer to the interface or %NULL if not found | |
1140 | */ | |
1141 | struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( | |
1142 | struct wpa_global *global, const char *path) | |
1143 | { | |
1144 | struct wpa_supplicant *wpa_s; | |
1145 | ||
1146 | for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { | |
1147 | if (strcmp(wpa_s->dbus_path, path) == 0) | |
1148 | return wpa_s; | |
1149 | } | |
1150 | return NULL; | |
1151 | } | |
1152 | ||
1153 | ||
1154 | /** | |
1155 | * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface | |
1156 | * @wpa_s: wpa_supplicant interface structure | |
1157 | * @path: dbus path to set on the interface | |
1158 | * Returns: 0 on succes, -1 on error | |
1159 | */ | |
1160 | int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s, | |
1161 | const char *path) | |
1162 | { | |
1163 | u32 len = strlen (path); | |
1164 | if (len >= WPAS_DBUS_OBJECT_PATH_MAX) | |
1165 | return -1; | |
1166 | if (wpa_s->dbus_path) | |
1167 | return -1; | |
1168 | wpa_s->dbus_path = strdup(path); | |
1169 | return 0; | |
1170 | } | |
1171 | ||
1172 | ||
1173 | /** | |
1174 | * wpa_supplicant_get_dbus_path - Get an interface's dbus path | |
1175 | * @wpa_s: %wpa_supplicant interface structure | |
1176 | * Returns: Interface's dbus object path, or %NULL on error | |
1177 | */ | |
1178 | const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s) | |
1179 | { | |
1180 | return wpa_s->dbus_path; | |
1181 | } |