dbus: Do not include libdbus dbus/dbus.h into dbus_{old,new}.h
[libeap.git] / wpa_supplicant / dbus / dbus_new.c
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
5  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * Alternatively, this software may be distributed under the terms of BSD
12  * license.
13  *
14  * See README and COPYING for more details.
15  */
16
17 #include "includes.h"
18
19 #include "common.h"
20 #include "wps/wps.h"
21 #include "../config.h"
22 #include "../wpa_supplicant_i.h"
23 #include "../bss.h"
24 #include "dbus_new_helpers.h"
25 #include "dbus_dict_helpers.h"
26 #include "dbus_new.h"
27 #include "dbus_new_handlers.h"
28 #include "dbus_common.h"
29 #include "dbus_common_i.h"
30
31 /**
32  * wpas_dbus_set_path - Assign a dbus path to an interface
33  * @wpa_s: wpa_supplicant interface structure
34  * @path: dbus path to set on the interface
35  * Returns: 0 on success, -1 on error
36  */
37 static int wpas_dbus_set_path(struct wpa_supplicant *wpa_s,
38                               const char *path)
39 {
40         u32 len = os_strlen(path);
41         if (len >= WPAS_DBUS_OBJECT_PATH_MAX)
42                 return -1;
43         if (wpa_s->dbus_new_path)
44                 return -1;
45         wpa_s->dbus_new_path = os_strdup(path);
46         return 0;
47 }
48
49
50 /**
51  * wpas_dbus_signal_interface - Send a interface related event signal
52  * @wpa_s: %wpa_supplicant network interface data
53  * @sig_name: signal name - InterfaceAdded or InterfaceRemoved
54  * @properties: determines if add second argument with object properties
55  *
56  * Notify listeners about event related with interface
57  */
58 static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
59                                        const char *sig_name, int properties)
60 {
61         struct wpas_dbus_priv *iface;
62         DBusMessage *_signal;
63         DBusMessageIter iter, iter_dict;
64         const char *path;
65
66         iface = wpa_s->global->dbus;
67
68         /* Do nothing if the control interface is not turned on */
69         if (iface == NULL)
70                 return;
71
72         path = wpas_dbus_get_path(wpa_s);
73         if (path == NULL) {
74                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_interface[dbus]: "
75                            "Interface doesn't have a dbus path. "
76                            "Can't send signal.");
77                 return;
78         }
79         _signal = dbus_message_new_signal(WPAS_DBUS_NEW_PATH,
80                                           WPAS_DBUS_NEW_INTERFACE, sig_name);
81         if (_signal == NULL) {
82                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_interface[dbus]: "
83                            "enough memory to send scan results signal.");
84                 return;
85         }
86
87         dbus_message_iter_init_append(_signal, &iter);
88
89         if(!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
90                                            &path))
91                 goto err;
92
93         if (properties) {
94                 if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
95                         goto err;
96
97                 wpa_dbus_get_object_properties(iface, path,
98                                                WPAS_DBUS_NEW_IFACE_INTERFACE,
99                                                &iter_dict);
100
101                 if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
102                         goto err;
103         }
104
105         dbus_connection_send(iface->con, _signal, NULL);
106
107         dbus_message_unref(_signal);
108         return;
109
110 err:
111         wpa_printf(MSG_ERROR, "wpas_dbus_signal_interface[dbus]: "
112                    "not enough memory to construct signal.");
113         dbus_message_unref(_signal);
114 }
115
116
117 /**
118  * wpas_dbus_signal_interface_added - Send a interface created signal
119  * @wpa_s: %wpa_supplicant network interface data
120  *
121  * Notify listeners about creating new interface
122  */
123 static void wpas_dbus_signal_interface_added(struct wpa_supplicant *wpa_s)
124 {
125         wpas_dbus_signal_interface(wpa_s, "InterfaceAdded", TRUE);
126 }
127
128
129 /**
130  * wpas_dbus_signal_interface_removed - Send a interface removed signal
131  * @wpa_s: %wpa_supplicant network interface data
132  *
133  * Notify listeners about removing interface
134  */
135 static void wpas_dbus_signal_interface_removed(struct wpa_supplicant *wpa_s)
136 {
137         wpas_dbus_signal_interface(wpa_s, "InterfaceRemoved", FALSE);
138
139 }
140
141
142 /**
143  * wpas_dbus_signal_scan_done - send scan done signal
144  * @wpa_s: %wpa_supplicant network interface data
145  * @success: indicates if scanning succeed or failed
146  *
147  * Notify listeners about finishing a scan
148  */
149 static void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s,
150                                        int success)
151 {
152         struct wpas_dbus_priv *iface;
153         DBusMessage *_signal;
154         const char *path;
155         dbus_bool_t succ;
156
157         iface = wpa_s->global->dbus;
158
159         /* Do nothing if the control interface is not turned on */
160         if (iface == NULL)
161                 return;
162
163         path = wpas_dbus_get_path(wpa_s);
164         if (path == NULL) {
165                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_scan_done[dbus]: "
166                            "Interface doesn't have a dbus path. "
167                            "Can't send signal.");
168                 return;
169         }
170         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE,
171                                           "ScanDone");
172         if (_signal == NULL) {
173                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_scan_done[dbus]: "
174                            "enough memory to send signal.");
175                 return;
176         }
177
178         succ = success ? TRUE : FALSE;
179         if (dbus_message_append_args(_signal, DBUS_TYPE_BOOLEAN, &succ,
180                                      DBUS_TYPE_INVALID)) {
181                 dbus_connection_send(iface->con, _signal, NULL);
182         } else {
183                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_scan_done[dbus]: "
184                            "not enough memory to construct signal.");
185         }
186         dbus_message_unref(_signal);
187 }
188
189
190 /**
191  * wpas_dbus_signal_blob - Send a BSS related event signal
192  * @wpa_s: %wpa_supplicant network interface data
193  * @bss_obj_path: BSS object path
194  * @sig_name: signal name - BSSAdded or BSSRemoved
195  * @properties: determines if add second argument with object properties
196  *
197  * Notify listeners about event related with BSS
198  */
199 static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
200                                  const char *bss_obj_path,
201                                  const char *sig_name, int properties)
202 {
203         struct wpas_dbus_priv *iface;
204         DBusMessage *_signal;
205         DBusMessageIter iter, iter_dict;
206         const char *path;
207
208         iface = wpa_s->global->dbus;
209
210         /* Do nothing if the control interface is not turned on */
211         if (iface == NULL)
212                 return;
213
214         path = wpas_dbus_get_path(wpa_s);
215         if (path == NULL) {
216                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_bss[dbus]: "
217                            "Interface doesn't have a dbus path. "
218                            "Can't send signal.");
219                 return;
220         }
221         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE,
222                                           sig_name);
223         if (_signal == NULL) {
224                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_bss[dbus]: "
225                            "enough memory to send signal.");
226                 return;
227         }
228
229         dbus_message_iter_init_append(_signal, &iter);
230
231         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
232                                             &bss_obj_path))
233                 goto err;
234
235         if (properties) {
236                 if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
237                         goto err;
238
239                 wpa_dbus_get_object_properties(iface, bss_obj_path,
240                                                WPAS_DBUS_NEW_IFACE_BSSID,
241                                                &iter_dict);
242
243                 if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
244                         goto err;
245         }
246
247         dbus_connection_send(iface->con, _signal, NULL);
248
249         dbus_message_unref(_signal);
250         return;
251
252 err:
253         wpa_printf(MSG_ERROR, "wpas_dbus_signal_bss[dbus]: "
254                    "not enough memory to construct signal.");
255         dbus_message_unref(_signal);
256 }
257
258
259 /**
260  * wpas_dbus_signal_bss_added - Send a BSS added signal
261  * @wpa_s: %wpa_supplicant network interface data
262  * @bss_obj_path: new BSS object path
263  *
264  * Notify listeners about adding new BSS
265  */
266 static void wpas_dbus_signal_bss_added(struct wpa_supplicant *wpa_s,
267                                        const char *bss_obj_path)
268 {
269         wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSAdded", TRUE);
270 }
271
272
273 /**
274  * wpas_dbus_signal_bss_removed - Send a BSS removed signal
275  * @wpa_s: %wpa_supplicant network interface data
276  * @bss_obj_path: BSS object path
277  *
278  * Notify listeners about removing BSS
279  */
280 static void wpas_dbus_signal_bss_removed(struct wpa_supplicant *wpa_s,
281                                          const char *bss_obj_path)
282 {
283         wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSRemoved", FALSE);
284 }
285
286
287 /**
288  * wpas_dbus_signal_blob - Send a blob related event signal
289  * @wpa_s: %wpa_supplicant network interface data
290  * @name: blob name
291  * @sig_name: signal name - BlobAdded or BlobRemoved
292  *
293  * Notify listeners about event related with blob
294  */
295 static void wpas_dbus_signal_blob(struct wpa_supplicant *wpa_s,
296                                   const char *name, const char *sig_name)
297 {
298         struct wpas_dbus_priv *iface;
299         DBusMessage *_signal;
300         const char *path;
301
302         iface = wpa_s->global->dbus;
303
304         /* Do nothing if the control interface is not turned on */
305         if (iface == NULL)
306                 return;
307
308         path = wpas_dbus_get_path(wpa_s);
309         if (path == NULL) {
310                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_blob[dbus]: "
311                            "Interface doesn't have a dbus path. "
312                            "Can't send signal.");
313                 return;
314         }
315         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE,
316                                           sig_name);
317         if (_signal == NULL) {
318                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_blob[dbus]: "
319                            "enough memory to send signal.");
320                 return;
321         }
322
323         if (dbus_message_append_args(_signal, DBUS_TYPE_STRING, &name,
324                                      DBUS_TYPE_INVALID)) {
325                 dbus_connection_send(iface->con, _signal, NULL);
326         } else {
327                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_blob[dbus]: "
328                            "not enough memory to construct signal.");
329         }
330         dbus_message_unref(_signal);
331 }
332
333
334 /**
335  * wpas_dbus_signal_blob_added - Send a blob added signal
336  * @wpa_s: %wpa_supplicant network interface data
337  * @name: blob name
338  *
339  * Notify listeners about adding a new blob
340  */
341 static void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
342                                         const char *name)
343 {
344         wpas_dbus_signal_blob(wpa_s, name, "BlobAdded");
345 }
346
347
348 /**
349  * wpas_dbus_signal_blob_removed - Send a blob removed signal
350  * @wpa_s: %wpa_supplicant network interface data
351  * @name: blob name
352  *
353  * Notify listeners about removing blob
354  */
355 static void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
356                                           const char *name)
357 {
358         wpas_dbus_signal_blob(wpa_s, name, "BlobRemoved");
359 }
360
361
362 /**
363  * wpas_dbus_signal_network - Send a network related event signal
364  * @wpa_s: %wpa_supplicant network interface data
365  * @id: new network id
366  * @sig_name: signal name - NetworkAdded, NetworkRemoved or NetworkSelected
367  * @properties: determines if add second argument with object properties
368  *
369  * Notify listeners about event related with configured network
370  */
371 static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
372                                      int id, const char *sig_name,
373                                      int properties)
374 {
375         struct wpas_dbus_priv *iface;
376         DBusMessage *_signal;
377         DBusMessageIter iter, iter_dict;
378         const char *path;
379         char *net_obj_path;
380
381         iface = wpa_s->global->dbus;
382
383         /* Do nothing if the control interface is not turned on */
384         if (iface == NULL)
385                 return;
386
387         path = wpas_dbus_get_path(wpa_s);
388         if (path == NULL) {
389                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_network[dbus]: "
390                            "Interface doesn't have a dbus path. "
391                            "Can't send signal.");
392                 return;
393         }
394
395         net_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
396         if (net_obj_path == NULL)
397                 return;
398         os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
399                     "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", path, id);
400
401         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE,
402                                           sig_name);
403         if (_signal == NULL) {
404                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_network[dbus]: "
405                            "enough memory to send signal.");
406                 os_free(net_obj_path);
407                 return;
408         }
409
410         dbus_message_iter_init_append(_signal, &iter);
411
412         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
413                                             &net_obj_path))
414                 goto err;
415
416         if (properties) {
417                 if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
418                         goto err;
419
420                 wpa_dbus_get_object_properties(iface, net_obj_path,
421                                                WPAS_DBUS_NEW_IFACE_NETWORK,
422                                                &iter_dict);
423
424                 if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
425                         goto err;
426         }
427
428         dbus_connection_send(iface->con, _signal, NULL);
429
430         os_free(net_obj_path);
431         dbus_message_unref(_signal);
432         return;
433
434 err:
435         wpa_printf(MSG_ERROR, "wpas_dbus_signal_network[dbus]: "
436                    "not enough memory to construct signal.");
437         os_free(net_obj_path);
438         dbus_message_unref(_signal);
439 }
440
441
442 /**
443  * wpas_dbus_signal_network_added - Send a network added signal
444  * @wpa_s: %wpa_supplicant network interface data
445  * @id: new network id
446  *
447  * Notify listeners about adding new network
448  */
449 static void wpas_dbus_signal_network_added(struct wpa_supplicant *wpa_s,
450                                            int id)
451 {
452         wpas_dbus_signal_network(wpa_s, id, "NetworkAdded", TRUE);
453 }
454
455
456 /**
457  * wpas_dbus_signal_network_removed - Send a network removed signal
458  * @wpa_s: %wpa_supplicant network interface data
459  * @id: network id
460  *
461  * Notify listeners about removing a network
462  */
463 static void wpas_dbus_signal_network_removed(struct wpa_supplicant *wpa_s,
464                                              int id)
465 {
466         wpas_dbus_signal_network(wpa_s, id, "NetworkRemoved", FALSE);
467 }
468
469
470 /**
471  * wpas_dbus_signal_network_selected - Send a network selected signal
472  * @wpa_s: %wpa_supplicant network interface data
473  * @id: network id
474  *
475  * Notify listeners about selecting a network
476  */
477 static void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s,
478                                               int id)
479 {
480         wpas_dbus_signal_network(wpa_s, id, "NetworkSelected", FALSE);
481 }
482
483
484 /**
485  * wpas_dbus_signal_state_changed - Send a state changed signal
486  * @wpa_s: %wpa_supplicant network interface data
487  * @new_state: new state wpa_supplicant is entering
488  * @old_state: old state wpa_supplicant is leaving
489  *
490  * Notify listeners that wpa_supplicant has changed state
491  */
492 static void wpas_dbus_signal_state_changed(struct wpa_supplicant *wpa_s,
493                                            enum wpa_states new_state,
494                                            enum wpa_states old_state)
495 {
496         struct wpas_dbus_priv *iface;
497         DBusMessage *_signal = NULL;
498         const char *path;
499         char *new_state_str, *old_state_str;
500         char *tmp;
501
502         /* Do nothing if the control interface is not turned on */
503         if (wpa_s->global == NULL)
504                 return;
505         iface = wpa_s->global->dbus;
506         if (iface == NULL)
507                 return;
508
509         /* Only send signal if state really changed */
510         if (new_state == old_state)
511                 return;
512
513         path = wpas_dbus_get_path(wpa_s);
514         if (path == NULL) {
515                 perror("wpas_dbus_signal_state_changed[dbus]: "
516                        "interface didn't have a dbus path");
517                 wpa_printf(MSG_ERROR,
518                            "wpas_dbus_signal_state_changed[dbus]: "
519                            "interface didn't have a dbus path; can't send "
520                            "signal.");
521                 return;
522         }
523         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE,
524                                           "StateChanged");
525         if (_signal == NULL) {
526                 perror("wpas_dbus_signal_state_changed[dbus]: "
527                        "couldn't create dbus signal; likely out of memory");
528                 wpa_printf(MSG_ERROR,
529                            "wpas_dbus_signal_state_changed[dbus]: "
530                            "couldn't create dbus signal; likely out of "
531                            "memory.");
532                 return;
533         }
534
535         new_state_str = os_strdup(wpa_supplicant_state_txt(new_state));
536         old_state_str = os_strdup(wpa_supplicant_state_txt(old_state));
537         if (new_state_str == NULL || old_state_str == NULL) {
538                 perror("wpas_dbus_signal_state_changed[dbus]: "
539                        "couldn't convert state strings");
540                 wpa_printf(MSG_ERROR,
541                            "wpas_dbus_signal_state_changed[dbus]: "
542                            "couldn't convert state strings.");
543                 goto out;
544         }
545
546         /* make state string lowercase to fit new DBus API convention */
547         tmp = new_state_str;
548         while (*tmp) {
549                 *tmp = tolower(*tmp);
550                 tmp++;
551         }
552         tmp = old_state_str;
553         while (*tmp) {
554                 *tmp = tolower(*tmp);
555                 tmp++;
556         }
557
558         if (!dbus_message_append_args(_signal,
559                                       DBUS_TYPE_STRING, &new_state_str,
560                                       DBUS_TYPE_STRING, &old_state_str,
561                                       DBUS_TYPE_INVALID)) {
562                 perror("wpas_dbus_signal_state_changed[dbus]: "
563                        "not enough memory to construct state change signal.");
564                 wpa_printf(MSG_ERROR,
565                            "wpas_dbus_signal_state_changed[dbus]: "
566                            "not enough memory to construct state change "
567                            "signal.");
568                 goto out;
569         }
570
571         dbus_connection_send(iface->con, _signal, NULL);
572
573 out:
574         dbus_message_unref(_signal);
575         os_free(new_state_str);
576         os_free(old_state_str);
577 }
578
579
580 /**
581  * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes
582  * @wpa_s: %wpa_supplicant network interface data
583  * @ssid: configured network which Enabled property has changed
584  *
585  * Sends PropertyChanged signals containing new value of Enabled property
586  * for specified network
587  */
588 static void wpas_dbus_signal_network_enabled_changed(
589         struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
590 {
591
592         struct network_handler_args args = {wpa_s, ssid};
593
594         char path[WPAS_DBUS_OBJECT_PATH_MAX];
595         os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
596                     "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
597                     wpas_dbus_get_path(wpa_s), ssid->id);
598
599         wpa_dbus_signal_property_changed(wpa_s->global->dbus,
600                                          (WPADBusPropertyAccessor)
601                                          wpas_dbus_getter_enabled, &args,
602                                          path, WPAS_DBUS_NEW_IFACE_NETWORK,
603                                          "Enabled");
604 }
605
606
607 #ifdef CONFIG_WPS
608
609 /**
610  * wpas_dbus_signal_wps_event_success - Signals Success WPS event
611  * @wpa_s: %wpa_supplicant network interface data
612  *
613  * Sends Event dbus signal with name "success" and empty dict as arguments
614  */
615 static void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s)
616 {
617
618         DBusMessage *_signal = NULL;
619         DBusMessageIter iter, dict_iter;
620         struct wpas_dbus_priv *iface;
621         char *key = "success";
622         const char *path;
623
624         iface = wpa_s->global->dbus;
625
626         /* Do nothing if the control interface is not turned on */
627         if (iface == NULL)
628                 return;
629
630         path = wpas_dbus_get_path(wpa_s);
631         if (!path) {
632                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_success"
633                            "[dbus]: interface has no dbus path set");
634                 return;
635         }
636
637         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_WPS,
638                                           "Event");
639         if (!_signal) {
640                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_success"
641                            "[dbus]: out of memory when creating a signal");
642                 return;
643         }
644
645         dbus_message_iter_init_append(_signal, &iter);
646
647         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
648             !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
649             !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
650                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_success"
651                            "[dbus]: out of memory");
652                 goto out;
653         }
654
655         dbus_connection_send(iface->con, _signal, NULL);
656 out:
657         dbus_message_unref(_signal);
658 }
659
660
661 /**
662  * wpas_dbus_signal_wps_event_fail - Signals Fail WPS event
663  * @wpa_s: %wpa_supplicant network interface data
664  *
665  * Sends Event dbus signal with name "fail" and dictionary containing
666  * "msg field with fail message number (int32) as arguments
667  */
668 static void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
669                                             struct wps_event_fail *fail)
670 {
671
672         DBusMessage *_signal = NULL;
673         DBusMessageIter iter, dict_iter;
674         struct wpas_dbus_priv *iface;
675         char *key = "fail";
676         const char *path;
677
678         iface = wpa_s->global->dbus;
679
680         /* Do nothing if the control interface is not turned on */
681         if (iface == NULL)
682                 return;
683
684         path = wpas_dbus_get_path(wpa_s);
685         if (!path) {
686                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_fail[dbus]: "
687                            "interface has no dbus path set");
688                 return;
689         }
690
691         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_WPS,
692                                           "Event");
693         if (!_signal) {
694                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_fail[dbus]: "
695                            "out of memory when creating a signal");
696                 return;
697         }
698
699         dbus_message_iter_init_append(_signal, &iter);
700
701         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
702             !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
703             !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
704             !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
705                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_fail[dbus]: "
706                            "out of memory");
707                 goto out;
708         }
709
710         dbus_connection_send(iface->con, _signal, NULL);
711 out:
712         dbus_message_unref(_signal);
713 }
714
715
716 /**
717  * wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event
718  * @wpa_s: %wpa_supplicant network interface data
719  *
720  * Sends Event dbus signal with name "m2d" and dictionary containing
721  * fields of wps_event_m2d structure.
722  */
723 static void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
724                                            struct wps_event_m2d *m2d)
725 {
726
727         DBusMessage *_signal = NULL;
728         DBusMessageIter iter, dict_iter;
729         struct wpas_dbus_priv *iface;
730         char *key = "m2d";
731         const char *path;
732
733         iface = wpa_s->global->dbus;
734
735         /* Do nothing if the control interface is not turned on */
736         if (iface == NULL)
737                 return;
738
739         path = wpas_dbus_get_path(wpa_s);
740         if (!path) {
741                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_m2d[dbus]: "
742                            "interface has no dbus path set");
743                 return;
744         }
745
746         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_WPS,
747                                           "Event");
748         if (!_signal) {
749                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_m2d[dbus]: "
750                            "out of memory when creating a signal");
751                 return;
752         }
753
754         dbus_message_iter_init_append(_signal, &iter);
755
756         if (!(dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) &&
757               wpa_dbus_dict_open_write(&iter, &dict_iter) &&
758               wpa_dbus_dict_append_uint16(&dict_iter, "config_methods",
759                                           m2d->config_methods) &&
760               wpa_dbus_dict_append_byte_array(&dict_iter, "manufacturer",
761                                               (const char *) m2d->manufacturer,
762                                               m2d->manufacturer_len) &&
763               wpa_dbus_dict_append_byte_array(&dict_iter, "model_name",
764                                               (const char *) m2d->model_name,
765                                               m2d->model_name_len) &&
766               wpa_dbus_dict_append_byte_array(&dict_iter, "model_number",
767                                               (const char *) m2d->model_number,
768                                               m2d->model_number_len) &&
769               wpa_dbus_dict_append_byte_array(&dict_iter, "serial_number",
770                                               (const char *)
771                                               m2d->serial_number,
772                                               m2d->serial_number_len) &&
773               wpa_dbus_dict_append_byte_array(&dict_iter, "dev_name",
774                                               (const char *) m2d->dev_name,
775                                               m2d->dev_name_len) &&
776               wpa_dbus_dict_append_byte_array(&dict_iter, "primary_dev_type",
777                                               (const char *)
778                                               m2d->primary_dev_type, 8) &&
779               wpa_dbus_dict_append_uint16(&dict_iter, "config_error",
780                                           m2d->config_error) &&
781               wpa_dbus_dict_append_uint16(&dict_iter, "dev_password_id",
782                                           m2d->dev_password_id) &&
783               wpa_dbus_dict_close_write(&iter, &dict_iter))) {
784                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_m2d[dbus]: "
785                            "out of memory");
786                 goto out;
787         }
788
789         dbus_connection_send(iface->con, _signal, NULL);
790 out:
791         dbus_message_unref(_signal);
792 }
793
794
795 /**
796  * wpas_dbus_signal_wps_cred - Signals new credentials
797  * @wpa_s: %wpa_supplicant network interface data
798  *
799  * Sends signal with credentials in directory argument
800  */
801 static void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
802                                       const struct wps_credential *cred)
803 {
804         DBusMessage *_signal = NULL;
805         DBusMessageIter iter, dict_iter;
806         struct wpas_dbus_priv *iface;
807         const char *path;
808         char *auth_type[6]; /* we have six possible authorization types */
809         int at_num = 0;
810         char *encr_type[4]; /* we have four possible encryption types */
811         int et_num = 0;
812
813         iface = wpa_s->global->dbus;
814
815         /* Do nothing if the control interface is not turned on */
816         if (iface == NULL)
817                 return;
818
819         path = wpas_dbus_get_path(wpa_s);
820         if (!path) {
821                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_cred[dbus]: "
822                            "interface has no dbus path set");
823                 return;
824         }
825
826         _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_WPS,
827                                           "Credentials");
828         if (!_signal) {
829                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_cred[dbus]: "
830                            "out of memory when creating a signal");
831                 return;
832         }
833
834         dbus_message_iter_init_append(_signal, &iter);
835
836         if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
837                 perror("wpas_dbus_signal_wps_cred[dbus]: out of memory "
838                        "when opening a dictionary");
839                 goto nomem;
840         }
841
842         if (cred->auth_type & WPS_AUTH_OPEN)
843                 auth_type[at_num++] = "open";
844         if (cred->auth_type & WPS_AUTH_WPAPSK)
845                 auth_type[at_num++] = "wpa-psk";
846         if (cred->auth_type & WPS_AUTH_SHARED)
847                 auth_type[at_num++] = "shared";
848         if (cred->auth_type & WPS_AUTH_WPA)
849                 auth_type[at_num++] = "wpa-eap";
850         if (cred->auth_type & WPS_AUTH_WPA2)
851                 auth_type[at_num++] = "wpa2-eap";
852         if (cred->auth_type & WPS_AUTH_WPA2PSK)
853                 auth_type[at_num++] =
854                 "wpa2-psk";
855
856         if (cred->encr_type & WPS_ENCR_NONE)
857                 encr_type[et_num++] = "none";
858         if (cred->encr_type & WPS_ENCR_WEP)
859                 encr_type[et_num++] = "wep";
860         if (cred->encr_type & WPS_ENCR_TKIP)
861                 encr_type[et_num++] = "tkip";
862         if (cred->encr_type & WPS_ENCR_AES)
863                 encr_type[et_num++] = "aes";
864
865         if (wpa_s->current_ssid) {
866                 if (!wpa_dbus_dict_append_byte_array(
867                             &dict_iter, "BSSID",
868                             (const char *) wpa_s->current_ssid->bssid,
869                             ETH_ALEN)) {
870                         perror("wpas_dbus_signal_wps_cred[dbus]: out of "
871                                "memory when appending bssid to dictionary");
872                         goto nomem;
873                 }
874         }
875
876         if (!(wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
877                                               (const char *) cred->ssid,
878                                               cred->ssid_len) &&
879               wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
880                                                 (const char **) auth_type,
881                                                 at_num) &&
882               wpa_dbus_dict_append_string_array(&dict_iter, "EncrType",
883                                                 (const char **) encr_type,
884                                                 et_num) &&
885               wpa_dbus_dict_append_byte_array(&dict_iter, "Key",
886                                               (const char *) cred->key,
887                                               cred->key_len) &&
888               wpa_dbus_dict_append_uint32(&dict_iter, "KeyIndex",
889                                           cred->key_idx))) {
890                 perror("wpas_dbus_signal_wps_cred[dbus]: out of memory "
891                        "when appending to dictionary");
892                 goto nomem;
893         }
894
895         if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
896                 perror("wpas_dbus_signal_wps_cred[dbus]: out of memory "
897                        "when closing a dictionary");
898                 goto nomem;
899         }
900
901         dbus_connection_send(iface->con, _signal, NULL);
902
903 nomem:
904         dbus_message_unref(_signal);
905 }
906
907 #endif /* CONFIG_WPS */
908
909
910 /**
911  * wpas_dbus_signal_prop_changed - Signals change of property
912  * @wpa_s: %wpa_supplicant network interface data
913  * @property: indicates which property has changed
914  *
915  * Sends ProertyChanged signals with path, interface and arguments
916  * depending on which property has changed.
917  */
918 static void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
919                                           enum wpas_dbus_prop property)
920 {
921         WPADBusPropertyAccessor getter;
922         char *iface;
923         char *prop;
924         void *arg;
925
926         switch (property) {
927         case WPAS_DBUS_PROP_AP_SCAN:
928                 getter = (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan;
929                 arg = wpa_s;
930                 iface = WPAS_DBUS_NEW_IFACE_INTERFACE;
931                 prop = "ApScan";
932                 break;
933         case WPAS_DBUS_PROP_SCANNING:
934                 getter = (WPADBusPropertyAccessor) wpas_dbus_getter_scanning;
935                 arg = wpa_s;
936                 iface = WPAS_DBUS_NEW_IFACE_INTERFACE;
937                 prop = "Scanning";
938                 break;
939         case WPAS_DBUS_PROP_CURRENT_BSS:
940                 getter = (WPADBusPropertyAccessor)
941                         wpas_dbus_getter_current_bss;
942                 arg = wpa_s;
943                 iface = WPAS_DBUS_NEW_IFACE_INTERFACE;
944                 prop = "CurrentBSS";
945                 break;
946         case WPAS_DBUS_PROP_CURRENT_NETWORK:
947                 getter = (WPADBusPropertyAccessor)
948                         wpas_dbus_getter_current_network;
949                 arg = wpa_s;
950                 iface = WPAS_DBUS_NEW_IFACE_INTERFACE;
951                 prop = "CurrentNetwork";
952                 break;
953         default:
954                 wpa_printf(MSG_ERROR, "wpas_dbus_signal_prop_changed[dbus]: "
955                            "Unknown Property enum value %d", property);
956                 return;
957         }
958
959         wpa_dbus_signal_property_changed(wpa_s->global->dbus,
960                                          getter, arg,
961                                          wpas_dbus_get_path(wpa_s), iface,
962                                          prop);
963 }
964
965
966 /**
967  * wpas_dbus_signal_debug_level_changed - Signals change of debug param
968  * @global: wpa_global structure
969  *
970  * Sends ProertyChanged signals informing that debug level has changed.
971  */
972 static void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
973 {
974         wpa_dbus_signal_property_changed(global->dbus,
975                                          (WPADBusPropertyAccessor)
976                                          wpas_dbus_getter_debug_level,
977                                          global, WPAS_DBUS_NEW_PATH,
978                                          WPAS_DBUS_NEW_INTERFACE,
979                                          "DebugLevel");
980 }
981
982
983 /**
984  * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
985  * @global: wpa_global structure
986  *
987  * Sends ProertyChanged signals informing that debug timestamp has changed.
988  */
989 static void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
990 {
991         wpa_dbus_signal_property_changed(global->dbus,
992                                          (WPADBusPropertyAccessor)
993                                          wpas_dbus_getter_debug_timestamp,
994                                          global, WPAS_DBUS_NEW_PATH,
995                                          WPAS_DBUS_NEW_INTERFACE,
996                                          "DebugTimestamp");
997 }
998
999
1000 /**
1001  * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
1002  * @global: wpa_global structure
1003  *
1004  * Sends ProertyChanged signals informing that debug show_keys has changed.
1005  */
1006 static void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
1007 {
1008         wpa_dbus_signal_property_changed(global->dbus,
1009                                          (WPADBusPropertyAccessor)
1010                                          wpas_dbus_getter_debug_show_keys,
1011                                          global, WPAS_DBUS_NEW_PATH,
1012                                          WPAS_DBUS_NEW_INTERFACE,
1013                                          "DebugShowKeys");
1014 }
1015
1016
1017 struct wpas_dbus_method {
1018         const char *name;
1019         const char *iface;
1020         WPADBusMethodHandler handler;
1021         struct wpa_dbus_argument args[3];
1022 };
1023
1024 struct wpas_dbus_property {
1025         const char *name;
1026         const char *iface;
1027         const char *type;
1028         WPADBusPropertyAccessor getter;
1029         WPADBusPropertyAccessor setter;
1030         enum dbus_prop_access _access;
1031 };
1032
1033 struct wpas_dbus_signal {
1034         const char *name;
1035         const char *iface;
1036         struct wpa_dbus_argument args[3];
1037 };
1038
1039
1040 static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
1041                                void *priv,
1042                                WPADBusArgumentFreeFunction priv_free,
1043                                const struct wpas_dbus_method *methods,
1044                                const struct wpas_dbus_property *properties,
1045                                const struct wpas_dbus_signal *signals)
1046 {
1047         int i;
1048
1049         obj_desc->user_data = priv;
1050         obj_desc->user_data_free_func = priv_free;
1051
1052         for (i = 0; methods && methods[i].name; i++) {
1053                 wpa_dbus_method_register(obj_desc, methods[i].iface,
1054                                          methods[i].name, methods[i].handler,
1055                                          methods[i].args);
1056         }
1057
1058         for (i = 0; properties && properties[i].name; i++) {
1059                 wpa_dbus_property_register(obj_desc, properties[i].iface,
1060                                            properties[i].name,
1061                                            properties[i].type,
1062                                            properties[i].getter,
1063                                            properties[i].setter,
1064                                            properties[i]._access);
1065         }
1066
1067         for (i = 0; signals && signals[i].name; i++) {
1068                 wpa_dbus_signal_register(obj_desc, signals[i].iface,
1069                                          signals[i].name, signals[i].args);
1070         }
1071 }
1072
1073
1074 static const struct wpas_dbus_method wpas_dbus_global_methods[] = {
1075         { "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
1076           (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
1077           {
1078                   { "args", "a{sv}", ARG_IN },
1079                   { "path", "o", ARG_OUT },
1080                   END_ARGS
1081           }
1082         },
1083         { "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
1084           (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
1085           {
1086                   { "path", "o", ARG_IN },
1087                   END_ARGS
1088           }
1089         },
1090         { "GetInterface", WPAS_DBUS_NEW_INTERFACE,
1091           (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
1092           {
1093                   { "ifname", "s", ARG_IN },
1094                   { "path", "o", ARG_OUT },
1095                   END_ARGS
1096           }
1097         },
1098         { NULL, NULL, NULL, { END_ARGS } }
1099 };
1100
1101 static const struct wpas_dbus_property wpas_dbus_global_properties[] = {
1102         { "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "y",
1103           (WPADBusPropertyAccessor) wpas_dbus_getter_debug_level,
1104           (WPADBusPropertyAccessor) wpas_dbus_setter_debug_level,
1105           RW
1106         },
1107         { "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
1108           (WPADBusPropertyAccessor) wpas_dbus_getter_debug_timestamp,
1109           (WPADBusPropertyAccessor) wpas_dbus_setter_debug_timestamp,
1110           RW
1111         },
1112         { "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
1113           (WPADBusPropertyAccessor) wpas_dbus_getter_debug_show_keys,
1114           (WPADBusPropertyAccessor) wpas_dbus_setter_debug_show_keys,
1115           RW
1116         },
1117         { "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
1118           (WPADBusPropertyAccessor) &wpas_dbus_getter_interfaces,
1119           NULL,
1120           R
1121         },
1122         { "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
1123           (WPADBusPropertyAccessor) wpas_dbus_getter_eap_methods,
1124           NULL,
1125           R
1126         },
1127         { NULL, NULL, NULL, NULL, NULL, 0 }
1128 };
1129
1130 static const struct wpas_dbus_signal wpas_dbus_global_signals[] = {
1131         { "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE,
1132           {
1133                   { "path", "o", ARG_OUT },
1134                   { "properties", "a{sv}", ARG_OUT },
1135                   END_ARGS
1136           }
1137         },
1138         { "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE,
1139           {
1140                   { "path", "o", ARG_OUT },
1141                   END_ARGS
1142           }
1143         },
1144         { "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
1145           {
1146                   { "properties", "a{sv}", ARG_OUT },
1147                   END_ARGS
1148           }
1149         },
1150         { NULL, NULL, { END_ARGS } }
1151 };
1152
1153
1154 /**
1155  * wpas_dbus_ctrl_iface_init - Initialize dbus control interface
1156  * @global: Pointer to global data from wpa_supplicant_init()
1157  * Returns: 0 on success or -1 on failure
1158  *
1159  * Initialize the dbus control interface for wpa_supplicantand and start
1160  * receiving commands from external programs over the bus.
1161  */
1162 int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
1163 {
1164         struct wpa_dbus_object_desc *obj_desc;
1165         int ret;
1166
1167         obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
1168         if (!obj_desc) {
1169                 wpa_printf(MSG_ERROR, "Not enough memory "
1170                            "to create object description");
1171                 return -1;
1172         }
1173
1174         wpas_dbus_register(obj_desc, priv->global, NULL,
1175                            wpas_dbus_global_methods,
1176                            wpas_dbus_global_properties,
1177                            wpas_dbus_global_signals);
1178
1179         wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'",
1180                    WPAS_DBUS_NEW_PATH);
1181         ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
1182                                        WPAS_DBUS_NEW_SERVICE,
1183                                        obj_desc);
1184         if (ret < 0)
1185                 free_dbus_object_desc(obj_desc);
1186         else
1187                 priv->dbus_new_initialized = 1;
1188
1189         return ret;
1190 }
1191
1192
1193 /**
1194  * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
1195  * wpa_supplicant
1196  * @iface: Pointer to dbus private data from wpas_dbus_init()
1197  *
1198  * Deinitialize the dbus control interface that was initialized with
1199  * wpas_dbus_ctrl_iface_init().
1200  */
1201 void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface)
1202 {
1203         if (!iface->dbus_new_initialized)
1204                 return;
1205         wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
1206                    WPAS_DBUS_NEW_PATH);
1207         dbus_connection_unregister_object_path(iface->con,
1208                                                WPAS_DBUS_NEW_PATH);
1209 }
1210
1211
1212 static void wpa_dbus_free(void *ptr)
1213 {
1214         os_free(ptr);
1215 }
1216
1217
1218 static const struct wpas_dbus_property wpas_dbus_network_properties[] = {
1219         { "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
1220           (WPADBusPropertyAccessor) wpas_dbus_getter_network_properties,
1221           (WPADBusPropertyAccessor) wpas_dbus_setter_network_properties,
1222           RW
1223         },
1224         { "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
1225           (WPADBusPropertyAccessor) wpas_dbus_getter_enabled,
1226           (WPADBusPropertyAccessor) wpas_dbus_setter_enabled,
1227           RW
1228         },
1229         { NULL, NULL, NULL, NULL, NULL, 0 }
1230 };
1231
1232
1233 static const struct wpas_dbus_signal wpas_dbus_network_signals[] = {
1234         { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
1235           {
1236                   { "properties", "a{sv}", ARG_OUT },
1237                   END_ARGS
1238           }
1239         },
1240         { NULL, NULL, { END_ARGS } }
1241 };
1242
1243
1244 /**
1245  * wpas_dbus_register_network - Register a configured network with dbus
1246  * @wpa_s: wpa_supplicant interface structure
1247  * @ssid: network configuration data
1248  * Returns: 0 on success, -1 on failure
1249  *
1250  * Registers network representing object with dbus
1251  */
1252 static int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
1253                                       struct wpa_ssid *ssid)
1254 {
1255         struct wpas_dbus_priv *ctrl_iface;
1256         struct wpa_dbus_object_desc *obj_desc;
1257
1258         struct network_handler_args *arg = NULL;
1259
1260         char *net_obj_path;
1261
1262         /* Do nothing if the control interface is not turned on */
1263         if (wpa_s == NULL || wpa_s->global == NULL)
1264                 return 0;
1265         ctrl_iface = wpa_s->global->dbus;
1266         if (ctrl_iface == NULL)
1267                 return 0;
1268
1269         net_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1270         if (net_obj_path == NULL)
1271                 return -1;
1272         os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1273                     "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
1274                     wpas_dbus_get_path(wpa_s), ssid->id);
1275
1276         wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'",
1277                    net_obj_path);
1278         obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
1279         if (!obj_desc) {
1280                 wpa_printf(MSG_ERROR, "Not enough memory "
1281                            "to create object description");
1282                 goto err;
1283         }
1284
1285         /* allocate memory for handlers arguments */
1286         arg = os_zalloc(sizeof(struct network_handler_args));
1287         if (!arg) {
1288                 wpa_printf(MSG_ERROR, "Not enough memory "
1289                            "to create arguments for method");
1290                 goto err;
1291         }
1292
1293         arg->wpa_s = wpa_s;
1294         arg->ssid = ssid;
1295
1296         wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
1297                            wpas_dbus_network_properties,
1298                            wpas_dbus_network_signals);
1299
1300         if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path,
1301                                                wpa_s->ifname, obj_desc))
1302                 goto err;
1303
1304         wpas_dbus_signal_network_added(wpa_s, ssid->id);
1305
1306         os_free(net_obj_path);
1307         return 0;
1308
1309 err:
1310         os_free(net_obj_path);
1311         os_free(obj_desc);
1312         os_free(arg);
1313         return -1;
1314 }
1315
1316
1317 /**
1318  * wpas_dbus_unregister_network - Unregister a configured network from dbus
1319  * @wpa_s: wpa_supplicant interface structure
1320  * @nid: network id
1321  * Returns: 0 on success, -1 on failure
1322  *
1323  * Unregisters network representing object from dbus
1324  */
1325 static int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
1326 {
1327         struct wpas_dbus_priv *ctrl_iface;
1328         char *net_obj_path;
1329         int ret;
1330
1331         /* Do nothing if the control interface is not turned on */
1332         if (wpa_s == NULL || wpa_s->global == NULL)
1333                 return 0;
1334         ctrl_iface = wpa_s->global->dbus;
1335         if (ctrl_iface == NULL)
1336                 return 0;
1337
1338         net_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1339         if (net_obj_path == NULL)
1340                 return -1;
1341         os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1342                     "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
1343                     wpas_dbus_get_path(wpa_s), nid);
1344
1345         wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'",
1346                    net_obj_path);
1347         ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path);
1348
1349         if (!ret)
1350                 wpas_dbus_signal_network_removed(wpa_s, nid);
1351
1352         os_free(net_obj_path);
1353         return ret;
1354 }
1355
1356
1357 static const struct wpas_dbus_property wpas_dbus_bss_properties[] = {
1358         { "SSID", WPAS_DBUS_NEW_IFACE_BSSID, "ay",
1359           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ssid,
1360           NULL,
1361           R
1362         },
1363         { "BSSID", WPAS_DBUS_NEW_IFACE_BSSID, "ay",
1364           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_bssid,
1365           NULL,
1366           R
1367         },
1368         { "Privacy", WPAS_DBUS_NEW_IFACE_BSSID, "b",
1369           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_privacy,
1370           NULL,
1371           R
1372         },
1373         { "Mode", WPAS_DBUS_NEW_IFACE_BSSID, "s",
1374           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_mode,
1375           NULL,
1376           R
1377         },
1378         { "Signal", WPAS_DBUS_NEW_IFACE_BSSID, "n",
1379           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_signal,
1380           NULL,
1381           R
1382         },
1383         { "Frequency", WPAS_DBUS_NEW_IFACE_BSSID, "q",
1384           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_frequency,
1385           NULL,
1386           R
1387         },
1388         { "MaxRate", WPAS_DBUS_NEW_IFACE_BSSID, "q",
1389           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_max_rate,
1390           NULL,
1391           R
1392         },
1393         { "WPAIE", WPAS_DBUS_NEW_IFACE_BSSID, "ay",
1394           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_wpaie,
1395           NULL,
1396           R
1397         },
1398         { "RSNIE", WPAS_DBUS_NEW_IFACE_BSSID, "ay",
1399           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rsnie,
1400           NULL,
1401           R
1402         },
1403         { "WPSIE", WPAS_DBUS_NEW_IFACE_BSSID, "ay",
1404           (WPADBusPropertyAccessor) wpas_dbus_getter_bss_wpsie,
1405           NULL,
1406           R
1407         },
1408         { NULL, NULL, NULL, NULL, NULL, 0 }
1409 };
1410
1411
1412 static const struct wpas_dbus_signal wpas_dbus_bss_signals[] = {
1413         { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSSID,
1414           {
1415                   { "properties", "a{sv}", ARG_OUT },
1416                   END_ARGS
1417           }
1418         },
1419         { NULL, NULL, { END_ARGS } }
1420 };
1421
1422
1423 /**
1424  * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus
1425  * @wpa_s: wpa_supplicant interface structure
1426  * @bssid: scanned network bssid
1427  * @id: unique BSS identifier
1428  * Returns: 0 on success, -1 on failure
1429  *
1430  * Unregisters BSS representing object from dbus
1431  */
1432 static int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
1433                                     u8 bssid[ETH_ALEN], unsigned int id)
1434 {
1435         struct wpas_dbus_priv *ctrl_iface;
1436         char *bss_obj_path;
1437
1438         /* Do nothing if the control interface is not turned on */
1439         if (wpa_s == NULL || wpa_s->global == NULL)
1440                 return 0;
1441         ctrl_iface = wpa_s->global->dbus;
1442         if (ctrl_iface == NULL)
1443                 return 0;
1444
1445         bss_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1446         if (bss_obj_path == NULL)
1447                 return -1;
1448
1449         os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1450                     "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
1451                     wpas_dbus_get_path(wpa_s), id);
1452
1453         wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'",
1454                    bss_obj_path);
1455         if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) {
1456                 wpa_printf(MSG_ERROR,
1457                            "Cannot unregister BSSID dbus object %s.",
1458                            bss_obj_path);
1459                 os_free(bss_obj_path);
1460                 return -1;
1461         }
1462
1463         wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
1464
1465         os_free(bss_obj_path);
1466         return 0;
1467 }
1468
1469
1470 /**
1471  * wpas_dbus_register_bss - Register a scanned BSS with dbus
1472  * @wpa_s: wpa_supplicant interface structure
1473  * @bssid: scanned network bssid
1474  * @id: unique BSS identifier
1475  * Returns: 0 on success, -1 on failure
1476  *
1477  * Registers BSS representing object with dbus
1478  */
1479 static int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
1480                                   u8 bssid[ETH_ALEN], unsigned int id)
1481 {
1482         struct wpas_dbus_priv *ctrl_iface;
1483         struct wpa_dbus_object_desc *obj_desc;
1484         char *bss_obj_path;
1485
1486         struct bss_handler_args *arg = NULL;
1487
1488         /* Do nothing if the control interface is not turned on */
1489         if (wpa_s == NULL || wpa_s->global == NULL)
1490                 return 0;
1491         ctrl_iface = wpa_s->global->dbus;
1492         if (ctrl_iface == NULL)
1493                 return 0;
1494
1495         bss_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1496         if (bss_obj_path == NULL)
1497                 return -1;
1498
1499         os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1500                     "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
1501                     wpas_dbus_get_path(wpa_s), id);
1502
1503         obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
1504         if (!obj_desc) {
1505                 wpa_printf(MSG_ERROR, "Not enough memory "
1506                            "to create object description");
1507                 goto err;
1508         }
1509
1510         arg = os_zalloc(sizeof(struct bss_handler_args));
1511         if (!arg) {
1512                 wpa_printf(MSG_ERROR, "Not enough memory "
1513                            "to create arguments for handler");
1514                 goto err;
1515         }
1516         arg->wpa_s = wpa_s;
1517         arg->id = id;
1518
1519         wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
1520                            wpas_dbus_bss_properties,
1521                            wpas_dbus_bss_signals);
1522
1523         wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'",
1524                    bss_obj_path);
1525         if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path,
1526                                                wpa_s->ifname, obj_desc)) {
1527                 wpa_printf(MSG_ERROR,
1528                            "Cannot register BSSID dbus object %s.",
1529                            bss_obj_path);
1530                 goto err;
1531         }
1532
1533         wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
1534
1535         os_free(bss_obj_path);
1536         return 0;
1537
1538 err:
1539         os_free(bss_obj_path);
1540         os_free(obj_desc);
1541         os_free(arg);
1542         return -1;
1543 }
1544
1545
1546 static const struct wpas_dbus_method wpas_dbus_interface_methods[] = {
1547         { "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
1548           (WPADBusMethodHandler) &wpas_dbus_handler_scan,
1549           {
1550                   { "args", "a{sv}", ARG_IN },
1551                   END_ARGS
1552           }
1553         },
1554         { "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
1555           (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
1556           {
1557                   END_ARGS
1558           }
1559         },
1560         { "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
1561           (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
1562           {
1563                   { "args", "a{sv}", ARG_IN },
1564                   { "path", "o", ARG_OUT },
1565                   END_ARGS
1566           }
1567         },
1568         { "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
1569           (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
1570           {
1571                   { "path", "o", ARG_IN },
1572                   END_ARGS
1573           }
1574         },
1575         { "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
1576           (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
1577           {
1578                   { "path", "o", ARG_IN },
1579                   END_ARGS
1580           }
1581         },
1582         { "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
1583           (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
1584           {
1585                   { "name", "s", ARG_IN },
1586                   { "data", "ay", ARG_IN },
1587                   END_ARGS
1588           }
1589         },
1590         { "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
1591           (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
1592           {
1593                   { "name", "s", ARG_IN },
1594                   { "data", "ay", ARG_OUT },
1595                   END_ARGS
1596           }
1597         },
1598         { "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
1599           (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
1600           {
1601                   { "name", "s", ARG_IN },
1602                   END_ARGS
1603           }
1604         },
1605 #ifdef CONFIG_WPS
1606         { "Start", WPAS_DBUS_NEW_IFACE_WPS,
1607           (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
1608           {
1609                   { "args", "a{sv}", ARG_IN },
1610                   { "output", "a{sv}", ARG_OUT },
1611                   END_ARGS
1612           }
1613         },
1614 #endif /* CONFIG_WPS */
1615         { NULL, NULL, NULL, { END_ARGS } }
1616 };
1617
1618 static const struct wpas_dbus_property wpas_dbus_interface_properties[] = {
1619         { "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
1620           (WPADBusPropertyAccessor) wpas_dbus_getter_capabilities,
1621           NULL, R
1622         },
1623         { "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
1624           (WPADBusPropertyAccessor) wpas_dbus_getter_state,
1625           NULL, R
1626         },
1627         { "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
1628           (WPADBusPropertyAccessor) wpas_dbus_getter_scanning,
1629           NULL, R
1630         },
1631         { "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
1632           (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan,
1633           (WPADBusPropertyAccessor) wpas_dbus_setter_ap_scan,
1634           RW
1635         },
1636         { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
1637           (WPADBusPropertyAccessor) wpas_dbus_getter_ifname,
1638           NULL, R
1639         },
1640         { "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
1641           (WPADBusPropertyAccessor) wpas_dbus_getter_driver,
1642           NULL, R
1643         },
1644         { "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
1645           (WPADBusPropertyAccessor) wpas_dbus_getter_bridge_ifname,
1646           NULL, R
1647         },
1648         { "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
1649           (WPADBusPropertyAccessor) wpas_dbus_getter_current_bss,
1650           NULL, R
1651         },
1652         { "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
1653           (WPADBusPropertyAccessor) wpas_dbus_getter_current_network,
1654           NULL, R
1655         },
1656         { "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
1657           (WPADBusPropertyAccessor) wpas_dbus_getter_blobs,
1658           NULL, R
1659         },
1660         { "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
1661           (WPADBusPropertyAccessor) wpas_dbus_getter_bsss,
1662           NULL, R
1663         },
1664         { "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
1665           (WPADBusPropertyAccessor) wpas_dbus_getter_networks,
1666           NULL, R
1667         },
1668 #ifdef CONFIG_WPS
1669         { "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
1670           (WPADBusPropertyAccessor) wpas_dbus_getter_process_credentials,
1671           (WPADBusPropertyAccessor) wpas_dbus_setter_process_credentials,
1672           RW
1673         },
1674 #endif /* CONFIG_WPS */
1675         { NULL, NULL, NULL, NULL, NULL, 0 }
1676 };
1677
1678 static const struct wpas_dbus_signal wpas_dbus_interface_signals[] = {
1679         { "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
1680           {
1681                   { "success", "b", ARG_OUT },
1682                   END_ARGS
1683           }
1684         },
1685         { "StateChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
1686           {
1687                   { "newState", "s", ARG_OUT },
1688                   { "oldState", "s", ARG_OUT },
1689                   END_ARGS
1690           }
1691         },
1692         { "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
1693           {
1694                   { "path", "o", ARG_OUT },
1695                   { "properties", "a{sv}", ARG_OUT },
1696                   END_ARGS
1697           }
1698         },
1699         { "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
1700           {
1701                   { "path", "o", ARG_OUT },
1702                   END_ARGS
1703           }
1704         },
1705         { "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
1706           {
1707                   { "name", "s", ARG_OUT },
1708                   END_ARGS
1709           }
1710         },
1711         { "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
1712           {
1713                   { "name", "s", ARG_OUT },
1714                   END_ARGS
1715           }
1716         },
1717         { "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
1718           {
1719                   { "path", "o", ARG_OUT },
1720                   { "properties", "a{sv}", ARG_OUT },
1721                   END_ARGS
1722           }
1723         },
1724         { "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
1725           {
1726                   { "path", "o", ARG_OUT },
1727                   END_ARGS
1728           }
1729         },
1730         { "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE,
1731           {
1732                   { "path", "o", ARG_OUT },
1733                   END_ARGS
1734           }
1735         },
1736         { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
1737           {
1738                   { "properties", "a{sv}", ARG_OUT },
1739                   END_ARGS
1740           }
1741         },
1742 #ifdef CONFIG_WPS
1743         { "Event", WPAS_DBUS_NEW_IFACE_WPS,
1744           {
1745                   { "name", "s", ARG_OUT },
1746                   { "args", "a{sv}", ARG_OUT },
1747                   END_ARGS
1748           }
1749         },
1750         { "Credentials", WPAS_DBUS_NEW_IFACE_WPS,
1751           {
1752                   { "credentials", "a{sv}", ARG_OUT },
1753                   END_ARGS
1754           }
1755         },
1756         { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
1757           {
1758                   { "properties", "a{sv}", ARG_OUT },
1759                   END_ARGS
1760           }
1761         },
1762 #endif /* CONFIG_WPS */
1763         { NULL, NULL, { END_ARGS } }
1764 };
1765
1766
1767 static int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
1768 {
1769
1770         struct wpa_dbus_object_desc *obj_desc = NULL;
1771         char *path;
1772         struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
1773         int next;
1774
1775         /* Do nothing if the control interface is not turned on */
1776         if (ctrl_iface == NULL)
1777                 return 0;
1778
1779         /* Create and set the interface's object path */
1780         path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1781         if (path == NULL)
1782                 return -1;
1783         next = ctrl_iface->next_objid++;
1784         os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1785                     WPAS_DBUS_NEW_PATH_INTERFACES "/%u",
1786                     next);
1787         if (wpas_dbus_set_path(wpa_s, path)) {
1788                 wpa_printf(MSG_DEBUG,
1789                            "Failed to set dbus path for interface %s",
1790                            wpa_s->ifname);
1791                 goto err;
1792         }
1793
1794         obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
1795         if (!obj_desc) {
1796                 wpa_printf(MSG_ERROR, "Not enough memory "
1797                            "to create object description");
1798                 goto err;
1799         }
1800
1801         wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
1802                            wpas_dbus_interface_properties,
1803                            wpas_dbus_interface_signals);
1804
1805         wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'", path);
1806         if (wpa_dbus_register_object_per_iface(ctrl_iface, path, wpa_s->ifname,
1807                                                obj_desc))
1808                 goto err;
1809
1810         wpas_dbus_signal_interface_added(wpa_s);
1811
1812         os_free(path);
1813         return 0;
1814
1815 err:
1816         os_free(obj_desc);
1817         os_free(path);
1818         return -1;
1819 }
1820
1821
1822 static int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
1823 {
1824         struct wpas_dbus_priv *ctrl_iface;
1825
1826         /* Do nothing if the control interface is not turned on */
1827         if (wpa_s == NULL || wpa_s->global == NULL)
1828                 return 0;
1829         ctrl_iface = wpa_s->global->dbus;
1830         if (ctrl_iface == NULL)
1831                 return 0;
1832
1833         wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
1834                    wpas_dbus_get_path(wpa_s));
1835         if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
1836                                                  wpas_dbus_get_path(wpa_s)))
1837                 return -1;
1838
1839         wpas_dbus_signal_interface_removed(wpa_s);
1840
1841         os_free(wpa_s->dbus_new_path);
1842         wpa_s->dbus_new_path = NULL;
1843
1844         return 0;
1845 }
1846
1847
1848 static struct wpas_dbus_callbacks callbacks =
1849 {
1850         .signal_interface_added = wpas_dbus_signal_interface_added,
1851         .signal_interface_removed = wpas_dbus_signal_interface_removed,
1852
1853         .register_interface = wpas_dbus_register_interface,
1854         .unregister_interface = wpas_dbus_unregister_interface,
1855
1856         .signal_scan_done = wpas_dbus_signal_scan_done,
1857
1858         .signal_blob_added = wpas_dbus_signal_blob_added,
1859         .signal_blob_removed = wpas_dbus_signal_blob_removed,
1860
1861         .signal_network_selected = wpas_dbus_signal_network_selected,
1862
1863         .signal_state_changed = wpas_dbus_signal_state_changed,
1864         .register_network = wpas_dbus_register_network,
1865         .unregister_network = wpas_dbus_unregister_network,
1866
1867         .signal_network_enabled_changed =
1868         wpas_dbus_signal_network_enabled_changed,
1869
1870         .register_bss = wpas_dbus_register_bss,
1871         .unregister_bss = wpas_dbus_unregister_bss,
1872
1873         .signal_prop_changed = wpas_dbus_signal_prop_changed,
1874
1875         .signal_debug_level_changed = wpas_dbus_signal_debug_level_changed,
1876         .signal_debug_timestamp_changed =
1877         wpas_dbus_signal_debug_timestamp_changed,
1878         .signal_debug_show_keys_changed =
1879         wpas_dbus_signal_debug_show_keys_changed,
1880
1881 #ifdef CONFIG_WPS
1882         .signal_wps_event_success = wpas_dbus_signal_wps_event_success,
1883         .signal_wps_event_fail = wpas_dbus_signal_wps_event_fail,
1884         .signal_wps_event_m2d = wpas_dbus_signal_wps_event_m2d,
1885         .signal_wps_credentials = wpas_dbus_signal_wps_cred,
1886 #endif /* CONFIG_WPS */
1887 };
1888
1889
1890 struct wpas_dbus_callbacks * wpas_dbus_get_callbacks(void)
1891 {
1892         return &callbacks;
1893 }
1894
1895
1896 /**
1897  * wpas_dbus_get_path - Get an interface's dbus path
1898  * @wpa_s: %wpa_supplicant interface structure
1899  * Returns: Interface's dbus object path, or %NULL on error
1900  */
1901 const char * wpas_dbus_get_path(struct wpa_supplicant *wpa_s)
1902 {
1903         return wpa_s->dbus_new_path;
1904 }