dbus: Do not deinitialize new D-Bus API if it is not initialized
[libeap.git] / wpa_supplicant / dbus / 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 "drivers/driver.h"
20 #include "wps/wps.h"
21 #include "../config.h"
22 #include "../wpa_supplicant_i.h"
23 #include "dbus.h"
24 #include "dbus_handlers.h"
25 #include "dbus_common.h"
26 #include "dbus_common_i.h"
27
28
29 /**
30  * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
31  * @path: The dbus object path
32  * @network: (out) the configured network this object path refers to, if any
33  * @bssid: (out) the scanned bssid this object path refers to, if any
34  * Returns: The object path of the network interface this path refers to
35  *
36  * For a given object path, decomposes the object path into object id, network,
37  * and BSSID parts, if those parts exist.
38  */
39 char * wpas_dbus_decompose_object_path(const char *path, char **network,
40                                        char **bssid)
41 {
42         const unsigned int dev_path_prefix_len =
43                 strlen(WPAS_DBUS_PATH_INTERFACES "/");
44         char *obj_path_only;
45         char *next_sep;
46
47         /* Be a bit paranoid about path */
48         if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
49                              dev_path_prefix_len))
50                 return NULL;
51
52         /* Ensure there's something at the end of the path */
53         if ((path + dev_path_prefix_len)[0] == '\0')
54                 return NULL;
55
56         obj_path_only = os_strdup(path);
57         if (obj_path_only == NULL)
58                 return NULL;
59
60         next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
61         if (next_sep != NULL) {
62                 const char *net_part = strstr(next_sep,
63                                               WPAS_DBUS_NETWORKS_PART "/");
64                 const char *bssid_part = strstr(next_sep,
65                                                 WPAS_DBUS_BSSIDS_PART "/");
66
67                 if (network && net_part) {
68                         /* Deal with a request for a configured network */
69                         const char *net_name = net_part +
70                                 strlen(WPAS_DBUS_NETWORKS_PART "/");
71                         *network = NULL;
72                         if (strlen(net_name))
73                                 *network = os_strdup(net_name);
74                 } else if (bssid && bssid_part) {
75                         /* Deal with a request for a scanned BSSID */
76                         const char *bssid_name = bssid_part +
77                                 strlen(WPAS_DBUS_BSSIDS_PART "/");
78                         if (strlen(bssid_name))
79                                 *bssid = os_strdup(bssid_name);
80                         else
81                                 *bssid = NULL;
82                 }
83
84                 /* Cut off interface object path before "/" */
85                 *next_sep = '\0';
86         }
87
88         return obj_path_only;
89 }
90
91
92 /**
93  * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
94  * @message: Pointer to incoming dbus message this error refers to
95  * Returns: A dbus error message
96  *
97  * Convenience function to create and return an invalid interface error
98  */
99 DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
100 {
101         return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
102                                       "wpa_supplicant knows nothing about "
103                                       "this interface.");
104 }
105
106
107 /**
108  * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
109  * @message: Pointer to incoming dbus message this error refers to
110  * Returns: a dbus error message
111  *
112  * Convenience function to create and return an invalid network error
113  */
114 DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
115 {
116         return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
117                                       "The requested network does not exist.");
118 }
119
120
121 /**
122  * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
123  * @message: Pointer to incoming dbus message this error refers to
124  * Returns: a dbus error message
125  *
126  * Convenience function to create and return an invalid bssid error
127  */
128 static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
129 {
130         return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
131                                       "The BSSID requested was invalid.");
132 }
133
134
135 /**
136  * wpas_dispatch_network_method - dispatch messages for configured networks
137  * @message: the incoming dbus message
138  * @wpa_s: a network interface's data
139  * @network_id: id of the configured network we're interested in
140  * Returns: a reply dbus message, or a dbus error message
141  *
142  * This function dispatches all incoming dbus messages for configured networks.
143  */
144 static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
145                                                   struct wpa_supplicant *wpa_s,
146                                                   int network_id)
147 {
148         DBusMessage *reply = NULL;
149         const char *method = dbus_message_get_member(message);
150         struct wpa_ssid *ssid;
151
152         ssid = wpa_config_get_network(wpa_s->conf, network_id);
153         if (ssid == NULL)
154                 return wpas_dbus_new_invalid_network_error(message);
155
156         if (!strcmp(method, "set"))
157                 reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
158         else if (!strcmp(method, "enable"))
159                 reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
160         else if (!strcmp(method, "disable"))
161                 reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
162
163         return reply;
164 }
165
166
167 /**
168  * wpas_dispatch_bssid_method - dispatch messages for scanned networks
169  * @message: the incoming dbus message
170  * @wpa_s: a network interface's data
171  * @bssid: bssid of the scanned network we're interested in
172  * Returns: a reply dbus message, or a dbus error message
173  *
174  * This function dispatches all incoming dbus messages for scanned networks.
175  */
176 static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
177                                                 struct wpa_supplicant *wpa_s,
178                                                 const char *bssid)
179 {
180         DBusMessage *reply = NULL;
181         const char *method = dbus_message_get_member(message);
182         struct wpa_scan_res *res = NULL;
183         size_t i;
184
185         /* Ensure we actually have scan data */
186         if (wpa_s->scan_res == NULL &&
187             wpa_supplicant_get_scan_results(wpa_s) < 0) {
188                 reply = wpas_dbus_new_invalid_bssid_error(message);
189                 goto out;
190         }
191
192         /* Find the bssid's scan data */
193         for (i = 0; i < wpa_s->scan_res->num; i++) {
194                 struct wpa_scan_res *search_res = wpa_s->scan_res->res[i];
195                 char mac_str[18];
196
197                 memset(mac_str, 0, sizeof(mac_str));
198                 snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT,
199                          MAC2STR(search_res->bssid));
200                 if (!strcmp(bssid, mac_str)) {
201                         res = search_res;
202                         break;
203                 }
204         }
205
206         if (!res) {
207                 reply = wpas_dbus_new_invalid_bssid_error(message);
208                 goto out;
209         }
210
211         /* Dispatch the method call against the scanned bssid */
212         if (!strcmp(method, "properties"))
213                 reply = wpas_dbus_bssid_properties(message, wpa_s, res);
214
215 out:
216         return reply;
217 }
218
219
220 /**
221  * wpas_iface_message_handler - Dispatch messages for interfaces or networks
222  * @connection: Connection to the system message bus
223  * @message: An incoming dbus message
224  * @user_data: A pointer to a dbus control interface data structure
225  * Returns: Whether or not the message was handled
226  *
227  * This function dispatches all incoming dbus messages for network interfaces,
228  * or objects owned by them, such as scanned BSSIDs and configured networks.
229  */
230 static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
231                                                     DBusMessage *message,
232                                                     void *user_data)
233 {
234         struct wpa_supplicant *wpa_s = user_data;
235         const char *method = dbus_message_get_member(message);
236         const char *path = dbus_message_get_path(message);
237         const char *msg_interface = dbus_message_get_interface(message);
238         char *iface_obj_path = NULL;
239         char *network = NULL;
240         char *bssid = NULL;
241         DBusMessage *reply = NULL;
242
243         /* Caller must specify a message interface */
244         if (!msg_interface)
245                 goto out;
246
247         iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
248                                                          &bssid);
249         if (iface_obj_path == NULL) {
250                 reply = wpas_dbus_new_invalid_iface_error(message);
251                 goto out;
252         }
253
254         /* Make sure the message's object path actually refers to the
255          * wpa_supplicant structure it's supposed to (which is wpa_s)
256          */
257         if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
258                                                   iface_obj_path) != wpa_s) {
259                 reply = wpas_dbus_new_invalid_iface_error(message);
260                 goto out;
261         }
262
263         if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
264                 /* A method for one of this interface's configured networks */
265                 int nid = strtoul(network, NULL, 10);
266                 if (errno != EINVAL)
267                         reply = wpas_dispatch_network_method(message, wpa_s,
268                                                              nid);
269                 else
270                         reply = wpas_dbus_new_invalid_network_error(message);
271         } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
272                 /* A method for one of this interface's scanned BSSIDs */
273                 reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
274         } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
275                 /* A method for an interface only. */
276                 if (!strcmp(method, "scan"))
277                         reply = wpas_dbus_iface_scan(message, wpa_s);
278                 else if (!strcmp(method, "scanResults"))
279                         reply = wpas_dbus_iface_scan_results(message, wpa_s);
280                 else if (!strcmp(method, "addNetwork"))
281                         reply = wpas_dbus_iface_add_network(message, wpa_s);
282                 else if (!strcmp(method, "removeNetwork"))
283                         reply = wpas_dbus_iface_remove_network(message, wpa_s);
284                 else if (!strcmp(method, "selectNetwork"))
285                         reply = wpas_dbus_iface_select_network(message, wpa_s);
286                 else if (!strcmp(method, "capabilities"))
287                         reply = wpas_dbus_iface_capabilities(message, wpa_s);
288                 else if (!strcmp(method, "disconnect"))
289                         reply = wpas_dbus_iface_disconnect(message, wpa_s);
290                 else if (!strcmp(method, "setAPScan"))
291                         reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
292                 else if (!strcmp(method, "setSmartcardModules"))
293                         reply = wpas_dbus_iface_set_smartcard_modules(message,
294                                                                       wpa_s);
295                 else if (!strcmp(method, "state"))
296                         reply = wpas_dbus_iface_get_state(message, wpa_s);
297                 else if (!strcmp(method, "scanning"))
298                         reply = wpas_dbus_iface_get_scanning(message, wpa_s);
299                 else if (!strcmp(method, "setBlobs"))
300                         reply = wpas_dbus_iface_set_blobs(message, wpa_s);
301                 else if (!strcmp(method, "removeBlobs"))
302                         reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
303 #ifdef CONFIG_WPS
304                 else if (!os_strcmp(method, "wpsPbc"))
305                         reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
306                 else if (!os_strcmp(method, "wpsPin"))
307                         reply = wpas_dbus_iface_wps_pin(message, wpa_s);
308                 else if (!os_strcmp(method, "wpsReg"))
309                         reply = wpas_dbus_iface_wps_reg(message, wpa_s);
310 #endif /* CONFIG_WPS */
311         }
312
313         /* If the message was handled, send back the reply */
314         if (reply) {
315                 if (!dbus_message_get_no_reply(message))
316                         dbus_connection_send(connection, reply, NULL);
317                 dbus_message_unref(reply);
318         }
319
320 out:
321         os_free(iface_obj_path);
322         os_free(network);
323         os_free(bssid);
324         return reply ? DBUS_HANDLER_RESULT_HANDLED :
325                 DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
326 }
327
328
329 /**
330  * wpas_message_handler - dispatch incoming dbus messages
331  * @connection: connection to the system message bus
332  * @message: an incoming dbus message
333  * @user_data: a pointer to a dbus control interface data structure
334  * Returns: whether or not the message was handled
335  *
336  * This function dispatches all incoming dbus messages to the correct
337  * handlers, depending on what the message's target object path is,
338  * and what the method call is.
339  */
340 static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
341         DBusMessage *message, void *user_data)
342 {
343         struct wpas_dbus_priv *ctrl_iface = user_data;
344         const char *method;
345         const char *path;
346         const char *msg_interface;
347         DBusMessage *reply = NULL;
348
349         method = dbus_message_get_member(message);
350         path = dbus_message_get_path(message);
351         msg_interface = dbus_message_get_interface(message);
352         if (!method || !path || !ctrl_iface || !msg_interface)
353                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
354
355         /* Validate the method interface */
356         if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
357                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
358
359         if (!strcmp(path, WPAS_DBUS_PATH)) {
360                 /* dispatch methods against our global dbus interface here */
361                 if (!strcmp(method, "addInterface")) {
362                         reply = wpas_dbus_global_add_interface(
363                                 message, ctrl_iface->global);
364                 } else if (!strcmp(method, "removeInterface")) {
365                         reply = wpas_dbus_global_remove_interface(
366                                 message, ctrl_iface->global);
367                 } else if (!strcmp(method, "getInterface")) {
368                         reply = wpas_dbus_global_get_interface(
369                                 message, ctrl_iface->global);
370                 } else if (!strcmp(method, "setDebugParams")) {
371                         reply = wpas_dbus_global_set_debugparams(
372                                 message, ctrl_iface->global);
373                 }
374         }
375
376         /* If the message was handled, send back the reply */
377         if (reply) {
378                 if (!dbus_message_get_no_reply(message))
379                         dbus_connection_send(connection, reply, NULL);
380                 dbus_message_unref(reply);
381         }
382
383         return reply ? DBUS_HANDLER_RESULT_HANDLED :
384                 DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
385 }
386
387
388 /**
389  * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
390  * @wpa_s: %wpa_supplicant network interface data
391  * Returns: 0 on success, -1 on failure
392  *
393  * Notify listeners that this interface has updated scan results.
394  */
395 void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
396 {
397         struct wpas_dbus_priv *iface = wpa_s->global->dbus;
398         DBusMessage *_signal;
399         const char *path;
400
401         /* Do nothing if the control interface is not turned on */
402         if (iface == NULL)
403                 return;
404
405         path = wpa_supplicant_get_dbus_path(wpa_s);
406         if (path == NULL) {
407                 perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
408                        "interface didn't have a dbus path");
409                 wpa_printf(MSG_ERROR,
410                            "wpa_supplicant_dbus_notify_scan_results[dbus]: "
411                            "interface didn't have a dbus path; can't send "
412                            "scan result signal.");
413                 return;
414         }
415         _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
416                                           "ScanResultsAvailable");
417         if (_signal == NULL) {
418                 perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
419                        "couldn't create dbus signal; likely out of memory");
420                 wpa_printf(MSG_ERROR, "dbus control interface: not enough "
421                            "memory to send scan results signal.");
422                 return;
423         }
424         dbus_connection_send(iface->con, _signal, NULL);
425         dbus_message_unref(_signal);
426 }
427
428
429 /**
430  * wpa_supplicant_dbus_notify_state_change - Send a state change signal
431  * @wpa_s: %wpa_supplicant network interface data
432  * @new_state: new state wpa_supplicant is entering
433  * @old_state: old state wpa_supplicant is leaving
434  * Returns: 0 on success, -1 on failure
435  *
436  * Notify listeners that wpa_supplicant has changed state
437  */
438 void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
439                                              enum wpa_states new_state,
440                                              enum wpa_states old_state)
441 {
442         struct wpas_dbus_priv *iface;
443         DBusMessage *_signal = NULL;
444         const char *path;
445         const char *new_state_str, *old_state_str;
446
447         /* Do nothing if the control interface is not turned on */
448         if (wpa_s->global == NULL)
449                 return;
450         iface = wpa_s->global->dbus;
451         if (iface == NULL)
452                 return;
453
454         /* Only send signal if state really changed */
455         if (new_state == old_state)
456                 return;
457
458         path = wpa_supplicant_get_dbus_path(wpa_s);
459         if (path == NULL) {
460                 perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
461                        "interface didn't have a dbus path");
462                 wpa_printf(MSG_ERROR,
463                            "wpa_supplicant_dbus_notify_state_change[dbus]: "
464                            "interface didn't have a dbus path; can't send "
465                            "signal.");
466                 return;
467         }
468         _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
469                                           "StateChange");
470         if (_signal == NULL) {
471                 perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
472                        "couldn't create dbus signal; likely out of memory");
473                 wpa_printf(MSG_ERROR,
474                            "wpa_supplicant_dbus_notify_state_change[dbus]: "
475                            "couldn't create dbus signal; likely out of "
476                            "memory.");
477                 return;
478         }
479
480         new_state_str = wpa_supplicant_state_txt(new_state);
481         old_state_str = wpa_supplicant_state_txt(old_state);
482         if (new_state_str == NULL || old_state_str == NULL) {
483                 perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
484                        "couldn't convert state strings");
485                 wpa_printf(MSG_ERROR,
486                            "wpa_supplicant_dbus_notify_state_change[dbus]: "
487                            "couldn't convert state strings.");
488                 goto out;
489         }
490
491         if (!dbus_message_append_args(_signal,
492                                       DBUS_TYPE_STRING, &new_state_str,
493                                       DBUS_TYPE_STRING, &old_state_str,
494                                       DBUS_TYPE_INVALID)) {
495                 perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
496                        "not enough memory to construct state change signal.");
497                 wpa_printf(MSG_ERROR,
498                            "wpa_supplicant_dbus_notify_state_change[dbus]: "
499                            "not enough memory to construct state change "
500                            "signal.");
501                 goto out;
502         }
503
504         dbus_connection_send(iface->con, _signal, NULL);
505
506 out:
507         dbus_message_unref(_signal);
508 }
509
510
511 /**
512  * wpa_supplicant_dbus_notify_scanning - send scanning status
513  * @wpa_s: %wpa_supplicant network interface data
514  * Returns: 0 on success, -1 on failure
515  *
516  * Notify listeners of interface scanning state changes
517  */
518 void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
519 {
520         struct wpas_dbus_priv *iface = wpa_s->global->dbus;
521         DBusMessage *_signal;
522         const char *path;
523         dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
524
525         /* Do nothing if the control interface is not turned on */
526         if (iface == NULL)
527                 return;
528
529         path = wpa_supplicant_get_dbus_path(wpa_s);
530         if (path == NULL) {
531                 perror("wpa_supplicant_dbus_notify_scanning[dbus]: interface "
532                        "didn't have a dbus path");
533                 wpa_printf(MSG_ERROR,
534                            "%s[dbus]: interface didn't have a dbus path; "
535                            "can't send scanning signal.", __FUNCTION__);
536                 return;
537         }
538         _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
539                                           "Scanning");
540         if (_signal == NULL) {
541                 perror("wpa_supplicant_dbus_notify_scanning[dbus]: couldn't "
542                        "create dbus signal; likely out of memory");
543                 wpa_printf(MSG_ERROR, "%s[dbus]: dbus control interface: not "
544                            "enough memory to send scan results signal.",
545                            __FUNCTION__);
546                 return;
547         }
548
549         if (dbus_message_append_args(_signal,
550                                      DBUS_TYPE_BOOLEAN, &scanning,
551                                      DBUS_TYPE_INVALID)) {
552                 dbus_connection_send(iface->con, _signal, NULL);
553         } else {
554                 perror("wpa_supplicant_dbus_notify_scanning[dbus]: not enough "
555                        "memory to construct signal.");
556                 wpa_printf(MSG_ERROR, "%s[dbus]: not enough memory to "
557                            "construct signal.", __FUNCTION__);
558         }
559         dbus_message_unref(_signal);
560 }
561
562
563 #ifdef CONFIG_WPS
564 void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
565                                          const struct wps_credential *cred)
566 {
567         struct wpas_dbus_priv *iface;
568         DBusMessage *_signal = NULL;
569         const char *path;
570
571         /* Do nothing if the control interface is not turned on */
572         if (wpa_s->global == NULL)
573                 return;
574         iface = wpa_s->global->dbus;
575         if (iface == NULL)
576                 return;
577
578         path = wpa_supplicant_get_dbus_path(wpa_s);
579         if (path == NULL) {
580                 perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: "
581                        "interface didn't have a dbus path");
582                 wpa_printf(MSG_ERROR,
583                            "wpa_supplicant_dbus_notify_wps_cred[dbus]: "
584                            "interface didn't have a dbus path; can't send "
585                            "signal.");
586                 return;
587         }
588         _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
589                                           "WpsCred");
590         if (_signal == NULL) {
591                 perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: "
592                        "couldn't create dbus signal; likely out of memory");
593                 wpa_printf(MSG_ERROR,
594                            "wpa_supplicant_dbus_notify_wps_cred[dbus]: "
595                            "couldn't create dbus signal; likely out of "
596                            "memory.");
597                 return;
598         }
599
600         if (!dbus_message_append_args(_signal,
601                                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
602                                       &cred->cred_attr, cred->cred_attr_len,
603                                       DBUS_TYPE_INVALID)) {
604                 perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: "
605                        "not enough memory to construct signal.");
606                 wpa_printf(MSG_ERROR,
607                            "wpa_supplicant_dbus_notify_wps_cred[dbus]: "
608                            "not enough memory to construct signal.");
609                 goto out;
610         }
611
612         dbus_connection_send(iface->con, _signal, NULL);
613
614 out:
615         dbus_message_unref(_signal);
616 }
617 #else /* CONFIG_WPS */
618 void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
619                                          const struct wps_credential *cred)
620 {
621 }
622 #endif /* CONFIG_WPS */
623
624
625 /**
626  * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
627  * @global: Pointer to global data from wpa_supplicant_init()
628  * Returns: 0 on success, -1 on failure
629  *
630  * Initialize the dbus control interface and start receiving commands from
631  * external programs over the bus.
632  */
633 int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
634 {
635         DBusError error;
636         int ret = -1;
637         DBusObjectPathVTable wpas_vtable = {
638                 NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
639         };
640
641         /* Register the message handler for the global dbus interface */
642         if (!dbus_connection_register_object_path(iface->con,
643                                                   WPAS_DBUS_PATH, &wpas_vtable,
644                                                   iface)) {
645                 perror("dbus_connection_register_object_path[dbus]");
646                 wpa_printf(MSG_ERROR, "Could not set up DBus message "
647                            "handler.");
648                 return -1;
649         }
650
651         /* Register our service with the message bus */
652         dbus_error_init(&error);
653         switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
654                                       0, &error)) {
655         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
656                 ret = 0;
657                 break;
658         case DBUS_REQUEST_NAME_REPLY_EXISTS:
659         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
660         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
661                 perror("dbus_bus_request_name[dbus]");
662                 wpa_printf(MSG_ERROR, "Could not request DBus service name: "
663                            "already registered.");
664                 break;
665         default:
666                 perror("dbus_bus_request_name[dbus]");
667                 wpa_printf(MSG_ERROR, "Could not request DBus service name: "
668                            "%s %s.", error.name, error.message);
669                 break;
670         }
671         dbus_error_free(&error);
672
673         if (ret != 0)
674                 return -1;
675
676         wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
677                    "'.");
678
679         return 0;
680 }
681
682
683 /**
684  * wpas_dbus_register_new_iface - Register a new interface with dbus
685  * @wpa_s: %wpa_supplicant interface description structure to register
686  * Returns: 0 on success, -1 on error
687  *
688  * Registers a new interface with dbus and assigns it a dbus object path.
689  */
690 int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
691 {
692         struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
693         DBusConnection * con;
694         u32 next;
695         DBusObjectPathVTable vtable = {
696                 NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
697         };
698         char *path;
699         int ret = -1;
700
701         /* Do nothing if the control interface is not turned on */
702         if (ctrl_iface == NULL)
703                 return 0;
704
705         con = ctrl_iface->con;
706         next = ctrl_iface->next_objid++;
707
708         /* Create and set the interface's object path */
709         path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
710         if (path == NULL)
711                 return -1;
712         snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
713                  WPAS_DBUS_PATH_INTERFACES "/%u",
714                  next);
715         if (wpa_supplicant_set_dbus_path(wpa_s, path)) {
716                 wpa_printf(MSG_DEBUG,
717                            "Failed to set dbus path for interface %s",
718                            wpa_s->ifname);
719                 goto out;
720         }
721
722         /* Register the message handler for the interface functions */
723         if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) {
724                 perror("wpas_dbus_register_iface [dbus]");
725                 wpa_printf(MSG_ERROR, "Could not set up DBus message "
726                            "handler for interface %s.", wpa_s->ifname);
727                 goto out;
728         }
729         ret = 0;
730
731 out:
732         os_free(path);
733         return ret;
734 }
735
736
737 /**
738  * wpas_dbus_unregister_iface - Unregister an interface from dbus
739  * @wpa_s: wpa_supplicant interface structure
740  * Returns: 0 on success, -1 on failure
741  *
742  * Unregisters the interface with dbus
743  */
744 int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
745 {
746         struct wpas_dbus_priv *ctrl_iface;
747         DBusConnection *con;
748         const char *path;
749
750         /* Do nothing if the control interface is not turned on */
751         if (wpa_s == NULL || wpa_s->global == NULL)
752                 return 0;
753         ctrl_iface = wpa_s->global->dbus;
754         if (ctrl_iface == NULL)
755                 return 0;
756
757         con = ctrl_iface->con;
758         path = wpa_supplicant_get_dbus_path(wpa_s);
759
760         if (!dbus_connection_unregister_object_path(con, path))
761                 return -1;
762
763         os_free(wpa_s->dbus_path);
764         wpa_s->dbus_path = NULL;
765
766         return 0;
767 }
768
769
770 /**
771  * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
772  * @global: Pointer to global data from wpa_supplicant_init()
773  * @path: Pointer to a dbus object path representing an interface
774  * Returns: Pointer to the interface or %NULL if not found
775  */
776 struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
777         struct wpa_global *global, const char *path)
778 {
779         struct wpa_supplicant *wpa_s;
780
781         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
782                 if (strcmp(wpa_s->dbus_path, path) == 0)
783                         return wpa_s;
784         }
785         return NULL;
786 }
787
788
789 /**
790  * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface
791  * @wpa_s: wpa_supplicant interface structure
792  * @path: dbus path to set on the interface
793  * Returns: 0 on succes, -1 on error
794  */
795 int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s,
796                                   const char *path)
797 {
798         u32 len = strlen (path);
799         if (len >= WPAS_DBUS_OBJECT_PATH_MAX)
800                 return -1;
801         if (wpa_s->dbus_path)
802                 return -1;
803         wpa_s->dbus_path = os_strdup(path);
804         return 0;
805 }
806
807
808 /**
809  * wpa_supplicant_get_dbus_path - Get an interface's dbus path
810  * @wpa_s: %wpa_supplicant interface structure
811  * Returns: Interface's dbus object path, or %NULL on error
812  */
813 const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s)
814 {
815         return wpa_s->dbus_path;
816 }