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