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