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