6052f7b6f26c5e5f64f16b14ae8dbdca05063f3b
[platform/upstream/connman.git] / gsupplicant / supplicant.c
1 /*
2  *
3  *  WPA supplicant library with GLib integration
4  *
5  *  Copyright (C) 2012-2013  Intel Corporation. All rights reserved.
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  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdint.h>
31 #include <syslog.h>
32 #include <ctype.h>
33 #include <stdbool.h>
34 #include <netinet/if_ether.h>
35 #include <netinet/in.h>
36
37 #include <glib.h>
38 #include <gdbus.h>
39
40 #include "dbus.h"
41 #include "gsupplicant.h"
42
43 #define IEEE80211_CAP_ESS       0x0001
44 #define IEEE80211_CAP_IBSS      0x0002
45 #define IEEE80211_CAP_PRIVACY   0x0010
46
47 #define BSS_UNKNOWN_STRENGTH    -90
48
49 static DBusConnection *connection;
50
51 static const GSupplicantCallbacks *callbacks_pointer;
52
53 static dbus_bool_t system_available = FALSE;
54 static dbus_bool_t system_ready = FALSE;
55
56 static dbus_int32_t debug_level;
57 static dbus_bool_t debug_timestamp = FALSE;
58 static dbus_bool_t debug_showkeys = FALSE;
59
60 static const char *debug_strings[] = {
61         "msgdump", "debug", "info", "warning", "error", NULL
62 };
63
64 static unsigned int eap_methods;
65
66 struct strvalmap {
67         const char *str;
68         unsigned int val;
69 };
70
71 static struct strvalmap eap_method_map[] = {
72         { "MD5",        G_SUPPLICANT_EAP_METHOD_MD5     },
73         { "TLS",        G_SUPPLICANT_EAP_METHOD_TLS     },
74         { "MSCHAPV2",   G_SUPPLICANT_EAP_METHOD_MSCHAPV2        },
75         { "PEAP",       G_SUPPLICANT_EAP_METHOD_PEAP    },
76         { "TTLS",       G_SUPPLICANT_EAP_METHOD_TTLS    },
77         { "GTC",        G_SUPPLICANT_EAP_METHOD_GTC     },
78         { "OTP",        G_SUPPLICANT_EAP_METHOD_OTP     },
79         { "LEAP",       G_SUPPLICANT_EAP_METHOD_LEAP    },
80         { "WSC",        G_SUPPLICANT_EAP_METHOD_WSC     },
81         { }
82 };
83
84 static struct strvalmap keymgmt_map[] = {
85         { "none",               G_SUPPLICANT_KEYMGMT_NONE               },
86         { "ieee8021x",          G_SUPPLICANT_KEYMGMT_IEEE8021X  },
87         { "wpa-none",           G_SUPPLICANT_KEYMGMT_WPA_NONE   },
88         { "wpa-psk",            G_SUPPLICANT_KEYMGMT_WPA_PSK    },
89         { "wpa-psk-sha256",     G_SUPPLICANT_KEYMGMT_WPA_PSK_256        },
90         { "wpa-ft-psk",         G_SUPPLICANT_KEYMGMT_WPA_FT_PSK },
91         { "wpa-ft-eap",         G_SUPPLICANT_KEYMGMT_WPA_FT_EAP },
92         { "wpa-eap",            G_SUPPLICANT_KEYMGMT_WPA_EAP    },
93         { "wpa-eap-sha256",     G_SUPPLICANT_KEYMGMT_WPA_EAP_256        },
94         { "wps",                G_SUPPLICANT_KEYMGMT_WPS                },
95         { }
96 };
97
98 static struct strvalmap authalg_capa_map[] = {
99         { "open",       G_SUPPLICANT_CAPABILITY_AUTHALG_OPEN    },
100         { "shared",     G_SUPPLICANT_CAPABILITY_AUTHALG_SHARED  },
101         { "leap",       G_SUPPLICANT_CAPABILITY_AUTHALG_LEAP    },
102         { }
103 };
104
105 static struct strvalmap proto_capa_map[] = {
106         { "wpa",        G_SUPPLICANT_CAPABILITY_PROTO_WPA               },
107         { "rsn",        G_SUPPLICANT_CAPABILITY_PROTO_RSN               },
108         { }
109 };
110
111 static struct strvalmap group_map[] = {
112         { "wep40",      G_SUPPLICANT_GROUP_WEP40        },
113         { "wep104",     G_SUPPLICANT_GROUP_WEP104       },
114         { "tkip",       G_SUPPLICANT_GROUP_TKIP },
115         { "ccmp",       G_SUPPLICANT_GROUP_CCMP },
116         { }
117 };
118
119 static struct strvalmap pairwise_map[] = {
120         { "none",       G_SUPPLICANT_PAIRWISE_NONE      },
121         { "tkip",       G_SUPPLICANT_PAIRWISE_TKIP      },
122         { "ccmp",       G_SUPPLICANT_PAIRWISE_CCMP      },
123         { }
124 };
125
126 static struct strvalmap scan_capa_map[] = {
127         { "active",     G_SUPPLICANT_CAPABILITY_SCAN_ACTIVE     },
128         { "passive",    G_SUPPLICANT_CAPABILITY_SCAN_PASSIVE    },
129         { "ssid",       G_SUPPLICANT_CAPABILITY_SCAN_SSID               },
130         { }
131 };
132
133 static struct strvalmap mode_capa_map[] = {
134         { "infrastructure",     G_SUPPLICANT_CAPABILITY_MODE_INFRA      },
135         { "ad-hoc",             G_SUPPLICANT_CAPABILITY_MODE_IBSS       },
136         { "ap",                 G_SUPPLICANT_CAPABILITY_MODE_AP         },
137         { "p2p",                G_SUPPLICANT_CAPABILITY_MODE_P2P        },
138         { }
139 };
140
141 static GHashTable *interface_table;
142 static GHashTable *bss_mapping;
143 static GHashTable *peer_mapping;
144 static GHashTable *group_mapping;
145 static GHashTable *pending_peer_connection;
146 static GHashTable *config_file_table;
147
148 struct _GSupplicantWpsCredentials {
149         unsigned char ssid[32];
150         unsigned int ssid_len;
151         char *key;
152 };
153
154 struct added_network_information {
155         char * ssid;
156         GSupplicantSecurity security;
157         char * passphrase;
158         char * private_passphrase;
159 };
160
161 struct _GSupplicantInterface {
162         char *path;
163         char *network_path;
164         unsigned int keymgmt_capa;
165         unsigned int authalg_capa;
166         unsigned int proto_capa;
167         unsigned int group_capa;
168         unsigned int pairwise_capa;
169         unsigned int scan_capa;
170         unsigned int mode_capa;
171         unsigned int max_scan_ssids;
172         bool p2p_support;
173         bool p2p_finding;
174         bool ap_create_in_progress;
175         dbus_bool_t ready;
176         GSupplicantState state;
177         dbus_bool_t scanning;
178         GSupplicantInterfaceCallback scan_callback;
179         void *scan_data;
180         int apscan;
181         char *ifname;
182         char *driver;
183         char *bridge;
184         struct _GSupplicantWpsCredentials wps_cred;
185         GSupplicantWpsState wps_state;
186         GHashTable *network_table;
187         GHashTable *peer_table;
188         GHashTable *group_table;
189         GHashTable *bss_mapping;
190         void *data;
191         const char *pending_peer_path;
192         GSupplicantNetwork *current_network;
193         struct added_network_information network_info;
194 };
195
196 struct g_supplicant_bss {
197         GSupplicantInterface *interface;
198         char *path;
199         unsigned char bssid[6];
200         unsigned char ssid[32];
201         unsigned int ssid_len;
202         dbus_uint16_t frequency;
203         dbus_uint32_t maxrate;
204         dbus_int16_t signal;
205         GSupplicantMode mode;
206         GSupplicantSecurity security;
207         dbus_bool_t rsn_selected;
208         unsigned int wpa_keymgmt;
209         unsigned int wpa_pairwise;
210         unsigned int wpa_group;
211         unsigned int rsn_keymgmt;
212         unsigned int rsn_pairwise;
213         unsigned int rsn_group;
214         unsigned int keymgmt;
215         dbus_bool_t privacy;
216         dbus_bool_t psk;
217         dbus_bool_t ieee8021x;
218         unsigned int wps_capabilities;
219 };
220
221 struct _GSupplicantNetwork {
222         GSupplicantInterface *interface;
223         char *path;
224         char *group;
225         char *name;
226         unsigned char ssid[32];
227         unsigned int ssid_len;
228         dbus_int16_t signal;
229         dbus_uint16_t frequency;
230         struct g_supplicant_bss *best_bss;
231         GSupplicantMode mode;
232         GSupplicantSecurity security;
233         dbus_bool_t wps;
234         unsigned int wps_capabilities;
235         GHashTable *bss_table;
236         GHashTable *config_table;
237 };
238
239 struct _GSupplicantPeer {
240         GSupplicantInterface *interface;
241         char *path;
242         unsigned char device_address[ETH_ALEN];
243         unsigned char iface_address[ETH_ALEN];
244         char *name;
245         unsigned char *widi_ies;
246         int widi_ies_length;
247         char *identifier;
248         unsigned int wps_capabilities;
249         GSList *groups;
250         const GSupplicantInterface *current_group_iface;
251         bool connection_requested;
252 };
253
254 struct _GSupplicantGroup {
255         GSupplicantInterface *interface;
256         GSupplicantInterface *orig_interface;
257         char *path;
258         int role;
259         GSList *members;
260 };
261
262 struct interface_data {
263         GSupplicantInterface *interface;
264         char *path; /* Interface path cannot be taken from interface (above) as
265                      * it might have been freed already.
266                      */
267         GSupplicantInterfaceCallback callback;
268         void *user_data;
269         bool network_remove_in_progress;
270         GSupplicantSSID *ssid;
271 };
272
273 struct interface_create_data {
274         char *ifname;
275         char *driver;
276         char *bridge;
277         GSupplicantInterface *interface;
278         GSupplicantInterfaceCallback callback;
279         void *user_data;
280 };
281
282 struct interface_connect_data {
283         GSupplicantInterface *interface;
284         char *path;
285         GSupplicantInterfaceCallback callback;
286         void *user_data;
287         union {
288                 GSupplicantSSID *ssid;
289                 GSupplicantPeerParams *peer;
290         };
291 };
292
293 struct interface_scan_data {
294         GSupplicantInterface *interface;
295         char *path;
296         GSupplicantInterfaceCallback callback;
297         GSupplicantScanParams *scan_params;
298         void *user_data;
299 };
300
301 static int network_remove(struct interface_data *data);
302
303 static inline void debug(const char *format, ...)
304 {
305         char str[256];
306         va_list ap;
307
308         if (!callbacks_pointer || !callbacks_pointer->debug)
309                 return;
310
311         va_start(ap, format);
312
313         if (vsnprintf(str, sizeof(str), format, ap) > 0)
314                 callbacks_pointer->debug(str);
315
316         va_end(ap);
317 }
318
319 #define SUPPLICANT_DBG(fmt, arg...) \
320         debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg);
321
322 static GSupplicantMode string2mode(const char *mode)
323 {
324         if (!mode)
325                 return G_SUPPLICANT_MODE_UNKNOWN;
326
327         if (g_str_equal(mode, "infrastructure"))
328                 return G_SUPPLICANT_MODE_INFRA;
329         else if (g_str_equal(mode, "ad-hoc"))
330                 return G_SUPPLICANT_MODE_IBSS;
331
332         return G_SUPPLICANT_MODE_UNKNOWN;
333 }
334
335 static const char *mode2string(GSupplicantMode mode)
336 {
337         switch (mode) {
338         case G_SUPPLICANT_MODE_UNKNOWN:
339                 break;
340         case G_SUPPLICANT_MODE_INFRA:
341                 return "managed";
342         case G_SUPPLICANT_MODE_IBSS:
343                 return "adhoc";
344         case G_SUPPLICANT_MODE_MASTER:
345                 return "ap";
346         }
347
348         return NULL;
349 }
350
351 static const char *security2string(GSupplicantSecurity security)
352 {
353         switch (security) {
354         case G_SUPPLICANT_SECURITY_UNKNOWN:
355                 break;
356         case G_SUPPLICANT_SECURITY_NONE:
357                 return "none";
358         case G_SUPPLICANT_SECURITY_WEP:
359                 return "wep";
360         case G_SUPPLICANT_SECURITY_PSK:
361                 return "psk";
362         case G_SUPPLICANT_SECURITY_IEEE8021X:
363                 return "ieee8021x";
364         }
365
366         return NULL;
367 }
368
369 static GSupplicantState string2state(const char *state)
370 {
371         if (!state)
372                 return G_SUPPLICANT_STATE_UNKNOWN;
373
374         if (g_str_equal(state, "unknown"))
375                 return G_SUPPLICANT_STATE_UNKNOWN;
376         else if (g_str_equal(state, "interface_disabled"))
377                 return G_SUPPLICANT_STATE_DISABLED;
378         else if (g_str_equal(state, "disconnected"))
379                 return G_SUPPLICANT_STATE_DISCONNECTED;
380         else if (g_str_equal(state, "inactive"))
381                 return G_SUPPLICANT_STATE_INACTIVE;
382         else if (g_str_equal(state, "scanning"))
383                 return G_SUPPLICANT_STATE_SCANNING;
384         else if (g_str_equal(state, "authenticating"))
385                 return G_SUPPLICANT_STATE_AUTHENTICATING;
386         else if (g_str_equal(state, "associating"))
387                 return G_SUPPLICANT_STATE_ASSOCIATING;
388         else if (g_str_equal(state, "associated"))
389                 return G_SUPPLICANT_STATE_ASSOCIATED;
390         else if (g_str_equal(state, "group_handshake"))
391                 return G_SUPPLICANT_STATE_GROUP_HANDSHAKE;
392         else if (g_str_equal(state, "4way_handshake"))
393                 return G_SUPPLICANT_STATE_4WAY_HANDSHAKE;
394         else if (g_str_equal(state, "completed"))
395                 return G_SUPPLICANT_STATE_COMPLETED;
396
397         return G_SUPPLICANT_STATE_UNKNOWN;
398 }
399
400 static bool compare_network_parameters(GSupplicantInterface *interface,
401                                 GSupplicantSSID *ssid)
402 {
403         if (memcmp(interface->network_info.ssid, ssid->ssid, ssid->ssid_len))
404                 return FALSE;
405
406         if (interface->network_info.security != ssid->security)
407                 return FALSE;
408
409         if (interface->network_info.passphrase &&
410                         g_strcmp0(interface->network_info.passphrase,
411                                 ssid->passphrase) != 0) {
412                 return FALSE;
413         }
414
415         if (interface->network_info.private_passphrase &&
416                         g_strcmp0(interface->network_info.private_passphrase,
417                                 ssid->private_key_passphrase) != 0) {
418                 return FALSE;
419         }
420
421         return TRUE;
422 }
423
424 static void remove_network_information(GSupplicantInterface * interface)
425 {
426         g_free(interface->network_info.ssid);
427         g_free(interface->network_info.passphrase);
428         g_free(interface->network_info.private_passphrase);
429         interface->network_info.ssid = NULL;
430         interface->network_info.passphrase = NULL;
431         interface->network_info.private_passphrase = NULL;
432 }
433
434 static int store_network_information(GSupplicantInterface * interface,
435                                 GSupplicantSSID *ssid)
436 {
437         interface->network_info.ssid = g_malloc(ssid->ssid_len + 1);
438         if (interface->network_info.ssid != NULL) {
439                 memcpy(interface->network_info.ssid, ssid->ssid,
440                         ssid->ssid_len);
441                 interface->network_info.ssid[ssid->ssid_len] = '\0';
442         } else {
443                 return -ENOMEM;
444         }
445
446         interface->network_info.security = ssid->security;
447
448         if ((ssid->security == G_SUPPLICANT_SECURITY_WEP ||
449                 ssid->security == G_SUPPLICANT_SECURITY_PSK ||
450                 ssid->security == G_SUPPLICANT_SECURITY_NONE) &&
451                 ssid->passphrase) {
452                 interface->network_info.passphrase = g_strdup(ssid->passphrase);
453         }
454
455         if (ssid->security == G_SUPPLICANT_SECURITY_IEEE8021X &&
456                         ssid->private_key_passphrase) {
457                 interface->network_info.private_passphrase =
458                         g_strdup(ssid->private_key_passphrase);
459         }
460
461         return 0;
462 }
463
464 static void callback_system_ready(void)
465 {
466         if (system_ready)
467                 return;
468
469         system_ready = TRUE;
470
471         if (!callbacks_pointer)
472                 return;
473
474         if (!callbacks_pointer->system_ready)
475                 return;
476
477         callbacks_pointer->system_ready();
478 }
479
480 static void callback_system_killed(void)
481 {
482         system_ready = FALSE;
483
484         if (!callbacks_pointer)
485                 return;
486
487         if (!callbacks_pointer->system_killed)
488                 return;
489
490         callbacks_pointer->system_killed();
491 }
492
493 static void callback_interface_added(GSupplicantInterface *interface)
494 {
495         SUPPLICANT_DBG("");
496
497         if (!callbacks_pointer)
498                 return;
499
500         if (!callbacks_pointer->interface_added)
501                 return;
502
503         callbacks_pointer->interface_added(interface);
504 }
505
506 static void callback_interface_state(GSupplicantInterface *interface)
507 {
508         if (!callbacks_pointer)
509                 return;
510
511         if (!callbacks_pointer->interface_state)
512                 return;
513
514         callbacks_pointer->interface_state(interface);
515 }
516
517 static void callback_interface_removed(GSupplicantInterface *interface)
518 {
519         if (!callbacks_pointer)
520                 return;
521
522         if (!callbacks_pointer->interface_removed)
523                 return;
524
525         callbacks_pointer->interface_removed(interface);
526 }
527
528 static void callback_p2p_support(GSupplicantInterface *interface)
529 {
530         SUPPLICANT_DBG("");
531
532         if (!interface->p2p_support)
533                 return;
534
535         if (callbacks_pointer && callbacks_pointer->p2p_support)
536                 callbacks_pointer->p2p_support(interface);
537 }
538
539 static void callback_scan_started(GSupplicantInterface *interface)
540 {
541         if (!callbacks_pointer)
542                 return;
543
544         if (!callbacks_pointer->scan_started)
545                 return;
546
547         callbacks_pointer->scan_started(interface);
548 }
549
550 static void callback_ap_create_fail(GSupplicantInterface *interface)
551 {
552         if (!callbacks_pointer)
553                 return;
554
555         if (!callbacks_pointer->ap_create_fail)
556                 return;
557
558         callbacks_pointer->ap_create_fail(interface);
559 }
560
561 static void callback_scan_finished(GSupplicantInterface *interface)
562 {
563         if (!callbacks_pointer)
564                 return;
565
566         if (!callbacks_pointer->scan_finished)
567                 return;
568
569         callbacks_pointer->scan_finished(interface);
570 }
571
572 static void callback_network_added(GSupplicantNetwork *network)
573 {
574         if (!callbacks_pointer)
575                 return;
576
577         if (!callbacks_pointer->network_added)
578                 return;
579
580         callbacks_pointer->network_added(network);
581 }
582
583 static void callback_network_removed(GSupplicantNetwork *network)
584 {
585         if (!callbacks_pointer)
586                 return;
587
588         if (!callbacks_pointer->network_removed)
589                 return;
590
591         callbacks_pointer->network_removed(network);
592 }
593
594 static void callback_network_changed(GSupplicantNetwork *network,
595                                         const char *property)
596 {
597         if (!callbacks_pointer)
598                 return;
599
600         if (!callbacks_pointer->network_changed)
601                 return;
602
603         callbacks_pointer->network_changed(network, property);
604 }
605
606 static void callback_network_associated(GSupplicantNetwork *network)
607 {
608         if (!callbacks_pointer)
609                 return;
610
611         if (!callbacks_pointer->network_associated)
612                 return;
613
614         callbacks_pointer->network_associated(network);
615 }
616
617 static void callback_sta_authorized(GSupplicantInterface *interface,
618                                         const char *addr)
619 {
620         if (!callbacks_pointer)
621                 return;
622
623         if (!callbacks_pointer->sta_authorized)
624                 return;
625
626         callbacks_pointer->sta_authorized(interface, addr);
627 }
628
629 static void callback_sta_deauthorized(GSupplicantInterface *interface,
630                                         const char *addr)
631 {
632         if (!callbacks_pointer)
633                 return;
634
635         if (!callbacks_pointer->sta_deauthorized)
636                 return;
637
638         callbacks_pointer->sta_deauthorized(interface, addr);
639 }
640
641 static void callback_peer_found(GSupplicantPeer *peer)
642 {
643         if (!callbacks_pointer)
644                 return;
645
646         if (!callbacks_pointer->peer_found)
647                 return;
648
649         callbacks_pointer->peer_found(peer);
650 }
651
652 static void callback_peer_lost(GSupplicantPeer *peer)
653 {
654         if (!callbacks_pointer)
655                 return;
656
657         if (!callbacks_pointer->peer_lost)
658                 return;
659
660         callbacks_pointer->peer_lost(peer);
661 }
662
663 static void callback_peer_changed(GSupplicantPeer *peer,
664                                                 GSupplicantPeerState state)
665 {
666         if (!callbacks_pointer)
667                 return;
668
669         if (!callbacks_pointer->peer_changed)
670                 return;
671
672         callbacks_pointer->peer_changed(peer, state);
673 }
674
675 static void callback_peer_request(GSupplicantPeer *peer)
676 {
677         if (!callbacks_pointer)
678                 return;
679
680         if (!callbacks_pointer->peer_request)
681                 return;
682
683         peer->connection_requested = true;
684
685         callbacks_pointer->peer_request(peer);
686 }
687
688 static void callback_disconnect_reason_code(GSupplicantInterface *interface,
689                                         int reason_code)
690 {
691         if (!callbacks_pointer)
692                 return;
693
694         if (!callbacks_pointer->disconnect_reasoncode)
695                 return;
696
697         if (reason_code != 0)
698                 callbacks_pointer->disconnect_reasoncode(interface,
699                                                         reason_code);
700 }
701
702 static void callback_assoc_status_code(GSupplicantInterface *interface,
703                                 int status_code)
704 {
705         if (!callbacks_pointer)
706                 return;
707
708         if (!callbacks_pointer->assoc_status_code)
709                 return;
710
711         callbacks_pointer->assoc_status_code(interface, status_code);
712
713 }
714
715 static void remove_group(gpointer data)
716 {
717         GSupplicantGroup *group = data;
718
719         if (group->members)
720                 g_slist_free_full(group->members, g_free);
721
722         g_free(group->path);
723         g_free(group);
724 }
725
726 static void remove_interface(gpointer data)
727 {
728         GSupplicantInterface *interface = data;
729
730         g_hash_table_destroy(interface->bss_mapping);
731         g_hash_table_destroy(interface->network_table);
732         g_hash_table_destroy(interface->peer_table);
733         g_hash_table_destroy(interface->group_table);
734
735         if (interface->scan_callback) {
736                 SUPPLICANT_DBG("call interface %p callback %p scanning %d",
737                                 interface, interface->scan_callback,
738                                 interface->scanning);
739
740                 interface->scan_callback(-EIO, interface, interface->scan_data);
741                 interface->scan_callback = NULL;
742                 interface->scan_data = NULL;
743
744                 if (interface->scanning) {
745                         interface->scanning = FALSE;
746                         callback_scan_finished(interface);
747                 }
748         }
749
750         callback_interface_removed(interface);
751
752         g_free(interface->wps_cred.key);
753         g_free(interface->path);
754         g_free(interface->network_path);
755         g_free(interface->ifname);
756         g_free(interface->driver);
757         g_free(interface->bridge);
758         remove_network_information(interface);
759         g_free(interface);
760 }
761
762 static void remove_network(gpointer data)
763 {
764         GSupplicantNetwork *network = data;
765
766         g_hash_table_destroy(network->bss_table);
767
768         callback_network_removed(network);
769
770         g_hash_table_destroy(network->config_table);
771
772         g_free(network->path);
773         g_free(network->group);
774         g_free(network->name);
775         g_free(network);
776 }
777
778 static void remove_bss(gpointer data)
779 {
780         struct g_supplicant_bss *bss = data;
781
782         supplicant_dbus_property_call_cancel_all(bss);
783
784         g_free(bss->path);
785         g_free(bss);
786 }
787
788 static void remove_peer(gpointer data)
789 {
790         GSupplicantPeer *peer = data;
791
792         callback_peer_lost(peer);
793
794         if (peer->groups)
795                 g_slist_free_full(peer->groups, g_free);
796
797         if (peer_mapping)
798                 g_hash_table_remove(peer_mapping, peer->path);
799
800         if (pending_peer_connection)
801                 g_hash_table_remove(pending_peer_connection, peer->path);
802
803         g_free(peer->path);
804         g_free(peer->name);
805         g_free(peer->identifier);
806         g_free(peer->widi_ies);
807
808         g_free(peer);
809 }
810
811 static void debug_strvalmap(const char *label, struct strvalmap *map,
812                                                         unsigned int val)
813 {
814         int i;
815
816         for (i = 0; map[i].str; i++) {
817                 if (val & map[i].val)
818                         SUPPLICANT_DBG("%s: %s", label, map[i].str);
819         }
820 }
821
822 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
823 {
824         GSupplicantInterface *interface = user_data;
825         const char *str = NULL;
826         int i;
827
828         dbus_message_iter_get_basic(iter, &str);
829         if (!str)
830                 return;
831
832         for (i = 0; keymgmt_map[i].str; i++)
833                 if (strcmp(str, keymgmt_map[i].str) == 0) {
834                         interface->keymgmt_capa |= keymgmt_map[i].val;
835                         break;
836                 }
837 }
838
839 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
840 {
841         GSupplicantInterface *interface = user_data;
842         const char *str = NULL;
843         int i;
844
845         dbus_message_iter_get_basic(iter, &str);
846         if (!str)
847                 return;
848
849         for (i = 0; authalg_capa_map[i].str; i++)
850                 if (strcmp(str, authalg_capa_map[i].str) == 0) {
851                         interface->authalg_capa |= authalg_capa_map[i].val;
852                         break;
853                 }
854 }
855
856 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
857 {
858         GSupplicantInterface *interface = user_data;
859         const char *str = NULL;
860         int i;
861
862         dbus_message_iter_get_basic(iter, &str);
863         if (!str)
864                 return;
865
866         for (i = 0; proto_capa_map[i].str; i++)
867                 if (strcmp(str, proto_capa_map[i].str) == 0) {
868                         interface->proto_capa |= proto_capa_map[i].val;
869                         break;
870                 }
871 }
872
873 static void interface_capability_pairwise(DBusMessageIter *iter,
874                                                         void *user_data)
875 {
876         GSupplicantInterface *interface = user_data;
877         const char *str = NULL;
878         int i;
879
880         dbus_message_iter_get_basic(iter, &str);
881         if (!str)
882                 return;
883
884         for (i = 0; pairwise_map[i].str; i++)
885                 if (strcmp(str, pairwise_map[i].str) == 0) {
886                         interface->pairwise_capa |= pairwise_map[i].val;
887                         break;
888                 }
889 }
890
891 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
892 {
893         GSupplicantInterface *interface = user_data;
894         const char *str = NULL;
895         int i;
896
897         dbus_message_iter_get_basic(iter, &str);
898         if (!str)
899                 return;
900
901         for (i = 0; group_map[i].str; i++)
902                 if (strcmp(str, group_map[i].str) == 0) {
903                         interface->group_capa |= group_map[i].val;
904                         break;
905                 }
906 }
907
908 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
909 {
910         GSupplicantInterface *interface = user_data;
911         const char *str = NULL;
912         int i;
913
914         dbus_message_iter_get_basic(iter, &str);
915         if (!str)
916                 return;
917
918         for (i = 0; scan_capa_map[i].str; i++)
919                 if (strcmp(str, scan_capa_map[i].str) == 0) {
920                         interface->scan_capa |= scan_capa_map[i].val;
921                         break;
922                 }
923 }
924
925 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
926 {
927         GSupplicantInterface *interface = user_data;
928         const char *str = NULL;
929         int i;
930
931         dbus_message_iter_get_basic(iter, &str);
932         if (!str)
933                 return;
934
935         for (i = 0; mode_capa_map[i].str; i++)
936                 if (strcmp(str, mode_capa_map[i].str) == 0) {
937                         interface->mode_capa |= mode_capa_map[i].val;
938                         break;
939                 }
940 }
941
942 static void interface_capability(const char *key, DBusMessageIter *iter,
943                                                         void *user_data)
944 {
945         GSupplicantInterface *interface = user_data;
946
947         if (!key)
948                 return;
949
950         if (g_strcmp0(key, "KeyMgmt") == 0)
951                 supplicant_dbus_array_foreach(iter,
952                                 interface_capability_keymgmt, interface);
953         else if (g_strcmp0(key, "AuthAlg") == 0)
954                 supplicant_dbus_array_foreach(iter,
955                                 interface_capability_authalg, interface);
956         else if (g_strcmp0(key, "Protocol") == 0)
957                 supplicant_dbus_array_foreach(iter,
958                                 interface_capability_proto, interface);
959         else if (g_strcmp0(key, "Pairwise") == 0)
960                 supplicant_dbus_array_foreach(iter,
961                                 interface_capability_pairwise, interface);
962         else if (g_strcmp0(key, "Group") == 0)
963                 supplicant_dbus_array_foreach(iter,
964                                 interface_capability_group, interface);
965         else if (g_strcmp0(key, "Scan") == 0)
966                 supplicant_dbus_array_foreach(iter,
967                                 interface_capability_scan, interface);
968         else if (g_strcmp0(key, "Modes") == 0)
969                 supplicant_dbus_array_foreach(iter,
970                                 interface_capability_mode, interface);
971         else if (g_strcmp0(key, "MaxScanSSID") == 0) {
972                 dbus_int32_t max_scan_ssid;
973
974                 dbus_message_iter_get_basic(iter, &max_scan_ssid);
975                 if (max_scan_ssid < 2)
976                         max_scan_ssid = 0;
977                 interface->max_scan_ssids = max_scan_ssid;
978
979         } else
980                 SUPPLICANT_DBG("key %s type %c",
981                                 key, dbus_message_iter_get_arg_type(iter));
982 }
983
984 struct set_apscan_data
985 {
986         unsigned int ap_scan;
987         GSupplicantInterface *interface;
988 };
989
990 static void set_apscan(DBusMessageIter *iter, void *user_data)
991 {
992         struct set_apscan_data *data = user_data;
993         unsigned int ap_scan = data->ap_scan;
994
995         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ap_scan);
996 }
997
998 static void set_apscan_complete(const char *error,
999                 DBusMessageIter *iter, void *user_data)
1000 {
1001         struct set_apscan_data *data = user_data;
1002         GSupplicantInterface *interface = data->interface;
1003
1004         if (error) {
1005                 interface->ap_create_in_progress = false;
1006                 SUPPLICANT_DBG("Set AP scan error %s", error);
1007                 goto error;
1008         }
1009
1010         interface->ap_create_in_progress = true;
1011 error:
1012         dbus_free(data);
1013 }
1014
1015 int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
1016                                                         unsigned int ap_scan)
1017 {
1018         struct set_apscan_data *data;
1019         int ret;
1020
1021         data = dbus_malloc0(sizeof(*data));
1022
1023         if (!data)
1024                 return -ENOMEM;
1025
1026         data->ap_scan = ap_scan;
1027         data->interface = interface;
1028
1029         ret = supplicant_dbus_property_set(interface->path,
1030                         SUPPLICANT_INTERFACE ".Interface",
1031                         "ApScan", DBUS_TYPE_UINT32_AS_STRING,
1032                         set_apscan, set_apscan_complete, data, NULL);
1033         if (ret < 0)
1034                 dbus_free(data);
1035
1036         return ret;
1037 }
1038
1039 void g_supplicant_interface_set_data(GSupplicantInterface *interface,
1040                                                                 void *data)
1041 {
1042         if (!interface)
1043                 return;
1044
1045         interface->data = data;
1046
1047         if (!data)
1048                 interface->scan_callback = NULL;
1049 }
1050
1051 void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
1052 {
1053         if (!interface)
1054                 return NULL;
1055
1056         return interface->data;
1057 }
1058
1059 const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface)
1060 {
1061         if (!interface)
1062                 return NULL;
1063
1064         return interface->ifname;
1065 }
1066
1067 const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface)
1068 {
1069         if (!interface)
1070                 return NULL;
1071
1072         return interface->driver;
1073 }
1074
1075 GSupplicantState g_supplicant_interface_get_state(
1076                                         GSupplicantInterface *interface)
1077 {
1078         if (!interface)
1079                 return G_SUPPLICANT_STATE_UNKNOWN;
1080
1081         return interface->state;
1082 }
1083
1084 const char *g_supplicant_interface_get_wps_key(GSupplicantInterface *interface)
1085 {
1086         if (!interface)
1087                 return NULL;
1088
1089         return (const char *)interface->wps_cred.key;
1090 }
1091
1092 const void *g_supplicant_interface_get_wps_ssid(GSupplicantInterface *interface,
1093                                                         unsigned int *ssid_len)
1094 {
1095         if (!ssid_len)
1096                 return NULL;
1097
1098         if (!interface || interface->wps_cred.ssid_len == 0) {
1099                 *ssid_len = 0;
1100                 return NULL;
1101         }
1102
1103         *ssid_len = interface->wps_cred.ssid_len;
1104         return interface->wps_cred.ssid;
1105 }
1106
1107 GSupplicantWpsState g_supplicant_interface_get_wps_state(
1108                                         GSupplicantInterface *interface)
1109 {
1110         if (!interface)
1111                 return G_SUPPLICANT_WPS_STATE_UNKNOWN;
1112
1113         return interface->wps_state;
1114 }
1115
1116 unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface)
1117 {
1118         if (!interface)
1119                 return 0;
1120
1121         return interface->mode_capa;
1122 }
1123
1124 unsigned int g_supplicant_interface_get_max_scan_ssids(
1125                                 GSupplicantInterface *interface)
1126 {
1127         if (!interface)
1128                 return 0;
1129
1130         return interface->max_scan_ssids;
1131 }
1132
1133 static void set_network_enabled(DBusMessageIter *iter, void *user_data)
1134 {
1135         dbus_bool_t enable = *(dbus_bool_t *)user_data;
1136
1137         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &enable);
1138 }
1139
1140 int g_supplicant_interface_enable_selected_network(GSupplicantInterface *interface,
1141                                                         dbus_bool_t enable)
1142 {
1143         if (!interface)
1144                 return -1;
1145
1146         if (!interface->network_path)
1147                 return -1;
1148
1149         SUPPLICANT_DBG(" ");
1150         return supplicant_dbus_property_set(interface->network_path,
1151                                 SUPPLICANT_INTERFACE ".Network",
1152                                 "Enabled", DBUS_TYPE_BOOLEAN_AS_STRING,
1153                                 set_network_enabled, NULL, &enable, NULL);
1154 }
1155
1156 dbus_bool_t g_supplicant_interface_get_ready(GSupplicantInterface *interface)
1157 {
1158         if (!interface)
1159                 return FALSE;
1160
1161         return interface->ready;
1162 }
1163
1164 GSupplicantInterface *g_supplicant_network_get_interface(
1165                                         GSupplicantNetwork *network)
1166 {
1167         if (!network)
1168                 return NULL;
1169
1170         return network->interface;
1171 }
1172
1173 const char *g_supplicant_network_get_name(GSupplicantNetwork *network)
1174 {
1175         if (!network || !network->name)
1176                 return "";
1177
1178         return network->name;
1179 }
1180
1181 const char *g_supplicant_network_get_identifier(GSupplicantNetwork *network)
1182 {
1183         if (!network || !network->group)
1184                 return "";
1185
1186         return network->group;
1187 }
1188
1189 const char *g_supplicant_network_get_path(GSupplicantNetwork *network)
1190 {
1191         if (!network || !network->path)
1192                 return NULL;
1193
1194         return network->path;
1195 }
1196
1197 const char *g_supplicant_network_get_mode(GSupplicantNetwork *network)
1198 {
1199         if (!network)
1200                 return G_SUPPLICANT_MODE_UNKNOWN;
1201
1202         return mode2string(network->mode);
1203 }
1204
1205 const char *g_supplicant_network_get_security(GSupplicantNetwork *network)
1206 {
1207         if (!network)
1208                 return G_SUPPLICANT_SECURITY_UNKNOWN;
1209
1210         return security2string(network->security);
1211 }
1212
1213 const void *g_supplicant_network_get_ssid(GSupplicantNetwork *network,
1214                                                 unsigned int *ssid_len)
1215 {
1216         if (!network) {
1217                 *ssid_len = 0;
1218                 return NULL;
1219         }
1220
1221         *ssid_len = network->ssid_len;
1222         return network->ssid;
1223 }
1224
1225 dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network)
1226 {
1227         if (!network)
1228                 return 0;
1229
1230         return network->signal;
1231 }
1232
1233 dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network)
1234 {
1235         if (!network)
1236                 return 0;
1237
1238         return network->frequency;
1239 }
1240
1241 dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network)
1242 {
1243         if (!network)
1244                 return FALSE;
1245
1246         return network->wps;
1247 }
1248
1249 dbus_bool_t g_supplicant_network_is_wps_active(GSupplicantNetwork *network)
1250 {
1251         if (!network)
1252                 return FALSE;
1253
1254         if (network->wps_capabilities & G_SUPPLICANT_WPS_CONFIGURED)
1255                 return TRUE;
1256
1257         return FALSE;
1258 }
1259
1260 dbus_bool_t g_supplicant_network_is_wps_pbc(GSupplicantNetwork *network)
1261 {
1262         if (!network)
1263                 return FALSE;
1264
1265         if (network->wps_capabilities & G_SUPPLICANT_WPS_PBC)
1266                 return TRUE;
1267
1268         return FALSE;
1269 }
1270
1271 dbus_bool_t g_supplicant_network_is_wps_advertizing(GSupplicantNetwork *network)
1272 {
1273         if (!network)
1274                 return FALSE;
1275
1276         if (network->wps_capabilities & G_SUPPLICANT_WPS_REGISTRAR)
1277                 return TRUE;
1278
1279         return FALSE;
1280 }
1281
1282 GSupplicantInterface *g_supplicant_peer_get_interface(GSupplicantPeer *peer)
1283 {
1284         if (!peer)
1285                 return NULL;
1286
1287         return peer->interface;
1288 }
1289
1290 const char *g_supplicant_peer_get_path(GSupplicantPeer *peer)
1291 {
1292         if (!peer)
1293                 return NULL;
1294
1295         return peer->path;
1296 }
1297
1298 const char *g_supplicant_peer_get_identifier(GSupplicantPeer *peer)
1299 {
1300         if (!peer)
1301                 return NULL;
1302
1303         return peer->identifier;
1304 }
1305
1306 const void *g_supplicant_peer_get_device_address(GSupplicantPeer *peer)
1307 {
1308         if (!peer)
1309                 return NULL;
1310
1311         return peer->device_address;
1312 }
1313
1314 const void *g_supplicant_peer_get_iface_address(GSupplicantPeer *peer)
1315 {
1316         if (!peer)
1317                 return NULL;
1318
1319         return peer->iface_address;
1320 }
1321
1322 const char *g_supplicant_peer_get_name(GSupplicantPeer *peer)
1323 {
1324         if (!peer)
1325                 return NULL;
1326
1327         return peer->name;
1328 }
1329
1330 const unsigned char *g_supplicant_peer_get_widi_ies(GSupplicantPeer *peer,
1331                                                                 int *length)
1332 {
1333         if (!peer || !length)
1334                 return NULL;
1335
1336         *length = peer->widi_ies_length;
1337         return peer->widi_ies;
1338 }
1339
1340 bool g_supplicant_peer_is_wps_pbc(GSupplicantPeer *peer)
1341 {
1342         if (!peer)
1343                 return false;
1344
1345         if (peer->wps_capabilities & G_SUPPLICANT_WPS_PBC)
1346                 return true;
1347
1348         return false;
1349 }
1350
1351 bool g_supplicant_peer_is_wps_pin(GSupplicantPeer *peer)
1352 {
1353         if (!peer)
1354                 return false;
1355
1356         if (peer->wps_capabilities & G_SUPPLICANT_WPS_PIN)
1357                 return true;
1358
1359         return false;
1360 }
1361
1362 bool g_supplicant_peer_is_in_a_group(GSupplicantPeer *peer)
1363 {
1364         if (!peer || !peer->groups)
1365                 return false;
1366
1367         return true;
1368 }
1369
1370 GSupplicantInterface *g_supplicant_peer_get_group_interface(GSupplicantPeer *peer)
1371 {
1372         if (!peer)
1373                 return NULL;
1374
1375         return (GSupplicantInterface *) peer->current_group_iface;
1376 }
1377
1378 bool g_supplicant_peer_is_client(GSupplicantPeer *peer)
1379 {
1380         GSupplicantGroup *group;
1381         GSList *list;
1382
1383         if (!peer)
1384                 return false;
1385
1386         for (list = peer->groups; list; list = list->next) {
1387                 const char *path = list->data;
1388
1389                 group = g_hash_table_lookup(group_mapping, path);
1390                 if (!group)
1391                         continue;
1392
1393                 if (group->role != G_SUPPLICANT_GROUP_ROLE_CLIENT ||
1394                                 group->orig_interface != peer->interface)
1395                         continue;
1396
1397                 if (group->interface == peer->current_group_iface)
1398                         return true;
1399         }
1400
1401         return false;
1402 }
1403
1404 bool g_supplicant_peer_has_requested_connection(GSupplicantPeer *peer)
1405 {
1406         if (!peer)
1407                 return false;
1408
1409         return peer->connection_requested;
1410 }
1411
1412 static void merge_network(GSupplicantNetwork *network)
1413 {
1414         GString *str;
1415         const char *ssid, *mode, *key_mgmt;
1416         unsigned int i, ssid_len;
1417         char *group;
1418
1419         ssid = g_hash_table_lookup(network->config_table, "ssid");
1420         mode = g_hash_table_lookup(network->config_table, "mode");
1421         key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
1422
1423         SUPPLICANT_DBG("ssid %s mode %s", ssid, mode);
1424
1425         if (ssid)
1426                 ssid_len = strlen(ssid);
1427         else
1428                 ssid_len = 0;
1429
1430         str = g_string_sized_new((ssid_len * 2) + 24);
1431         if (!str)
1432                 return;
1433
1434         for (i = 0; i < ssid_len; i++)
1435                 g_string_append_printf(str, "%02x", ssid[i]);
1436
1437         if (g_strcmp0(mode, "0") == 0)
1438                 g_string_append_printf(str, "_managed");
1439         else if (g_strcmp0(mode, "1") == 0)
1440                 g_string_append_printf(str, "_adhoc");
1441
1442         if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
1443                 g_string_append_printf(str, "_psk");
1444
1445         group = g_string_free(str, FALSE);
1446
1447         SUPPLICANT_DBG("%s", group);
1448
1449         g_free(group);
1450
1451         g_hash_table_destroy(network->config_table);
1452
1453         g_free(network->path);
1454         g_free(network);
1455 }
1456
1457 static void network_property(const char *key, DBusMessageIter *iter,
1458                                                         void *user_data)
1459 {
1460         GSupplicantNetwork *network = user_data;
1461
1462         if (!network->interface)
1463                 return;
1464
1465         if (!key) {
1466                 merge_network(network);
1467                 return;
1468         }
1469
1470         if (g_strcmp0(key, "Enabled") == 0) {
1471                 dbus_bool_t enabled = FALSE;
1472
1473                 dbus_message_iter_get_basic(iter, &enabled);
1474         } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
1475                 const char *str = NULL;
1476
1477                 dbus_message_iter_get_basic(iter, &str);
1478                 if (str) {
1479                         g_hash_table_replace(network->config_table,
1480                                                 g_strdup(key), g_strdup(str));
1481                 }
1482         } else
1483                 SUPPLICANT_DBG("key %s type %c",
1484                                 key, dbus_message_iter_get_arg_type(iter));
1485 }
1486
1487 static void interface_network_added(DBusMessageIter *iter, void *user_data)
1488 {
1489         GSupplicantInterface *interface = user_data;
1490         GSupplicantNetwork *network;
1491         const char *path = NULL;
1492
1493         SUPPLICANT_DBG("");
1494
1495         dbus_message_iter_get_basic(iter, &path);
1496         if (!path)
1497                 return;
1498
1499         if (g_strcmp0(path, "/") == 0)
1500                 return;
1501
1502         network = g_try_new0(GSupplicantNetwork, 1);
1503         if (!network)
1504                 return;
1505
1506         network->interface = interface;
1507         network->path = g_strdup(path);
1508
1509         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1510                                                         g_free, g_free);
1511
1512         dbus_message_iter_next(iter);
1513         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1514                 supplicant_dbus_property_foreach(iter, network_property,
1515                                                                 network);
1516                 network_property(NULL, NULL, network);
1517                 return;
1518         }
1519
1520         supplicant_dbus_property_get_all(path,
1521                                 SUPPLICANT_INTERFACE ".Network",
1522                                         network_property, network, NULL);
1523 }
1524
1525 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
1526 {
1527         SUPPLICANT_DBG("");
1528 }
1529
1530 static char *create_name(unsigned char *ssid, int ssid_len)
1531 {
1532         GString *string;
1533         const gchar *remainder, *invalid;
1534         int valid_bytes, remaining_bytes;
1535
1536         if (ssid_len < 1 || ssid[0] == '\0')
1537                 return g_strdup("");
1538
1539         string = NULL;
1540         remainder = (const gchar *)ssid;
1541         remaining_bytes = ssid_len;
1542
1543         while (remaining_bytes != 0) {
1544                 if (g_utf8_validate(remainder, remaining_bytes,
1545                                         &invalid)) {
1546                         break;
1547                 }
1548
1549                 valid_bytes = invalid - remainder;
1550
1551                 if (!string)
1552                         string = g_string_sized_new(remaining_bytes);
1553
1554                 g_string_append_len(string, remainder, valid_bytes);
1555
1556                 /* append U+FFFD REPLACEMENT CHARACTER */
1557                 g_string_append(string, "\357\277\275");
1558
1559                 remaining_bytes -= valid_bytes + 1;
1560                 remainder = invalid + 1;
1561         }
1562
1563         if (!string)
1564                 return g_strndup((const gchar *)ssid, ssid_len + 1);
1565
1566         g_string_append(string, remainder);
1567
1568         return g_string_free(string, FALSE);
1569 }
1570
1571 static char *create_group(struct g_supplicant_bss *bss)
1572 {
1573         GString *str;
1574         unsigned int i;
1575         const char *mode, *security;
1576
1577         str = g_string_sized_new((bss->ssid_len * 2) + 24);
1578         if (!str)
1579                 return NULL;
1580
1581         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
1582                 for (i = 0; i < bss->ssid_len; i++)
1583                         g_string_append_printf(str, "%02x", bss->ssid[i]);
1584         } else
1585                 g_string_append_printf(str, "hidden");
1586
1587         mode = mode2string(bss->mode);
1588         if (mode)
1589                 g_string_append_printf(str, "_%s", mode);
1590
1591         security = security2string(bss->security);
1592         if (security)
1593                 g_string_append_printf(str, "_%s", security);
1594
1595         return g_string_free(str, FALSE);
1596 }
1597
1598 static int add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
1599 {
1600         GSupplicantInterface *interface = bss->interface;
1601         GSupplicantNetwork *network;
1602         char *group;
1603         bool is_new_network;
1604
1605         group = create_group(bss);
1606         SUPPLICANT_DBG("New group created: %s", group);
1607
1608         if (!group)
1609                 return -ENOMEM;
1610
1611         network = g_hash_table_lookup(interface->network_table, group);
1612         if (network) {
1613                 g_free(group);
1614                 SUPPLICANT_DBG("Network %s already exist", network->name);
1615                 is_new_network = false;
1616
1617                 goto done;
1618         }
1619
1620         is_new_network = true;
1621
1622         network = g_try_new0(GSupplicantNetwork, 1);
1623         if (!network) {
1624                 g_free(group);
1625                 return -ENOMEM;
1626         }
1627
1628         network->interface = interface;
1629         if (!network->path)
1630                 network->path = g_strdup(bss->path);
1631         network->group = group;
1632         network->name = create_name(bss->ssid, bss->ssid_len);
1633         network->mode = bss->mode;
1634         network->security = bss->security;
1635         network->ssid_len = bss->ssid_len;
1636         memcpy(network->ssid, bss->ssid, bss->ssid_len);
1637         network->signal = bss->signal;
1638         network->frequency = bss->frequency;
1639         network->best_bss = bss;
1640
1641         if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) {
1642                 network->wps = TRUE;
1643                 network->wps_capabilities = bss->wps_capabilities;
1644         }
1645
1646         SUPPLICANT_DBG("New network %s created", network->name);
1647
1648         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1649                                                         NULL, remove_bss);
1650
1651         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1652                                                         g_free, g_free);
1653
1654         g_hash_table_replace(interface->network_table,
1655                                                 network->group, network);
1656
1657         callback_network_added(network);
1658
1659 done:
1660         /* We update network's WPS properties if only bss provides WPS. */
1661         if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) {
1662                 network->wps = TRUE;
1663                 network->wps_capabilities = bss->wps_capabilities;
1664
1665                 if (!is_new_network)
1666                         callback_network_changed(network, "WPSCapabilities");
1667         }
1668
1669         /*
1670          * Do not change best BSS if we are connected. It will be done through
1671          * CurrentBSS property in case of misalignment with wpa_s or roaming.
1672          */
1673         if (network != interface->current_network &&
1674                                 bss->signal > network->signal) {
1675                 network->signal = bss->signal;
1676                 network->best_bss = bss;
1677                 callback_network_changed(network, "Signal");
1678         }
1679
1680         g_hash_table_replace(interface->bss_mapping, bss->path, network);
1681         g_hash_table_replace(network->bss_table, bss->path, bss);
1682
1683         g_hash_table_replace(bss_mapping, bss->path, interface);
1684
1685         return 0;
1686 }
1687
1688 static void bss_rates(DBusMessageIter *iter, void *user_data)
1689 {
1690         struct g_supplicant_bss *bss = user_data;
1691         dbus_uint32_t rate = 0;
1692
1693         dbus_message_iter_get_basic(iter, &rate);
1694         if (rate == 0)
1695                 return;
1696
1697         if (rate > bss->maxrate)
1698                 bss->maxrate = rate;
1699 }
1700
1701 static void bss_keymgmt(DBusMessageIter *iter, void *user_data)
1702 {
1703         unsigned int *keymgmt = user_data;
1704         const char *str = NULL;
1705         int i;
1706
1707         dbus_message_iter_get_basic(iter, &str);
1708         if (!str)
1709                 return;
1710
1711         for (i = 0; keymgmt_map[i].str; i++)
1712                 if (strcmp(str, keymgmt_map[i].str) == 0) {
1713                         SUPPLICANT_DBG("Keymgmt: %s", str);
1714                         *keymgmt |= keymgmt_map[i].val;
1715                         break;
1716                 }
1717 }
1718
1719 static void bss_group(DBusMessageIter *iter, void *user_data)
1720 {
1721         unsigned int *group = user_data;
1722         const char *str = NULL;
1723         int i;
1724
1725         dbus_message_iter_get_basic(iter, &str);
1726         if (!str)
1727                 return;
1728
1729         for (i = 0; group_map[i].str; i++)
1730                 if (strcmp(str, group_map[i].str) == 0) {
1731                         SUPPLICANT_DBG("Group: %s", str);
1732                         *group |= group_map[i].val;
1733                         break;
1734                 }
1735 }
1736
1737 static void bss_pairwise(DBusMessageIter *iter, void *user_data)
1738 {
1739         unsigned int *pairwise = user_data;
1740         const char *str = NULL;
1741         int i;
1742
1743         dbus_message_iter_get_basic(iter, &str);
1744         if (!str)
1745                 return;
1746
1747         for (i = 0; pairwise_map[i].str; i++)
1748                 if (strcmp(str, pairwise_map[i].str) == 0) {
1749                         SUPPLICANT_DBG("Pairwise: %s", str);
1750                         *pairwise |= pairwise_map[i].val;
1751                         break;
1752                 }
1753 }
1754
1755 static void bss_wpa(const char *key, DBusMessageIter *iter,
1756                         void *user_data)
1757 {
1758         struct g_supplicant_bss *bss = user_data;
1759         unsigned int value = 0;
1760
1761         SUPPLICANT_DBG("Key: %s", key);
1762
1763         if (g_strcmp0(key, "KeyMgmt") == 0) {
1764                 supplicant_dbus_array_foreach(iter, bss_keymgmt, &value);
1765
1766                 if (bss->rsn_selected)
1767                         bss->rsn_keymgmt = value;
1768                 else
1769                         bss->wpa_keymgmt = value;
1770         } else if (g_strcmp0(key, "Group") == 0) {
1771                 supplicant_dbus_array_foreach(iter, bss_group, &value);
1772
1773                 if (bss->rsn_selected)
1774                         bss->rsn_group = value;
1775                 else
1776                         bss->wpa_group = value;
1777         } else if (g_strcmp0(key, "Pairwise") == 0) {
1778                 supplicant_dbus_array_foreach(iter, bss_pairwise, &value);
1779
1780                 if (bss->rsn_selected)
1781                         bss->rsn_pairwise = value;
1782                 else
1783                         bss->wpa_pairwise = value;
1784         }
1785 }
1786
1787 static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size,
1788                                                         unsigned int type)
1789 {
1790         unsigned int len = 0;
1791
1792         while (len + 4 < ie_size) {
1793                 unsigned int hi = ie[len];
1794                 unsigned int lo = ie[len + 1];
1795                 unsigned int tmp_type = (hi << 8) + lo;
1796                 unsigned int v_len = 0;
1797
1798                 /* hi and lo are used to recreate an unsigned int
1799                  * based on 2 8bits length unsigned int. */
1800
1801                 hi = ie[len + 2];
1802                 lo = ie[len + 3];
1803                 v_len = (hi << 8) + lo;
1804
1805                 if (tmp_type == type) {
1806                         unsigned int ret_value = 0;
1807                         unsigned char *value = (unsigned char *)&ret_value;
1808
1809                         SUPPLICANT_DBG("IE: match type 0x%x", type);
1810
1811                         /* Verifying length relevance */
1812                         if (v_len > sizeof(unsigned int) ||
1813                                 len + 4 + v_len > ie_size)
1814                                 break;
1815
1816                         memcpy(value, ie + len + 4, v_len);
1817
1818                         SUPPLICANT_DBG("returning 0x%x", ret_value);
1819                         return ret_value;
1820                 }
1821
1822                 len += v_len + 4;
1823         }
1824
1825         SUPPLICANT_DBG("returning 0");
1826         return 0;
1827 }
1828
1829 static void bss_process_ies(DBusMessageIter *iter, void *user_data)
1830 {
1831         struct g_supplicant_bss *bss = user_data;
1832         const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
1833         unsigned char *ie, *ie_end;
1834         DBusMessageIter array;
1835         unsigned int value;
1836         int ie_len;
1837
1838 #define WMM_WPA1_WPS_INFO 221
1839 #define WPS_INFO_MIN_LEN  6
1840 #define WPS_VERSION_TLV   0x104A
1841 #define WPS_STATE_TLV     0x1044
1842 #define WPS_METHODS_TLV   0x1012
1843 #define WPS_REGISTRAR_TLV 0x1041
1844 #define WPS_VERSION       0x10
1845 #define WPS_PBC           0x04
1846 #define WPS_PIN           0x00
1847 #define WPS_CONFIGURED    0x02
1848
1849         dbus_message_iter_recurse(iter, &array);
1850         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1851
1852         if (!ie || ie_len < 2)
1853                 return;
1854
1855         bss->wps_capabilities = 0;
1856         bss->keymgmt = 0;
1857
1858         for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end;
1859                                                         ie += ie[1] + 2) {
1860
1861                 if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
1862                         memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
1863                         continue;
1864
1865                 SUPPLICANT_DBG("IE: match WPS_OUI");
1866
1867                 value = get_tlv(&ie[6], ie[1], WPS_STATE_TLV);
1868                 if (get_tlv(&ie[6], ie[1], WPS_VERSION_TLV) == WPS_VERSION &&
1869                                                                 value != 0) {
1870                         bss->keymgmt |= G_SUPPLICANT_KEYMGMT_WPS;
1871
1872                         if (value == WPS_CONFIGURED)
1873                                 bss->wps_capabilities |=
1874                                         G_SUPPLICANT_WPS_CONFIGURED;
1875                 }
1876
1877                 value = get_tlv(&ie[6], ie[1], WPS_METHODS_TLV);
1878                 if (value != 0) {
1879                         if (GUINT16_FROM_BE(value) == WPS_PBC)
1880                                 bss->wps_capabilities |= G_SUPPLICANT_WPS_PBC;
1881                         if (GUINT16_FROM_BE(value) == WPS_PIN)
1882                                 bss->wps_capabilities |= G_SUPPLICANT_WPS_PIN;
1883                 } else
1884                         bss->wps_capabilities |=
1885                                 G_SUPPLICANT_WPS_PBC | G_SUPPLICANT_WPS_PIN;
1886
1887                 /* If the AP sends this it means it's advertizing
1888                  * as a registrar and the WPS process is launched
1889                  * on its side */
1890                 if (get_tlv(&ie[6], ie[1], WPS_REGISTRAR_TLV) != 0)
1891                         bss->wps_capabilities |= G_SUPPLICANT_WPS_REGISTRAR;
1892
1893                 SUPPLICANT_DBG("WPS Methods 0x%x", bss->wps_capabilities);
1894         }
1895 }
1896
1897 static void bss_compute_security(struct g_supplicant_bss *bss)
1898 {
1899         /*
1900          * Combining RSN and WPA keymgmt
1901          * We combine it since parsing IEs might have set something for WPS. */
1902         bss->keymgmt |= bss->rsn_keymgmt | bss->wpa_keymgmt;
1903
1904         bss->ieee8021x = FALSE;
1905         bss->psk = FALSE;
1906
1907         if (bss->keymgmt &
1908                         (G_SUPPLICANT_KEYMGMT_WPA_EAP |
1909                                 G_SUPPLICANT_KEYMGMT_WPA_FT_EAP |
1910                                 G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
1911                 bss->ieee8021x = TRUE;
1912
1913         if (bss->keymgmt &
1914                         (G_SUPPLICANT_KEYMGMT_WPA_PSK |
1915                                 G_SUPPLICANT_KEYMGMT_WPA_FT_PSK |
1916                                 G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
1917                 bss->psk = TRUE;
1918
1919         if (bss->ieee8021x)
1920                 bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
1921         else if (bss->psk)
1922                 bss->security = G_SUPPLICANT_SECURITY_PSK;
1923         else if (bss->privacy)
1924                 bss->security = G_SUPPLICANT_SECURITY_WEP;
1925         else
1926                 bss->security = G_SUPPLICANT_SECURITY_NONE;
1927 }
1928
1929
1930 static void bss_property(const char *key, DBusMessageIter *iter,
1931                                                         void *user_data)
1932 {
1933         struct g_supplicant_bss *bss = user_data;
1934
1935         if (!bss->interface)
1936                 return;
1937
1938         SUPPLICANT_DBG("key %s", key);
1939
1940         if (!key)
1941                 return;
1942
1943         if (g_strcmp0(key, "BSSID") == 0) {
1944                 DBusMessageIter array;
1945                 unsigned char *addr;
1946                 int addr_len;
1947
1948                 dbus_message_iter_recurse(iter, &array);
1949                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
1950
1951                 if (addr_len == 6)
1952                         memcpy(bss->bssid, addr, addr_len);
1953         } else if (g_strcmp0(key, "SSID") == 0) {
1954                 DBusMessageIter array;
1955                 unsigned char *ssid;
1956                 int ssid_len;
1957
1958                 dbus_message_iter_recurse(iter, &array);
1959                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
1960
1961                 if (ssid_len > 0 && ssid_len < 33) {
1962                         memcpy(bss->ssid, ssid, ssid_len);
1963                         bss->ssid_len = ssid_len;
1964                 } else {
1965                         memset(bss->ssid, 0, sizeof(bss->ssid));
1966                         bss->ssid_len = 0;
1967                 }
1968         } else if (g_strcmp0(key, "Capabilities") == 0) {
1969                 dbus_uint16_t capabilities = 0x0000;
1970
1971                 dbus_message_iter_get_basic(iter, &capabilities);
1972
1973                 if (capabilities & IEEE80211_CAP_ESS)
1974                         bss->mode = G_SUPPLICANT_MODE_INFRA;
1975                 else if (capabilities & IEEE80211_CAP_IBSS)
1976                         bss->mode = G_SUPPLICANT_MODE_IBSS;
1977
1978                 if (capabilities & IEEE80211_CAP_PRIVACY)
1979                         bss->privacy = TRUE;
1980         } else if (g_strcmp0(key, "Mode") == 0) {
1981                 const char *mode = NULL;
1982
1983                 dbus_message_iter_get_basic(iter, &mode);
1984                 bss->mode = string2mode(mode);
1985         } else if (g_strcmp0(key, "Frequency") == 0) {
1986                 dbus_uint16_t frequency = 0;
1987
1988                 dbus_message_iter_get_basic(iter, &frequency);
1989                 bss->frequency = frequency;
1990         } else if (g_strcmp0(key, "Signal") == 0) {
1991                 dbus_int16_t signal = 0;
1992
1993                 dbus_message_iter_get_basic(iter, &signal);
1994
1995                 bss->signal = signal;
1996                 if (!bss->signal)
1997                         bss->signal = BSS_UNKNOWN_STRENGTH;
1998
1999         } else if (g_strcmp0(key, "Level") == 0) {
2000                 dbus_int32_t level = 0;
2001
2002                 dbus_message_iter_get_basic(iter, &level);
2003         } else if (g_strcmp0(key, "Rates") == 0) {
2004                 supplicant_dbus_array_foreach(iter, bss_rates, bss);
2005         } else if (g_strcmp0(key, "MaxRate") == 0) {
2006                 dbus_uint32_t maxrate = 0;
2007
2008                 dbus_message_iter_get_basic(iter, &maxrate);
2009                 if (maxrate != 0)
2010                         bss->maxrate = maxrate;
2011         } else if (g_strcmp0(key, "Privacy") == 0) {
2012                 dbus_bool_t privacy = FALSE;
2013
2014                 dbus_message_iter_get_basic(iter, &privacy);
2015                 bss->privacy = privacy;
2016         } else if (g_strcmp0(key, "RSN") == 0) {
2017                 bss->rsn_selected = TRUE;
2018
2019                 supplicant_dbus_property_foreach(iter, bss_wpa, bss);
2020         } else if (g_strcmp0(key, "WPA") == 0) {
2021                 bss->rsn_selected = FALSE;
2022
2023                 supplicant_dbus_property_foreach(iter, bss_wpa, bss);
2024         } else if (g_strcmp0(key, "IEs") == 0)
2025                 bss_process_ies(iter, bss);
2026         else
2027                 SUPPLICANT_DBG("key %s type %c",
2028                                 key, dbus_message_iter_get_arg_type(iter));
2029 }
2030
2031 static struct g_supplicant_bss *interface_bss_added(DBusMessageIter *iter,
2032                                                         void *user_data)
2033 {
2034         GSupplicantInterface *interface = user_data;
2035         GSupplicantNetwork *network;
2036         struct g_supplicant_bss *bss;
2037         const char *path = NULL;
2038
2039         SUPPLICANT_DBG("");
2040
2041         dbus_message_iter_get_basic(iter, &path);
2042         if (!path)
2043                 return NULL;
2044
2045         if (g_strcmp0(path, "/") == 0)
2046                 return NULL;
2047
2048         SUPPLICANT_DBG("%s", path);
2049
2050         network = g_hash_table_lookup(interface->bss_mapping, path);
2051         if (network) {
2052                 bss = g_hash_table_lookup(network->bss_table, path);
2053                 if (bss)
2054                         return NULL;
2055         }
2056
2057         bss = g_try_new0(struct g_supplicant_bss, 1);
2058         if (!bss)
2059                 return NULL;
2060
2061         bss->interface = interface;
2062         bss->path = g_strdup(path);
2063         bss->signal = BSS_UNKNOWN_STRENGTH;
2064
2065         return bss;
2066 }
2067
2068 static void interface_bss_added_with_keys(DBusMessageIter *iter,
2069                                                 void *user_data)
2070 {
2071         struct g_supplicant_bss *bss;
2072
2073         SUPPLICANT_DBG("");
2074
2075         bss = interface_bss_added(iter, user_data);
2076         if (!bss)
2077                 return;
2078
2079         dbus_message_iter_next(iter);
2080
2081         if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID)
2082                 return;
2083
2084         supplicant_dbus_property_foreach(iter, bss_property, bss);
2085
2086         bss_compute_security(bss);
2087         if (add_or_replace_bss_to_network(bss) < 0)
2088                 SUPPLICANT_DBG("add_or_replace_bss_to_network failed");
2089 }
2090
2091 static void interface_bss_added_without_keys(DBusMessageIter *iter,
2092                                                 void *user_data)
2093 {
2094         struct g_supplicant_bss *bss;
2095
2096         SUPPLICANT_DBG("");
2097
2098         bss = interface_bss_added(iter, user_data);
2099         if (!bss)
2100                 return;
2101
2102         supplicant_dbus_property_get_all(bss->path,
2103                                         SUPPLICANT_INTERFACE ".BSS",
2104                                         bss_property, bss, bss);
2105
2106         bss_compute_security(bss);
2107         if (add_or_replace_bss_to_network(bss) < 0)
2108                         SUPPLICANT_DBG("add_or_replace_bss_to_network failed");
2109 }
2110
2111 static void update_signal(gpointer key, gpointer value,
2112                                                 gpointer user_data)
2113 {
2114         struct g_supplicant_bss *bss = value;
2115         GSupplicantNetwork *network = user_data;
2116
2117         if (bss->signal > network->signal) {
2118                 network->signal = bss->signal;
2119                 network->best_bss = bss;
2120         }
2121 }
2122
2123 static void update_network_signal(GSupplicantNetwork *network)
2124 {
2125         if (g_hash_table_size(network->bss_table) <= 1 && network->best_bss)
2126                 return;
2127
2128         g_hash_table_foreach(network->bss_table,
2129                                 update_signal, network);
2130
2131         SUPPLICANT_DBG("New network signal %d", network->signal);
2132 }
2133
2134 static void interface_current_bss(GSupplicantInterface *interface,
2135                                                 DBusMessageIter *iter)
2136 {
2137         GSupplicantNetwork *network;
2138         struct g_supplicant_bss *bss;
2139         const char *path;
2140
2141         dbus_message_iter_get_basic(iter, &path);
2142         if (g_strcmp0(path, "/") == 0) {
2143                 interface->current_network = NULL;
2144                 return;
2145         }
2146
2147         interface_bss_added_without_keys(iter, interface);
2148
2149         network = g_hash_table_lookup(interface->bss_mapping, path);
2150         if (!network)
2151                 return;
2152
2153         bss = g_hash_table_lookup(network->bss_table, path);
2154         if (!bss)
2155                 return;
2156
2157         interface->current_network = network;
2158
2159         if (bss != network->best_bss) {
2160                 /*
2161                  * This is the case where either wpa_s got associated
2162                  * to a BSS different than the one ConnMan considers
2163                  * the best, or we are roaming.
2164                  */
2165                 SUPPLICANT_DBG("Update best BSS for %s", network->name);
2166
2167                 network->best_bss = bss;
2168
2169                 if (network->signal != bss->signal) {
2170                         SUPPLICANT_DBG("New network signal %d dBm",
2171                                                 bss->signal);
2172
2173                         network->signal = bss->signal;
2174                         callback_network_changed(network, "Signal");
2175                 }
2176         }
2177
2178         /*
2179          * wpa_s could notify about CurrentBSS in any state once
2180          * it got associated. It is not sure such notification will
2181          * arrive together with transition to ASSOCIATED state.
2182          * In fact, for networks with security WEP or OPEN, it
2183          * always arrives together with transition to COMPLETED.
2184          */
2185         switch (interface->state) {
2186         case G_SUPPLICANT_STATE_UNKNOWN:
2187         case G_SUPPLICANT_STATE_DISABLED:
2188         case G_SUPPLICANT_STATE_DISCONNECTED:
2189         case G_SUPPLICANT_STATE_INACTIVE:
2190         case G_SUPPLICANT_STATE_SCANNING:
2191         case G_SUPPLICANT_STATE_AUTHENTICATING:
2192         case G_SUPPLICANT_STATE_ASSOCIATING:
2193                 return;
2194         case G_SUPPLICANT_STATE_ASSOCIATED:
2195         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2196         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2197         case G_SUPPLICANT_STATE_COMPLETED:
2198                 callback_network_associated(network);
2199                 break;
2200         }
2201 }
2202
2203 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
2204 {
2205         GSupplicantInterface *interface = user_data;
2206         GSupplicantNetwork *network;
2207         struct g_supplicant_bss *bss = NULL;
2208         const char *path = NULL;
2209         bool is_current_network_bss = false;
2210
2211         dbus_message_iter_get_basic(iter, &path);
2212         if (!path)
2213                 return;
2214
2215         network = g_hash_table_lookup(interface->bss_mapping, path);
2216         if (!network)
2217                 return;
2218
2219         bss = g_hash_table_lookup(network->bss_table, path);
2220         if (network->best_bss == bss) {
2221                 network->best_bss = NULL;
2222                 network->signal = BSS_UNKNOWN_STRENGTH;
2223                 is_current_network_bss = true;
2224         }
2225
2226         g_hash_table_remove(bss_mapping, path);
2227
2228         g_hash_table_remove(interface->bss_mapping, path);
2229         g_hash_table_remove(network->bss_table, path);
2230
2231         update_network_signal(network);
2232
2233         if (g_hash_table_size(network->bss_table) == 0) {
2234                 g_hash_table_remove(interface->network_table, network->group);
2235         } else {
2236                 if (is_current_network_bss && network->best_bss)
2237                         callback_network_changed(network, "");
2238         }
2239 }
2240
2241 static void set_config_methods(DBusMessageIter *iter, void *user_data)
2242 {
2243         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, user_data);
2244 }
2245
2246 static void wps_property(const char *key, DBusMessageIter *iter,
2247                                                         void *user_data)
2248 {
2249         GSupplicantInterface *interface = user_data;
2250
2251         if (!interface)
2252                 return;
2253
2254         SUPPLICANT_DBG("key: %s", key);
2255
2256         if (g_strcmp0(key, "ConfigMethods") == 0) {
2257                 const char *config_methods = "push_button", *str = NULL;
2258
2259                 dbus_message_iter_get_basic(iter, &str);
2260                 if (str && strlen(str) > 0) {
2261                         /* It was already set at wpa_s level, don't modify it. */
2262                         SUPPLICANT_DBG("%s", str);
2263                         return;
2264                 }
2265
2266                 supplicant_dbus_property_set(interface->path,
2267                         SUPPLICANT_INTERFACE ".Interface.WPS",
2268                         "ConfigMethods", DBUS_TYPE_STRING_AS_STRING,
2269                         set_config_methods, NULL, &config_methods, NULL);
2270
2271                 SUPPLICANT_DBG("No value. Set %s", config_methods);
2272         }
2273
2274 }
2275
2276 static void interface_property(const char *key, DBusMessageIter *iter,
2277                                                         void *user_data)
2278 {
2279         GSupplicantInterface *interface = user_data;
2280
2281         if (!interface)
2282                 return;
2283
2284         SUPPLICANT_DBG("%s", key);
2285
2286         if (!key) {
2287                 debug_strvalmap("KeyMgmt capability", keymgmt_map,
2288                                                 interface->keymgmt_capa);
2289                 debug_strvalmap("AuthAlg capability", authalg_capa_map,
2290                                                 interface->authalg_capa);
2291                 debug_strvalmap("Protocol capability", proto_capa_map,
2292                                                 interface->proto_capa);
2293                 debug_strvalmap("Pairwise capability", pairwise_map,
2294                                                 interface->pairwise_capa);
2295                 debug_strvalmap("Group capability", group_map,
2296                                                 interface->group_capa);
2297                 debug_strvalmap("Scan capability", scan_capa_map,
2298                                                 interface->scan_capa);
2299                 debug_strvalmap("Mode capability", mode_capa_map,
2300                                                 interface->mode_capa);
2301
2302                 supplicant_dbus_property_get_all(interface->path,
2303                                 SUPPLICANT_INTERFACE ".Interface.WPS",
2304                                 wps_property, interface, interface);
2305
2306                 if (interface->ready)
2307                         callback_interface_added(interface);
2308
2309                 return;
2310         }
2311
2312         if (g_strcmp0(key, "Capabilities") == 0) {
2313                 supplicant_dbus_property_foreach(iter, interface_capability,
2314                                                                 interface);
2315                 if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_P2P)
2316                         interface->p2p_support = true;
2317         } else if (g_strcmp0(key, "State") == 0) {
2318                 const char *str = NULL;
2319
2320                 dbus_message_iter_get_basic(iter, &str);
2321                 if (str)
2322                         if (string2state(str) != interface->state) {
2323                                 interface->state = string2state(str);
2324                                 callback_interface_state(interface);
2325                         }
2326
2327                 if (interface->ap_create_in_progress) {
2328                         if (interface->state == G_SUPPLICANT_STATE_DISCONNECTED)
2329                                 callback_ap_create_fail(interface);
2330
2331                         interface->ap_create_in_progress = false;
2332                 }
2333
2334                 if (interface->state == G_SUPPLICANT_STATE_DISABLED)
2335                         interface->ready = FALSE;
2336                 else
2337                         interface->ready = TRUE;
2338
2339                 SUPPLICANT_DBG("state %s (%d)", str, interface->state);
2340         } else if (g_strcmp0(key, "Scanning") == 0) {
2341                 dbus_bool_t scanning = FALSE;
2342
2343                 dbus_message_iter_get_basic(iter, &scanning);
2344                 interface->scanning = scanning;
2345
2346                 if (interface->ready) {
2347                         if (interface->scanning)
2348                                 callback_scan_started(interface);
2349                         else
2350                                 callback_scan_finished(interface);
2351                 }
2352         } else if (g_strcmp0(key, "ApScan") == 0) {
2353                 int apscan = 1;
2354
2355                 dbus_message_iter_get_basic(iter, &apscan);
2356                 interface->apscan = apscan;
2357         } else if (g_strcmp0(key, "Ifname") == 0) {
2358                 const char *str = NULL;
2359
2360                 dbus_message_iter_get_basic(iter, &str);
2361                 if (str) {
2362                         g_free(interface->ifname);
2363                         interface->ifname = g_strdup(str);
2364                 }
2365         } else if (g_strcmp0(key, "Driver") == 0) {
2366                 const char *str = NULL;
2367
2368                 dbus_message_iter_get_basic(iter, &str);
2369                 if (str) {
2370                         g_free(interface->driver);
2371                         interface->driver = g_strdup(str);
2372                 }
2373         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
2374                 const char *str = NULL;
2375
2376                 dbus_message_iter_get_basic(iter, &str);
2377                 if (str) {
2378                         g_free(interface->bridge);
2379                         interface->bridge = g_strdup(str);
2380                 }
2381         } else if (g_strcmp0(key, "ConfigFile") == 0) {
2382                 const char *str = NULL;
2383
2384                 dbus_message_iter_get_basic(iter, &str);
2385                 if (str && strlen(str) > 0 && interface->ifname) {
2386                         SUPPLICANT_DBG("New {%s, %s}", interface->ifname, str);
2387                         g_hash_table_replace(config_file_table,
2388                                 g_strdup(interface->ifname), g_strdup(str));
2389                 }
2390         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
2391                 interface_current_bss(interface, iter);
2392         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
2393                 interface_network_added(iter, interface);
2394         } else if (g_strcmp0(key, "BSSs") == 0) {
2395                 supplicant_dbus_array_foreach(iter,
2396                                         interface_bss_added_without_keys,
2397                                         interface);
2398         } else if (g_strcmp0(key, "Blobs") == 0) {
2399                 /* Nothing */
2400         } else if (g_strcmp0(key, "Networks") == 0) {
2401                 supplicant_dbus_array_foreach(iter, interface_network_added,
2402                                                                 interface);
2403         } else if (g_strcmp0(key, "DisconnectReason") == 0) {
2404                 int reason_code;
2405                 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
2406                         dbus_message_iter_get_basic(iter, &reason_code);
2407                         callback_disconnect_reason_code(interface, reason_code);
2408                 }
2409         } else if (g_strcmp0(key, "AssocStatusCode") == 0) {
2410                 int status_code;
2411                 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
2412                         dbus_message_iter_get_basic(iter, &status_code);
2413                         callback_assoc_status_code(interface, status_code);
2414                 }
2415         } else {
2416                 SUPPLICANT_DBG("key %s type %c",
2417                                 key, dbus_message_iter_get_arg_type(iter));
2418         }
2419 }
2420
2421 static void scan_network_update(DBusMessageIter *iter, void *user_data)
2422 {
2423         GSupplicantInterface *interface = user_data;
2424         GSupplicantNetwork *network;
2425         char *path;
2426
2427         if (!iter)
2428                 return;
2429
2430         dbus_message_iter_get_basic(iter, &path);
2431
2432         if (!path)
2433                 return;
2434
2435         if (g_strcmp0(path, "/") == 0)
2436                 return;
2437
2438         /* Update the network details based on scan BSS data */
2439         network = g_hash_table_lookup(interface->bss_mapping, path);
2440         if (network)
2441                 callback_network_added(network);
2442 }
2443
2444 static void scan_bss_data(const char *key, DBusMessageIter *iter,
2445                                 void *user_data)
2446 {
2447         GSupplicantInterface *interface = user_data;
2448
2449         if (iter)
2450                 supplicant_dbus_array_foreach(iter, scan_network_update,
2451                                                 interface);
2452
2453         if (interface->scan_callback)
2454                 interface->scan_callback(0, interface, interface->scan_data);
2455
2456         interface->scan_callback = NULL;
2457         interface->scan_data = NULL;
2458 }
2459
2460 static GSupplicantInterface *interface_alloc(const char *path)
2461 {
2462         GSupplicantInterface *interface;
2463
2464         interface = g_try_new0(GSupplicantInterface, 1);
2465         if (!interface)
2466                 return NULL;
2467
2468         interface->path = g_strdup(path);
2469
2470         interface->network_table = g_hash_table_new_full(g_str_hash,
2471                                         g_str_equal, NULL, remove_network);
2472         interface->peer_table = g_hash_table_new_full(g_str_hash,
2473                                         g_str_equal, NULL, remove_peer);
2474         interface->group_table = g_hash_table_new_full(g_str_hash,
2475                                         g_str_equal, NULL, remove_group);
2476         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
2477                                                                 NULL, NULL);
2478
2479         g_hash_table_replace(interface_table, interface->path, interface);
2480
2481         return interface;
2482 }
2483
2484 static void interface_added(DBusMessageIter *iter, void *user_data)
2485 {
2486         GSupplicantInterface *interface;
2487         const char *path = NULL;
2488         bool properties_appended = GPOINTER_TO_UINT(user_data);
2489
2490         SUPPLICANT_DBG("");
2491
2492         dbus_message_iter_get_basic(iter, &path);
2493         if (!path)
2494                 return;
2495
2496         if (g_strcmp0(path, "/") == 0)
2497                 return;
2498
2499         interface = g_hash_table_lookup(interface_table, path);
2500         if (interface)
2501                 return;
2502
2503         interface = interface_alloc(path);
2504         if (!interface)
2505                 return;
2506
2507         if (!properties_appended) {
2508                 supplicant_dbus_property_get_all(path,
2509                                                 SUPPLICANT_INTERFACE ".Interface",
2510                                                 interface_property, interface,
2511                                                 interface);
2512                 return;
2513         }
2514
2515         dbus_message_iter_next(iter);
2516         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
2517                 supplicant_dbus_property_foreach(iter, interface_property,
2518                                                                 interface);
2519                 interface_property(NULL, NULL, interface);
2520         }
2521 }
2522
2523 static void interface_removed(DBusMessageIter *iter, void *user_data)
2524 {
2525         const char *path = NULL;
2526         GSupplicantInterface *interface = user_data;
2527
2528         dbus_message_iter_get_basic(iter, &path);
2529         if (!path)
2530                 return;
2531
2532         interface = g_hash_table_lookup(interface_table, path);
2533         g_supplicant_interface_cancel(interface);
2534
2535         g_hash_table_remove(interface_table, path);
2536 }
2537
2538 static void eap_method(DBusMessageIter *iter, void *user_data)
2539 {
2540         const char *str = NULL;
2541         int i;
2542
2543         dbus_message_iter_get_basic(iter, &str);
2544         if (!str)
2545                 return;
2546
2547         for (i = 0; eap_method_map[i].str; i++)
2548                 if (strcmp(str, eap_method_map[i].str) == 0) {
2549                         eap_methods |= eap_method_map[i].val;
2550                         break;
2551                 }
2552 }
2553
2554 static void service_property(const char *key, DBusMessageIter *iter,
2555                                                         void *user_data)
2556 {
2557         if (!key) {
2558                 callback_system_ready();
2559                 return;
2560         }
2561
2562         if (g_strcmp0(key, "DebugLevel") == 0) {
2563                 const char *str = NULL;
2564                 int i;
2565
2566                 dbus_message_iter_get_basic(iter, &str);
2567                 for (i = 0; debug_strings[i]; i++)
2568                         if (g_strcmp0(debug_strings[i], str) == 0) {
2569                                 debug_level = i;
2570                                 break;
2571                         }
2572                 SUPPLICANT_DBG("Debug level %d", debug_level);
2573         } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
2574                 dbus_message_iter_get_basic(iter, &debug_timestamp);
2575                 SUPPLICANT_DBG("Debug timestamp %u", debug_timestamp);
2576         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
2577                 dbus_message_iter_get_basic(iter, &debug_showkeys);
2578                 SUPPLICANT_DBG("Debug show keys %u", debug_showkeys);
2579         } else if (g_strcmp0(key, "Interfaces") == 0) {
2580                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
2581         } else if (g_strcmp0(key, "EapMethods") == 0) {
2582                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
2583                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
2584         } else if (g_strcmp0(key, "Country") == 0) {
2585                 const char *country = NULL;
2586
2587                 dbus_message_iter_get_basic(iter, &country);
2588                 SUPPLICANT_DBG("Country %s", country);
2589         } else
2590                 SUPPLICANT_DBG("key %s type %c",
2591                                 key, dbus_message_iter_get_arg_type(iter));
2592 }
2593
2594 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
2595 {
2596         const char *name = NULL, *old = NULL, *new = NULL;
2597
2598         SUPPLICANT_DBG("");
2599
2600         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
2601                 return;
2602
2603         dbus_message_iter_get_basic(iter, &name);
2604         if (!name)
2605                 return;
2606
2607         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
2608                 return;
2609
2610         dbus_message_iter_next(iter);
2611         dbus_message_iter_get_basic(iter, &old);
2612         dbus_message_iter_next(iter);
2613         dbus_message_iter_get_basic(iter, &new);
2614
2615         if (!old || !new)
2616                 return;
2617
2618         if (strlen(old) > 0 && strlen(new) == 0) {
2619                 system_available = FALSE;
2620                 g_hash_table_remove_all(bss_mapping);
2621                 g_hash_table_remove_all(peer_mapping);
2622                 g_hash_table_remove_all(group_mapping);
2623                 g_hash_table_remove_all(config_file_table);
2624                 g_hash_table_remove_all(interface_table);
2625                 callback_system_killed();
2626         }
2627
2628         if (strlen(new) > 0 && strlen(old) == 0) {
2629                 system_available = TRUE;
2630                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
2631                                                 SUPPLICANT_INTERFACE,
2632                                                 service_property, NULL, NULL);
2633         }
2634 }
2635
2636 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
2637 {
2638         SUPPLICANT_DBG("");
2639
2640         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
2641                 return;
2642
2643         supplicant_dbus_property_foreach(iter, service_property, NULL);
2644 }
2645
2646 static void signal_interface_added(const char *path, DBusMessageIter *iter)
2647 {
2648         SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
2649
2650         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
2651                 interface_added(iter, GUINT_TO_POINTER(true));
2652 }
2653
2654 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
2655 {
2656         SUPPLICANT_DBG("");
2657
2658         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
2659                 interface_removed(iter, NULL);
2660 }
2661
2662 static void signal_interface_changed(const char *path, DBusMessageIter *iter)
2663 {
2664         GSupplicantInterface *interface;
2665
2666         SUPPLICANT_DBG("");
2667
2668         interface = g_hash_table_lookup(interface_table, path);
2669         if (!interface)
2670                 return;
2671
2672         supplicant_dbus_property_foreach(iter, interface_property, interface);
2673 }
2674
2675 static void signal_scan_done(const char *path, DBusMessageIter *iter)
2676 {
2677         GSupplicantInterface *interface;
2678         dbus_bool_t success = FALSE;
2679
2680         SUPPLICANT_DBG("");
2681
2682         interface = g_hash_table_lookup(interface_table, path);
2683         if (!interface)
2684                 return;
2685
2686         dbus_message_iter_get_basic(iter, &success);
2687
2688         if (interface->scanning) {
2689                 callback_scan_finished(interface);
2690                 interface->scanning = FALSE;
2691         }
2692
2693         /*
2694          * If scan is unsuccessful return -EIO else get the scanned BSSs
2695          * and update the network details accordingly
2696          */
2697         if (!success) {
2698                 if (interface->scan_callback)
2699                         interface->scan_callback(-EIO, interface,
2700                                                 interface->scan_data);
2701
2702                 interface->scan_callback = NULL;
2703                 interface->scan_data = NULL;
2704
2705                 return;
2706         }
2707
2708         supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface",
2709                                 "BSSs", scan_bss_data, interface, interface);
2710 }
2711
2712 static void signal_bss_added(const char *path, DBusMessageIter *iter)
2713 {
2714         GSupplicantInterface *interface;
2715
2716         SUPPLICANT_DBG("");
2717
2718         interface = g_hash_table_lookup(interface_table, path);
2719         if (!interface)
2720                 return;
2721
2722         interface_bss_added_with_keys(iter, interface);
2723 }
2724
2725 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
2726 {
2727         GSupplicantInterface *interface;
2728
2729         SUPPLICANT_DBG("");
2730
2731         interface = g_hash_table_lookup(interface_table, path);
2732         if (!interface)
2733                 return;
2734
2735         interface_bss_removed(iter, interface);
2736 }
2737
2738 static void signal_network_added(const char *path, DBusMessageIter *iter)
2739 {
2740         GSupplicantInterface *interface;
2741
2742         SUPPLICANT_DBG("");
2743
2744         interface = g_hash_table_lookup(interface_table, path);
2745         if (!interface)
2746                 return;
2747
2748         interface_network_added(iter, interface);
2749 }
2750
2751 static void signal_network_removed(const char *path, DBusMessageIter *iter)
2752 {
2753         GSupplicantInterface *interface;
2754
2755         SUPPLICANT_DBG("");
2756
2757         interface = g_hash_table_lookup(interface_table, path);
2758         if (!interface)
2759                 return;
2760
2761         interface_network_removed(iter, interface);
2762 }
2763
2764 static void signal_sta_authorized(const char *path, DBusMessageIter *iter)
2765 {
2766         GSupplicantInterface *interface;
2767         const char *addr = NULL;
2768
2769         SUPPLICANT_DBG("");
2770
2771         interface = g_hash_table_lookup(interface_table, path);
2772         if (!interface)
2773                 return;
2774
2775         dbus_message_iter_get_basic(iter, &addr);
2776         if (!addr)
2777                 return;
2778
2779         callback_sta_authorized(interface, addr);
2780 }
2781
2782 static void signal_sta_deauthorized(const char *path, DBusMessageIter *iter)
2783 {
2784         GSupplicantInterface *interface;
2785         const char *addr = NULL;
2786
2787         SUPPLICANT_DBG("");
2788
2789         interface = g_hash_table_lookup(interface_table, path);
2790         if (!interface)
2791                 return;
2792
2793         dbus_message_iter_get_basic(iter, &addr);
2794         if (!addr)
2795                 return;
2796
2797         callback_sta_deauthorized(interface, addr);
2798 }
2799
2800 static void signal_bss_changed(const char *path, DBusMessageIter *iter)
2801 {
2802         GSupplicantInterface *interface;
2803         GSupplicantNetwork *network;
2804         GSupplicantSecurity old_security;
2805         unsigned int old_wps_capabilities;
2806         struct g_supplicant_bss *bss;
2807
2808         SUPPLICANT_DBG("");
2809
2810         interface = g_hash_table_lookup(bss_mapping, path);
2811         if (!interface)
2812                 return;
2813
2814         network = g_hash_table_lookup(interface->bss_mapping, path);
2815         if (!network)
2816                 return;
2817
2818         bss = g_hash_table_lookup(network->bss_table, path);
2819         if (!bss)
2820                 return;
2821
2822         supplicant_dbus_property_foreach(iter, bss_property, bss);
2823
2824         old_security = network->security;
2825         bss_compute_security(bss);
2826
2827         if (old_security != bss->security) {
2828                 struct g_supplicant_bss *new_bss;
2829
2830                 SUPPLICANT_DBG("New network security for %s with path %s",
2831                                bss->ssid, bss->path);
2832
2833                 /*
2834                  * Security change policy:
2835                  * - We first copy the current bss into a new one with
2836                  *   its own pointer (path)
2837                  * - Clear the old bss pointer and remove the network completely
2838                  *   if there are no more BSSs in the bss table.
2839                  * - The new bss will be added either to an existing network
2840                  *   or an additional network will be created
2841                  */
2842
2843                 new_bss = g_try_new0(struct g_supplicant_bss, 1);
2844                 if (!new_bss)
2845                         return;
2846
2847                 memcpy(new_bss, bss, sizeof(struct g_supplicant_bss));
2848                 new_bss->path = g_strdup(bss->path);
2849
2850                 if (network->best_bss == bss) {
2851                         network->best_bss = NULL;
2852                         network->signal = BSS_UNKNOWN_STRENGTH;
2853                 }
2854
2855                 g_hash_table_remove(bss_mapping, path);
2856
2857                 g_hash_table_remove(interface->bss_mapping, path);
2858                 g_hash_table_remove(network->bss_table, path);
2859
2860                 update_network_signal(network);
2861
2862                 if (g_hash_table_size(network->bss_table) == 0)
2863                         g_hash_table_remove(interface->network_table,
2864                                             network->group);
2865
2866                 if (add_or_replace_bss_to_network(new_bss) < 0) {
2867                         /*
2868                          * Prevent a memory leak on failure in
2869                          * add_or_replace_bss_to_network
2870                          */
2871                         SUPPLICANT_DBG("Failed to add bss %s to network table",
2872                                        new_bss->path);
2873                         g_free(new_bss->path);
2874                         g_free(new_bss);
2875                 }
2876
2877                 return;
2878         }
2879
2880         old_wps_capabilities = network->wps_capabilities;
2881
2882         if (old_wps_capabilities != bss->wps_capabilities) {
2883                 network->wps_capabilities = bss->wps_capabilities;
2884                 callback_network_changed(network, "WPSCapabilities");
2885         }
2886
2887         /* Consider only property changes of the connected BSS */
2888         if (network == interface->current_network && bss != network->best_bss)
2889                 return;
2890
2891         if (bss->signal == network->signal)
2892                 return;
2893
2894         /*
2895          * If the new signal is lower than the SSID signal, we need
2896          * to check for the new maximum.
2897          */
2898         if (bss->signal < network->signal) {
2899                 if (bss != network->best_bss)
2900                         return;
2901                 network->signal = bss->signal;
2902                 update_network_signal(network);
2903         } else {
2904                 network->signal = bss->signal;
2905                 network->best_bss = bss;
2906         }
2907
2908         SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid,
2909                         network->signal);
2910
2911         callback_network_changed(network, "Signal");
2912 }
2913
2914 static void wps_credentials(const char *key, DBusMessageIter *iter,
2915                         void *user_data)
2916 {
2917         GSupplicantInterface *interface = user_data;
2918
2919         if (!key)
2920                 return;
2921
2922         SUPPLICANT_DBG("key %s", key);
2923
2924         if (g_strcmp0(key, "Key") == 0) {
2925                 DBusMessageIter array;
2926                 unsigned char *key_val;
2927                 int key_len;
2928
2929                 dbus_message_iter_recurse(iter, &array);
2930                 dbus_message_iter_get_fixed_array(&array, &key_val, &key_len);
2931
2932                 g_free(interface->wps_cred.key);
2933                 interface->wps_cred.key = g_try_malloc0(
2934                                                 sizeof(char) * key_len + 1);
2935
2936                 if (!interface->wps_cred.key)
2937                         return;
2938
2939                 memcpy(interface->wps_cred.key, key_val,
2940                                                 sizeof(char) * key_len);
2941
2942                 SUPPLICANT_DBG("WPS key present");
2943         } else if (g_strcmp0(key, "SSID") == 0) {
2944                 DBusMessageIter array;
2945                 unsigned char *ssid;
2946                 int ssid_len;
2947
2948                 dbus_message_iter_recurse(iter, &array);
2949                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
2950
2951                 if (ssid_len > 0 && ssid_len < 33) {
2952                         memcpy(interface->wps_cred.ssid, ssid, ssid_len);
2953                         interface->wps_cred.ssid_len = ssid_len;
2954                 } else {
2955                         memset(interface->wps_cred.ssid, 0, 32);
2956                         interface->wps_cred.ssid_len = 0;
2957                 }
2958         }
2959 }
2960
2961 static void signal_wps_credentials(const char *path, DBusMessageIter *iter)
2962 {
2963         GSupplicantInterface *interface;
2964
2965         SUPPLICANT_DBG("");
2966
2967         interface = g_hash_table_lookup(interface_table, path);
2968         if (!interface)
2969                 return;
2970
2971         supplicant_dbus_property_foreach(iter, wps_credentials, interface);
2972 }
2973
2974 static void wps_event_args(const char *key, DBusMessageIter *iter,
2975                         void *user_data)
2976 {
2977         GSupplicantInterface *interface = user_data;
2978
2979         if (!key || !interface)
2980                 return;
2981
2982         SUPPLICANT_DBG("Arg Key %s", key);
2983 }
2984
2985 static void signal_wps_event(const char *path, DBusMessageIter *iter)
2986 {
2987         GSupplicantInterface *interface;
2988         const char *name = NULL;
2989
2990         SUPPLICANT_DBG("");
2991
2992         interface = g_hash_table_lookup(interface_table, path);
2993         if (!interface)
2994                 return;
2995
2996         dbus_message_iter_get_basic(iter, &name);
2997
2998         SUPPLICANT_DBG("Name: %s", name);
2999
3000         if (g_strcmp0(name, "success") == 0)
3001                 interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
3002         else if (g_strcmp0(name, "fail") == 0)
3003                 interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
3004         else
3005                 interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
3006
3007         if (!dbus_message_iter_has_next(iter))
3008                 return;
3009
3010         dbus_message_iter_next(iter);
3011
3012         supplicant_dbus_property_foreach(iter, wps_event_args, interface);
3013 }
3014
3015 static void create_peer_identifier(GSupplicantPeer *peer)
3016 {
3017         const unsigned char test[ETH_ALEN] = {};
3018
3019         if (!peer)
3020                 return;
3021
3022         if (!memcmp(peer->device_address, test, ETH_ALEN)) {
3023                 peer->identifier = g_strdup(peer->name);
3024                 return;
3025         }
3026
3027         peer->identifier = g_malloc0(19);
3028         snprintf(peer->identifier, 19, "%02x%02x%02x%02x%02x%02x",
3029                                                 peer->device_address[0],
3030                                                 peer->device_address[1],
3031                                                 peer->device_address[2],
3032                                                 peer->device_address[3],
3033                                                 peer->device_address[4],
3034                                                 peer->device_address[5]);
3035 }
3036
3037 struct peer_property_data {
3038         GSupplicantPeer *peer;
3039         GSList *old_groups;
3040         bool groups_changed;
3041         bool services_changed;
3042 };
3043
3044 static void peer_groups_relation(DBusMessageIter *iter, void *user_data)
3045 {
3046         struct peer_property_data *data = user_data;
3047         GSupplicantPeer *peer = data->peer;
3048         GSupplicantGroup *group;
3049         const char *str = NULL;
3050         GSList *elem;
3051
3052         dbus_message_iter_get_basic(iter, &str);
3053         if (!str)
3054                 return;
3055
3056         group = g_hash_table_lookup(group_mapping, str);
3057         if (!group)
3058                 return;
3059
3060         elem = g_slist_find_custom(data->old_groups, str, (GCompareFunc)g_strcmp0);
3061         if (elem) {
3062                 data->old_groups = g_slist_remove_link(data->old_groups, elem);
3063                 peer->groups = g_slist_concat(elem, peer->groups);
3064         } else {
3065                 peer->groups = g_slist_prepend(peer->groups, g_strdup(str));
3066                 data->groups_changed = true;
3067         }
3068 }
3069
3070 static void peer_property(const char *key, DBusMessageIter *iter,
3071                                                         void *user_data)
3072 {
3073         GSupplicantPeer *pending_peer;
3074         struct peer_property_data *data = user_data;
3075         GSupplicantPeer *peer = data->peer;
3076
3077         SUPPLICANT_DBG("key: %s", key);
3078
3079         if (!peer->interface)
3080                 return;
3081
3082         if (!key) {
3083                 if (peer->name) {
3084                         create_peer_identifier(peer);
3085                         callback_peer_found(peer);
3086                         pending_peer = g_hash_table_lookup(
3087                                         pending_peer_connection, peer->path);
3088
3089                         if (pending_peer && pending_peer == peer) {
3090                                 callback_peer_request(peer);
3091                                 g_hash_table_remove(pending_peer_connection,
3092                                                 peer->path);
3093                         }
3094
3095                         dbus_free(data);
3096                 }
3097
3098                 return;
3099         }
3100
3101         if (g_strcmp0(key, "DeviceAddress") == 0) {
3102                 unsigned char *dev_addr;
3103                 DBusMessageIter array;
3104                 int len;
3105
3106                 dbus_message_iter_recurse(iter, &array);
3107                 dbus_message_iter_get_fixed_array(&array, &dev_addr, &len);
3108
3109                 if (len == ETH_ALEN)
3110                         memcpy(peer->device_address, dev_addr, len);
3111         } else if (g_strcmp0(key, "DeviceName") == 0) {
3112                 const char *str = NULL;
3113
3114                 dbus_message_iter_get_basic(iter, &str);
3115                 if (str)
3116                         peer->name = g_strdup(str);
3117         } else if (g_strcmp0(key, "config_method") == 0) {
3118                 uint16_t wps_config;
3119
3120                 dbus_message_iter_get_basic(iter, &wps_config);
3121
3122                 if (wps_config & G_SUPPLICANT_WPS_CONFIG_PBC)
3123                         peer->wps_capabilities |= G_SUPPLICANT_WPS_PBC;
3124                 if (wps_config & ~G_SUPPLICANT_WPS_CONFIG_PBC)
3125                         peer->wps_capabilities |= G_SUPPLICANT_WPS_PIN;
3126         } else if (g_strcmp0(key, "Groups") == 0) {
3127                 data->old_groups = peer->groups;
3128                 peer->groups = NULL;
3129
3130                 supplicant_dbus_array_foreach(iter,
3131                                                 peer_groups_relation, data);
3132                 if (g_slist_length(data->old_groups) > 0) {
3133                         g_slist_free_full(data->old_groups, g_free);
3134                         data->groups_changed = true;
3135                 }
3136         } else if (g_strcmp0(key, "IEs") == 0) {
3137                 DBusMessageIter array;
3138                 unsigned char *ie;
3139                 int ie_len;
3140
3141                 dbus_message_iter_recurse(iter, &array);
3142                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
3143
3144                 if (!ie || ie_len < 2)
3145                         return;
3146
3147                 if (peer->widi_ies) {
3148                         if (memcmp(peer->widi_ies, ie, ie_len) == 0)
3149                                 return;
3150
3151                         g_free(peer->widi_ies);
3152                         peer->widi_ies_length = 0;
3153                 }
3154
3155                 peer->widi_ies = g_malloc0(ie_len * sizeof(unsigned char));
3156
3157                 memcpy(peer->widi_ies, ie, ie_len);
3158                 peer->widi_ies_length = ie_len;
3159                 data->services_changed = true;
3160         }
3161 }
3162
3163 static void signal_peer_found(const char *path, DBusMessageIter *iter)
3164 {
3165         struct peer_property_data *property_data;
3166         GSupplicantInterface *interface;
3167         const char *obj_path = NULL;
3168         GSupplicantPeer *peer;
3169
3170         SUPPLICANT_DBG("");
3171
3172         interface = g_hash_table_lookup(interface_table, path);
3173         if (!interface)
3174                 return;
3175
3176         dbus_message_iter_get_basic(iter, &obj_path);
3177         if (!obj_path || g_strcmp0(obj_path, "/") == 0)
3178                 return;
3179
3180         peer = g_hash_table_lookup(interface->peer_table, obj_path);
3181         if (peer)
3182                 return;
3183
3184         peer = g_try_new0(GSupplicantPeer, 1);
3185         if (!peer)
3186                 return;
3187
3188         peer->interface = interface;
3189         peer->path = g_strdup(obj_path);
3190         g_hash_table_insert(interface->peer_table, peer->path, peer);
3191         g_hash_table_replace(peer_mapping, peer->path, interface);
3192
3193         property_data = dbus_malloc0(sizeof(struct peer_property_data));
3194         property_data->peer = peer;
3195
3196         dbus_message_iter_next(iter);
3197         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
3198                 supplicant_dbus_property_foreach(iter, peer_property,
3199                                                         property_data);
3200                 peer_property(NULL, NULL, property_data);
3201                 return;
3202         }
3203
3204         supplicant_dbus_property_get_all(obj_path,
3205                                         SUPPLICANT_INTERFACE ".Peer",
3206                                         peer_property, property_data, NULL);
3207 }
3208
3209 static void signal_peer_lost(const char *path, DBusMessageIter *iter)
3210 {
3211         GSupplicantInterface *interface;
3212         const char *obj_path = NULL;
3213         GSupplicantPeer *peer;
3214
3215         SUPPLICANT_DBG("");
3216
3217         interface = g_hash_table_lookup(interface_table, path);
3218         if (!interface)
3219                 return;
3220
3221         dbus_message_iter_get_basic(iter, &obj_path);
3222         if (!obj_path || g_strcmp0(obj_path, "/") == 0)
3223                 return;
3224
3225         peer = g_hash_table_lookup(interface->peer_table, obj_path);
3226         if (!peer)
3227                 return;
3228
3229         g_hash_table_remove(interface->peer_table, obj_path);
3230 }
3231
3232 static void signal_peer_changed(const char *path, DBusMessageIter *iter)
3233 {
3234         struct peer_property_data *property_data;
3235         GSupplicantInterface *interface;
3236         GSupplicantPeer *peer;
3237
3238         SUPPLICANT_DBG("");
3239
3240         interface = g_hash_table_lookup(peer_mapping, path);
3241         if (!interface)
3242                 return;
3243
3244         peer = g_hash_table_lookup(interface->peer_table, path);
3245         if (!peer) {
3246                 g_hash_table_remove(peer_mapping, path);
3247                 return;
3248         }
3249
3250         property_data = dbus_malloc0(sizeof(struct peer_property_data));
3251         property_data->peer = peer;
3252
3253         supplicant_dbus_property_foreach(iter, peer_property, property_data);
3254         if (property_data->services_changed)
3255                 callback_peer_changed(peer,
3256                                         G_SUPPLICANT_PEER_SERVICES_CHANGED);
3257
3258         if (property_data->groups_changed)
3259                 callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_CHANGED);
3260
3261         dbus_free(property_data);
3262
3263         if (!g_supplicant_peer_is_in_a_group(peer))
3264                 peer->connection_requested = false;
3265 }
3266
3267 struct group_sig_data {
3268         const char *peer_obj_path;
3269         unsigned char iface_address[ETH_ALEN];
3270         const char *interface_obj_path;
3271         const char *group_obj_path;
3272         int role;
3273 };
3274
3275 static void group_sig_property(const char *key, DBusMessageIter *iter,
3276                                                         void *user_data)
3277 {
3278         struct group_sig_data *data = user_data;
3279
3280         if (!key)
3281                 return;
3282
3283         if (g_strcmp0(key, "peer_interface_addr") == 0) {
3284                 unsigned char *dev_addr;
3285                 DBusMessageIter array;
3286                 int len;
3287
3288                 dbus_message_iter_recurse(iter, &array);
3289                 dbus_message_iter_get_fixed_array(&array, &dev_addr, &len);
3290
3291                 if (len == ETH_ALEN)
3292                         memcpy(data->iface_address, dev_addr, len);
3293         } else if (g_strcmp0(key, "role") == 0) {
3294                 const char *str = NULL;
3295
3296                 dbus_message_iter_get_basic(iter, &str);
3297                 if (g_strcmp0(str, "GO") == 0)
3298                         data->role = G_SUPPLICANT_GROUP_ROLE_GO;
3299                 else
3300                         data->role = G_SUPPLICANT_GROUP_ROLE_CLIENT;
3301         } else if (g_strcmp0(key, "peer_object") == 0)
3302                 dbus_message_iter_get_basic(iter, &data->peer_obj_path);
3303         else if (g_strcmp0(key, "interface_object") == 0)
3304                 dbus_message_iter_get_basic(iter, &data->interface_obj_path);
3305         else if (g_strcmp0(key, "group_object") == 0)
3306                 dbus_message_iter_get_basic(iter, &data->group_obj_path);
3307
3308 }
3309
3310 static void signal_group_success(const char *path, DBusMessageIter *iter)
3311 {
3312         GSupplicantInterface *interface;
3313         struct group_sig_data data = {};
3314         GSupplicantPeer *peer;
3315
3316         SUPPLICANT_DBG("");
3317
3318         interface = g_hash_table_lookup(interface_table, path);
3319         if (!interface)
3320                 return;
3321
3322         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3323         if (!data.peer_obj_path)
3324                 return;
3325
3326         peer = g_hash_table_lookup(interface->peer_table, data.peer_obj_path);
3327         if (!peer)
3328                 return;
3329
3330         memcpy(peer->iface_address, data.iface_address, ETH_ALEN);
3331         interface->pending_peer_path = peer->path;
3332 }
3333
3334 static void signal_group_failure(const char *path, DBusMessageIter *iter)
3335 {
3336         GSupplicantInterface *interface;
3337         struct group_sig_data data = {};
3338         GSupplicantPeer *peer;
3339
3340         SUPPLICANT_DBG("");
3341
3342         interface = g_hash_table_lookup(interface_table, path);
3343         if (!interface)
3344                 return;
3345
3346         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3347         if (!data.peer_obj_path)
3348                 return;
3349
3350         peer = g_hash_table_lookup(interface->peer_table, data.peer_obj_path);
3351         if (!peer)
3352                 return;
3353
3354         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_FAILED);
3355         peer->connection_requested = false;
3356 }
3357
3358 static void signal_group_started(const char *path, DBusMessageIter *iter)
3359 {
3360         GSupplicantInterface *interface, *g_interface;
3361         struct group_sig_data data = {};
3362         GSupplicantGroup *group;
3363         GSupplicantPeer *peer;
3364
3365         SUPPLICANT_DBG("");
3366
3367         interface = g_hash_table_lookup(interface_table, path);
3368         if (!interface)
3369                 return;
3370
3371         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3372         if (!data.interface_obj_path || !data.group_obj_path)
3373                 return;
3374
3375         peer = g_hash_table_lookup(interface->peer_table,
3376                                                 interface->pending_peer_path);
3377         interface->pending_peer_path = NULL;
3378         if (!peer)
3379                 return;
3380
3381         g_interface = g_hash_table_lookup(interface_table,
3382                                                 data.interface_obj_path);
3383         if (!g_interface)
3384                 return;
3385
3386         group = g_hash_table_lookup(interface->group_table,
3387                                                 data.group_obj_path);
3388         if (group)
3389                 return;
3390
3391         group = g_try_new0(GSupplicantGroup, 1);
3392         if (!group)
3393                 return;
3394
3395         group->interface = g_interface;
3396         group->orig_interface = interface;
3397         group->path = g_strdup(data.group_obj_path);
3398         group->role = data.role;
3399
3400         g_hash_table_insert(interface->group_table, group->path, group);
3401         g_hash_table_replace(group_mapping, group->path, group);
3402
3403         peer->current_group_iface = g_interface;
3404         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_STARTED);
3405 }
3406
3407 static void remove_peer_group_interface(GHashTable *group_table,
3408                                 const char* path)
3409 {
3410         GSupplicantGroup *group;
3411         GHashTableIter iter;
3412         gpointer value, key;
3413
3414         if (!group_table)
3415                 return;
3416
3417         group = g_hash_table_lookup(group_table, path);
3418
3419         if (!group || !group->orig_interface)
3420                 return;
3421
3422         g_hash_table_iter_init(&iter, group->orig_interface->peer_table);
3423
3424         while (g_hash_table_iter_next(&iter, &key, &value)) {
3425                 GSupplicantPeer *peer = value;
3426
3427                 if (peer->current_group_iface == group->interface)
3428                         peer->current_group_iface = NULL;
3429         }
3430 }
3431
3432 static void signal_group_finished(const char *path, DBusMessageIter *iter)
3433 {
3434         GSupplicantInterface *interface;
3435         struct group_sig_data data = {};
3436
3437         SUPPLICANT_DBG("");
3438
3439         interface = g_hash_table_lookup(interface_table, path);
3440         if (!interface)
3441                 return;
3442
3443         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3444         if (!data.interface_obj_path || !data.group_obj_path)
3445                 return;
3446
3447         remove_peer_group_interface(interface->group_table, data.group_obj_path);
3448
3449         g_hash_table_remove(group_mapping, data.group_obj_path);
3450
3451         g_hash_table_remove(interface->group_table, data.group_obj_path);
3452 }
3453
3454 static void signal_group_request(const char *path, DBusMessageIter *iter)
3455 {
3456         GSupplicantInterface *interface;
3457         GSupplicantPeer *peer;
3458         const char *obj_path;
3459
3460         SUPPLICANT_DBG("");
3461
3462         interface = g_hash_table_lookup(interface_table, path);
3463         if (!interface)
3464                 return;
3465
3466         dbus_message_iter_get_basic(iter, &obj_path);
3467         if (!obj_path || !g_strcmp0(obj_path, "/"))
3468                 return;
3469
3470         peer = g_hash_table_lookup(interface->peer_table, obj_path);
3471         if (!peer)
3472                 return;
3473
3474         /*
3475          * Peer has been previously found and property set,
3476          * otherwise, defer connection to when peer property
3477          * is set.
3478          */
3479         if (peer->identifier)
3480                 callback_peer_request(peer);
3481         else
3482                 g_hash_table_replace(pending_peer_connection, peer->path, peer);
3483 }
3484
3485 static void signal_group_peer_joined(const char *path, DBusMessageIter *iter)
3486 {
3487         const char *peer_path = NULL;
3488         GSupplicantInterface *interface;
3489         GSupplicantGroup *group;
3490         GSupplicantPeer *peer;
3491
3492         SUPPLICANT_DBG("");
3493
3494         group = g_hash_table_lookup(group_mapping, path);
3495         if (!group)
3496                 return;
3497
3498         dbus_message_iter_get_basic(iter, &peer_path);
3499         if (!peer_path)
3500                 return;
3501
3502         interface = g_hash_table_lookup(peer_mapping, peer_path);
3503         if (!interface)
3504                 return;
3505
3506         peer = g_hash_table_lookup(interface->peer_table, peer_path);
3507         if (!peer)
3508                 return;
3509
3510         group->members = g_slist_prepend(group->members, g_strdup(peer_path));
3511
3512         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_JOINED);
3513 }
3514
3515 static void signal_group_peer_disconnected(const char *path, DBusMessageIter *iter)
3516 {
3517         const char *peer_path = NULL;
3518         GSupplicantInterface *interface;
3519         GSupplicantGroup *group;
3520         GSupplicantPeer *peer;
3521         GSList *elem;
3522
3523         SUPPLICANT_DBG("");
3524
3525         group = g_hash_table_lookup(group_mapping, path);
3526         if (!group)
3527                 return;
3528
3529         dbus_message_iter_get_basic(iter, &peer_path);
3530         if (!peer_path)
3531                 return;
3532
3533         for (elem = group->members; elem; elem = elem->next) {
3534                 if (!g_strcmp0(elem->data, peer_path))
3535                         break;
3536         }
3537
3538         if (!elem)
3539                 return;
3540
3541         g_free(elem->data);
3542         group->members = g_slist_delete_link(group->members, elem);
3543
3544         interface = g_hash_table_lookup(peer_mapping, peer_path);
3545         if (!interface)
3546                 return;
3547
3548         peer = g_hash_table_lookup(interface->peer_table, peer_path);
3549         if (!peer)
3550                 return;
3551
3552         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_DISCONNECTED);
3553         peer->connection_requested = false;
3554 }
3555
3556 static struct {
3557         const char *interface;
3558         const char *member;
3559         void (*function) (const char *path, DBusMessageIter *iter);
3560 } signal_map[] = {
3561         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
3562
3563         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
3564         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
3565         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
3566         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
3567
3568         { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
3569         { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done         },
3570         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added         },
3571         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed       },
3572         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
3573         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
3574         { SUPPLICANT_INTERFACE ".Interface", "StaAuthorized",     signal_sta_authorized    },
3575         { SUPPLICANT_INTERFACE ".Interface", "StaDeauthorized",   signal_sta_deauthorized  },
3576
3577         { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed   },
3578
3579         { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
3580         { SUPPLICANT_INTERFACE ".Interface.WPS", "Event",       signal_wps_event       },
3581
3582         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceFound", signal_peer_found },
3583         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceLost",  signal_peer_lost  },
3584
3585         { SUPPLICANT_INTERFACE ".Peer", "PropertiesChanged", signal_peer_changed },
3586
3587         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationSuccess", signal_group_success },
3588         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationFailure", signal_group_failure },
3589         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupStarted", signal_group_started },
3590         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupFinished", signal_group_finished },
3591         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationRequest", signal_group_request },
3592
3593         { SUPPLICANT_INTERFACE ".Group", "PeerJoined", signal_group_peer_joined },
3594         { SUPPLICANT_INTERFACE ".Group", "PeerDisconnected", signal_group_peer_disconnected },
3595
3596         { }
3597 };
3598
3599 static DBusHandlerResult g_supplicant_filter(DBusConnection *conn,
3600                                         DBusMessage *message, void *data)
3601 {
3602         DBusMessageIter iter;
3603         const char *path;
3604         int i;
3605
3606         path = dbus_message_get_path(message);
3607         if (!path)
3608                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3609
3610         if (!dbus_message_iter_init(message, &iter))
3611                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3612
3613         for (i = 0; signal_map[i].interface; i++) {
3614                 if (!dbus_message_has_interface(message, signal_map[i].interface))
3615                         continue;
3616
3617                 if (!dbus_message_has_member(message, signal_map[i].member))
3618                         continue;
3619
3620                 signal_map[i].function(path, &iter);
3621                 break;
3622         }
3623
3624         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3625 }
3626
3627 void g_supplicant_interface_cancel(GSupplicantInterface *interface)
3628 {
3629         SUPPLICANT_DBG("Cancelling any pending DBus calls");
3630         supplicant_dbus_method_call_cancel_all(interface);
3631         supplicant_dbus_property_call_cancel_all(interface);
3632 }
3633
3634 struct supplicant_regdom {
3635         GSupplicantCountryCallback callback;
3636         const char *alpha2;
3637         const void *user_data;
3638 };
3639
3640 static void country_result(const char *error,
3641                                 DBusMessageIter *iter, void *user_data)
3642 {
3643         struct supplicant_regdom *regdom = user_data;
3644         int result = 0;
3645
3646         SUPPLICANT_DBG("Country setting result");
3647
3648         if (!user_data)
3649                 return;
3650
3651         if (error) {
3652                 SUPPLICANT_DBG("Country setting failure %s", error);
3653                 result = -EINVAL;
3654         }
3655
3656         if (regdom->callback)
3657                 regdom->callback(result, regdom->alpha2,
3658                                         (void *) regdom->user_data);
3659
3660         g_free(regdom);
3661 }
3662
3663 static void country_params(DBusMessageIter *iter, void *user_data)
3664 {
3665         struct supplicant_regdom *regdom = user_data;
3666
3667         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
3668                                                         &regdom->alpha2);
3669 }
3670
3671 int g_supplicant_set_country(const char *alpha2,
3672                                 GSupplicantCountryCallback callback,
3673                                         const void *user_data)
3674 {
3675         struct supplicant_regdom *regdom;
3676         int ret;
3677
3678         SUPPLICANT_DBG("Country setting %s", alpha2);
3679
3680         if (!system_available)
3681                 return -EFAULT;
3682
3683         regdom = dbus_malloc0(sizeof(*regdom));
3684         if (!regdom)
3685                 return -ENOMEM;
3686
3687         regdom->callback = callback;
3688         regdom->alpha2 = alpha2;
3689         regdom->user_data = user_data;
3690
3691         ret =  supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
3692                                         "Country", DBUS_TYPE_STRING_AS_STRING,
3693                                         country_params, country_result,
3694                                         regdom, NULL);
3695         if (ret < 0) {
3696                 dbus_free(regdom);
3697                 SUPPLICANT_DBG("Unable to set Country configuration");
3698         }
3699         return ret;
3700 }
3701
3702 int g_supplicant_interface_set_country(GSupplicantInterface *interface,
3703                                         GSupplicantCountryCallback callback,
3704                                                         const char *alpha2,
3705                                                         void *user_data)
3706 {
3707         struct supplicant_regdom *regdom;
3708         int ret;
3709
3710         regdom = dbus_malloc0(sizeof(*regdom));
3711         if (!regdom)
3712                 return -ENOMEM;
3713
3714         regdom->callback = callback;
3715         regdom->alpha2 = alpha2;
3716         regdom->user_data = user_data;
3717
3718         ret =  supplicant_dbus_property_set(interface->path,
3719                                 SUPPLICANT_INTERFACE ".Interface",
3720                                 "Country", DBUS_TYPE_STRING_AS_STRING,
3721                                 country_params, country_result,
3722                                         regdom, NULL);
3723         if (ret < 0) {
3724                 dbus_free(regdom);
3725                 SUPPLICANT_DBG("Unable to set Country configuration");
3726         }
3727
3728         return ret;
3729 }
3730
3731 bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface)
3732 {
3733         if (!interface)
3734                 return false;
3735
3736         return interface->p2p_support;
3737 }
3738
3739 struct supplicant_p2p_dev_config {
3740         char *device_name;
3741         char *dev_type;
3742 };
3743
3744 static void p2p_device_config_result(const char *error,
3745                                         DBusMessageIter *iter, void *user_data)
3746 {
3747         struct supplicant_p2p_dev_config *config = user_data;
3748
3749         if (error)
3750                 SUPPLICANT_DBG("Unable to set P2P Device configuration: %s",
3751                                                                         error);
3752
3753         g_free(config->device_name);
3754         g_free(config->dev_type);
3755         dbus_free(config);
3756 }
3757
3758 static int dev_type_str2bin(const char *type, unsigned char dev_type[8])
3759 {
3760         int length, pos, end;
3761         char b[3] = {};
3762         char *e = NULL;
3763
3764         end = strlen(type);
3765         for (length = pos = 0; type[pos] != '\0' && length < 8; length++) {
3766                 if (pos+2 > end)
3767                         return 0;
3768
3769                 b[0] = type[pos];
3770                 b[1] = type[pos+1];
3771
3772                 dev_type[length] = strtol(b, &e, 16);
3773                 if (e && *e != '\0')
3774                         return 0;
3775
3776                 pos += 2;
3777         }
3778
3779         return 8;
3780 }
3781
3782 static void p2p_device_config_params(DBusMessageIter *iter, void *user_data)
3783 {
3784         struct supplicant_p2p_dev_config *config = user_data;
3785         DBusMessageIter dict;
3786
3787         supplicant_dbus_dict_open(iter, &dict);
3788
3789         supplicant_dbus_dict_append_basic(&dict, "DeviceName",
3790                                 DBUS_TYPE_STRING, &config->device_name);
3791
3792         if (config->dev_type) {
3793                 unsigned char dev_type[8] = {}, *type;
3794                 int len;
3795
3796                 len = dev_type_str2bin(config->dev_type, dev_type);
3797                 if (len) {
3798                         type = dev_type;
3799                         supplicant_dbus_dict_append_fixed_array(&dict,
3800                                         "PrimaryDeviceType",
3801                                         DBUS_TYPE_BYTE, &type, len);
3802                 }
3803         }
3804
3805         supplicant_dbus_dict_close(iter, &dict);
3806 }
3807
3808 int g_supplicant_interface_set_p2p_device_config(GSupplicantInterface *interface,
3809                                         const char *device_name,
3810                                         const char *primary_dev_type)
3811 {
3812         struct supplicant_p2p_dev_config *config;
3813         int ret;
3814
3815         SUPPLICANT_DBG("P2P Device settings %s/%s",
3816                                         device_name, primary_dev_type);
3817
3818         config = dbus_malloc0(sizeof(*config));
3819         if (!config)
3820                 return -ENOMEM;
3821
3822         config->device_name = g_strdup(device_name);
3823         config->dev_type = g_strdup(primary_dev_type);
3824
3825         ret = supplicant_dbus_property_set(interface->path,
3826                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
3827                                 "P2PDeviceConfig",
3828                                 DBUS_TYPE_ARRAY_AS_STRING
3829                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
3830                                 DBUS_TYPE_STRING_AS_STRING
3831                                 DBUS_TYPE_VARIANT_AS_STRING
3832                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
3833                                 p2p_device_config_params,
3834                                 p2p_device_config_result, config, NULL);
3835         if (ret < 0) {
3836                 g_free(config->device_name);
3837                 g_free(config->dev_type);
3838                 dbus_free(config);
3839                 SUPPLICANT_DBG("Unable to set P2P Device configuration");
3840         }
3841
3842         return ret;
3843 }
3844
3845 static gboolean peer_lookup_by_identifier(gpointer key, gpointer value,
3846                                                         gpointer user_data)
3847 {
3848         const GSupplicantPeer *peer = value;
3849         const char *identifier = user_data;
3850
3851         if (!g_strcmp0(identifier, peer->identifier))
3852                 return TRUE;
3853
3854         return FALSE;
3855 }
3856
3857 GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interface,
3858                                                         const char *identifier)
3859 {
3860         GSupplicantPeer *peer;
3861
3862         peer = g_hash_table_find(interface->peer_table,
3863                                         peer_lookup_by_identifier,
3864                                         (void *) identifier);
3865         return peer;
3866 }
3867
3868 static void interface_create_data_free(struct interface_create_data *data)
3869 {
3870         g_free(data->ifname);
3871         g_free(data->driver);
3872         g_free(data->bridge);
3873         dbus_free(data);
3874 }
3875
3876 static bool interface_exists(GSupplicantInterface *interface,
3877                                 const char *path)
3878 {
3879         GSupplicantInterface *tmp;
3880
3881         tmp = g_hash_table_lookup(interface_table, path);
3882         if (tmp && tmp == interface)
3883                 return true;
3884
3885         return false;
3886 }
3887
3888 static void interface_create_property(const char *key, DBusMessageIter *iter,
3889                                                         void *user_data)
3890 {
3891         struct interface_create_data *data = user_data;
3892         GSupplicantInterface *interface = data->interface;
3893
3894         if (!key) {
3895                 if (data->callback) {
3896                         data->callback(0, data->interface, data->user_data);
3897                         callback_p2p_support(interface);
3898                 }
3899
3900                 interface_create_data_free(data);
3901         }
3902
3903         interface_property(key, iter, interface);
3904 }
3905
3906 static void interface_create_result(const char *error,
3907                                 DBusMessageIter *iter, void *user_data)
3908 {
3909         struct interface_create_data *data = user_data;
3910         const char *path = NULL;
3911         int err;
3912
3913         SUPPLICANT_DBG("");
3914
3915         if (error) {
3916                 g_warning("error %s", error);
3917                 err = -EIO;
3918                 goto done;
3919         }
3920
3921         dbus_message_iter_get_basic(iter, &path);
3922         if (!path) {
3923                 err = -EINVAL;
3924                 goto done;
3925         }
3926
3927         if (!system_available) {
3928                 err = -EFAULT;
3929                 goto done;
3930         }
3931
3932         data->interface = g_hash_table_lookup(interface_table, path);
3933         if (!data->interface) {
3934                 data->interface = interface_alloc(path);
3935                 if (!data->interface) {
3936                         err = -ENOMEM;
3937                         goto done;
3938                 }
3939         }
3940
3941         err = supplicant_dbus_property_get_all(path,
3942                                         SUPPLICANT_INTERFACE ".Interface",
3943                                         interface_create_property, data,
3944                                         NULL);
3945         if (err == 0)
3946                 return;
3947
3948 done:
3949         if (data->callback)
3950                 data->callback(err, NULL, data->user_data);
3951
3952         interface_create_data_free(data);
3953 }
3954
3955 static void interface_create_params(DBusMessageIter *iter, void *user_data)
3956 {
3957         struct interface_create_data *data = user_data;
3958         DBusMessageIter dict;
3959         char *config_file = NULL;
3960
3961         SUPPLICANT_DBG("");
3962
3963         supplicant_dbus_dict_open(iter, &dict);
3964
3965         supplicant_dbus_dict_append_basic(&dict, "Ifname",
3966                                         DBUS_TYPE_STRING, &data->ifname);
3967
3968         if (data->driver)
3969                 supplicant_dbus_dict_append_basic(&dict, "Driver",
3970                                         DBUS_TYPE_STRING, &data->driver);
3971
3972         if (data->bridge)
3973                 supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
3974                                         DBUS_TYPE_STRING, &data->bridge);
3975
3976         config_file = g_hash_table_lookup(config_file_table, data->ifname);
3977         if (config_file) {
3978                 SUPPLICANT_DBG("[%s] ConfigFile %s", data->ifname, config_file);
3979
3980                 supplicant_dbus_dict_append_basic(&dict, "ConfigFile",
3981                                         DBUS_TYPE_STRING, &config_file);
3982         }
3983
3984         supplicant_dbus_dict_close(iter, &dict);
3985 }
3986
3987 static void interface_get_result(const char *error,
3988                                 DBusMessageIter *iter, void *user_data)
3989 {
3990         struct interface_create_data *data = user_data;
3991         GSupplicantInterface *interface;
3992         const char *path = NULL;
3993         int err;
3994
3995         SUPPLICANT_DBG("");
3996
3997         if (error) {
3998                 SUPPLICANT_DBG("Interface not created yet");
3999                 goto create;
4000         }
4001
4002         dbus_message_iter_get_basic(iter, &path);
4003         if (!path) {
4004                 err = -EINVAL;
4005                 goto done;
4006         }
4007
4008         interface = g_hash_table_lookup(interface_table, path);
4009         if (!interface) {
4010                 err = -ENOENT;
4011                 goto done;
4012         }
4013
4014         if (data->callback) {
4015                 data->callback(0, interface, data->user_data);
4016                 callback_p2p_support(interface);
4017         }
4018
4019         interface_create_data_free(data);
4020
4021         return;
4022
4023 create:
4024         if (!system_available) {
4025                 err = -EFAULT;
4026                 goto done;
4027         }
4028
4029         SUPPLICANT_DBG("Creating interface");
4030
4031         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
4032                                                 SUPPLICANT_INTERFACE,
4033                                                 "CreateInterface",
4034                                                 interface_create_params,
4035                                                 interface_create_result, data,
4036                                                 NULL);
4037         if (err == 0)
4038                 return;
4039
4040 done:
4041         if (data->callback)
4042                 data->callback(err, NULL, data->user_data);
4043
4044         interface_create_data_free(data);
4045 }
4046
4047 static void interface_get_params(DBusMessageIter *iter, void *user_data)
4048 {
4049         struct interface_create_data *data = user_data;
4050
4051         SUPPLICANT_DBG("");
4052
4053         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
4054 }
4055
4056 int g_supplicant_interface_create(const char *ifname, const char *driver,
4057                                         const char *bridge,
4058                                         GSupplicantInterfaceCallback callback,
4059                                                         void *user_data)
4060 {
4061         struct interface_create_data *data;
4062         int ret;
4063
4064         SUPPLICANT_DBG("ifname %s", ifname);
4065
4066         if (!ifname)
4067                 return -EINVAL;
4068
4069         if (!system_available)
4070                 return -EFAULT;
4071
4072         data = dbus_malloc0(sizeof(*data));
4073         if (!data)
4074                 return -ENOMEM;
4075
4076         data->ifname = g_strdup(ifname);
4077         data->driver = g_strdup(driver);
4078         data->bridge = g_strdup(bridge);
4079         data->callback = callback;
4080         data->user_data = user_data;
4081
4082         ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
4083                                                 SUPPLICANT_INTERFACE,
4084                                                 "GetInterface",
4085                                                 interface_get_params,
4086                                                 interface_get_result, data,
4087                                                 NULL);
4088         if (ret < 0)
4089                 interface_create_data_free(data);
4090
4091         return ret;
4092 }
4093
4094 static void interface_remove_result(const char *error,
4095                                 DBusMessageIter *iter, void *user_data)
4096 {
4097         struct interface_data *data = user_data;
4098         int err;
4099
4100         if (error) {
4101                 err = -EIO;
4102                 SUPPLICANT_DBG("error: %s", error);
4103                 goto done;
4104         }
4105
4106         if (!system_available) {
4107                 err = -EFAULT;
4108                 goto done;
4109         }
4110
4111         /*
4112          * The gsupplicant interface is already freed by the InterfaceRemoved
4113          * signal callback. Simply invoke the interface_data callback.
4114          */
4115         err = 0;
4116
4117 done:
4118         g_free(data->path);
4119
4120         if (data->callback)
4121                 data->callback(err, NULL, data->user_data);
4122
4123         dbus_free(data);
4124 }
4125
4126
4127 static void interface_remove_params(DBusMessageIter *iter, void *user_data)
4128 {
4129         struct interface_data *data = user_data;
4130
4131         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
4132                                                         &data->interface->path);
4133 }
4134
4135
4136 int g_supplicant_interface_remove(GSupplicantInterface *interface,
4137                         GSupplicantInterfaceCallback callback,
4138                                                         void *user_data)
4139 {
4140         struct interface_data *data;
4141         int ret;
4142
4143         if (!interface)
4144                 return -EINVAL;
4145
4146         if (!system_available)
4147                 return -EFAULT;
4148
4149         g_supplicant_interface_cancel(interface);
4150
4151         data = dbus_malloc0(sizeof(*data));
4152         if (!data)
4153                 return -ENOMEM;
4154
4155         data->interface = interface;
4156         data->path = g_strdup(interface->path);
4157         data->callback = callback;
4158         data->user_data = user_data;
4159
4160         ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
4161                                                 SUPPLICANT_INTERFACE,
4162                                                 "RemoveInterface",
4163                                                 interface_remove_params,
4164                                                 interface_remove_result, data,
4165                                                 NULL);
4166         if (ret < 0) {
4167                 g_free(data->path);
4168                 dbus_free(data);
4169         }
4170         return ret;
4171 }
4172
4173 static void interface_scan_result(const char *error,
4174                                 DBusMessageIter *iter, void *user_data)
4175 {
4176         struct interface_scan_data *data = user_data;
4177         int err = 0;
4178
4179         if (error) {
4180                 SUPPLICANT_DBG("error %s", error);
4181                 err = -EIO;
4182         }
4183
4184         /* A non ready interface cannot send/receive anything */
4185         if (interface_exists(data->interface, data->path)) {
4186                 if (!data->interface->ready)
4187                         err = -ENOLINK;
4188         }
4189
4190         g_free(data->path);
4191
4192         if (err != 0) {
4193                 if (data->callback)
4194                         data->callback(err, data->interface, data->user_data);
4195         } else {
4196                 data->interface->scan_callback = data->callback;
4197                 data->interface->scan_data = data->user_data;
4198         }
4199
4200         if (data->scan_params)
4201                 g_supplicant_free_scan_params(data->scan_params);
4202
4203         dbus_free(data);
4204 }
4205
4206 static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq)
4207 {
4208         DBusMessageIter data;
4209         unsigned int width = 0; /* Not used by wpa_supplicant atm */
4210
4211         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data);
4212
4213         dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq);
4214         dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width);
4215
4216         dbus_message_iter_close_container(iter, &data);
4217 }
4218
4219 static void add_scan_frequencies(DBusMessageIter *iter,
4220                                                 void *user_data)
4221 {
4222         GSupplicantScanParams *scan_data = user_data;
4223         unsigned int freq;
4224         int i;
4225
4226         for (i = 0; i < scan_data->num_freqs; i++) {
4227                 freq = scan_data->freqs[i];
4228                 if (!freq)
4229                         break;
4230
4231                 add_scan_frequency(iter, freq);
4232         }
4233 }
4234
4235 static void append_ssid(DBusMessageIter *iter,
4236                         const void *ssid, unsigned int len)
4237 {
4238         DBusMessageIter array;
4239
4240         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
4241         DBUS_TYPE_BYTE_AS_STRING, &array);
4242
4243         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
4244                                                                 &ssid, len);
4245         dbus_message_iter_close_container(iter, &array);
4246 }
4247
4248 static void append_ssids(DBusMessageIter *iter, void *user_data)
4249 {
4250         GSupplicantScanParams *scan_data = user_data;
4251         GSList *list;
4252
4253         for (list = scan_data->ssids; list; list = list->next) {
4254                 struct scan_ssid *scan_ssid = list->data;
4255
4256                 append_ssid(iter, scan_ssid->ssid, scan_ssid->ssid_len);
4257         }
4258 }
4259
4260 static void supplicant_add_scan_frequency(DBusMessageIter *dict,
4261                 supplicant_dbus_array_function function,
4262                                         void *user_data)
4263 {
4264         GSupplicantScanParams *scan_params = user_data;
4265         DBusMessageIter entry, value, array;
4266         const char *key = "Channels";
4267
4268         if (scan_params->freqs && scan_params->freqs[0] != 0) {
4269                 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
4270                                                 NULL, &entry);
4271
4272                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
4273
4274                 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
4275                                         DBUS_TYPE_ARRAY_AS_STRING
4276                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
4277                                         DBUS_TYPE_UINT32_AS_STRING
4278                                         DBUS_TYPE_UINT32_AS_STRING
4279                                         DBUS_STRUCT_END_CHAR_AS_STRING,
4280                                         &value);
4281
4282                 dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
4283                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
4284                                         DBUS_TYPE_UINT32_AS_STRING
4285                                         DBUS_TYPE_UINT32_AS_STRING
4286                                         DBUS_STRUCT_END_CHAR_AS_STRING,
4287                                         &array);
4288
4289                 if (function)
4290                         function(&array, user_data);
4291
4292                 dbus_message_iter_close_container(&value, &array);
4293                 dbus_message_iter_close_container(&entry, &value);
4294                 dbus_message_iter_close_container(dict, &entry);
4295         }
4296 }
4297
4298 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
4299 {
4300         DBusMessageIter dict;
4301         const char *type = "passive";
4302         struct interface_scan_data *data = user_data;
4303
4304         supplicant_dbus_dict_open(iter, &dict);
4305
4306         if (data && data->scan_params) {
4307                 type = "active";
4308
4309                 supplicant_dbus_dict_append_basic(&dict, "Type",
4310                                         DBUS_TYPE_STRING, &type);
4311
4312
4313                 if (data->scan_params->ssids) {
4314                         supplicant_dbus_dict_append_array(&dict, "SSIDs",
4315                                                         DBUS_TYPE_STRING,
4316                                                         append_ssids,
4317                                                         data->scan_params);
4318                 }
4319                 supplicant_add_scan_frequency(&dict, add_scan_frequencies,
4320                                                 data->scan_params);
4321         } else
4322                 supplicant_dbus_dict_append_basic(&dict, "Type",
4323                                         DBUS_TYPE_STRING, &type);
4324
4325         supplicant_dbus_dict_close(iter, &dict);
4326 }
4327
4328 static int interface_ready_to_scan(GSupplicantInterface *interface)
4329 {
4330         if (!interface)
4331                 return -EINVAL;
4332
4333         if (!system_available)
4334                 return -EFAULT;
4335
4336         if (interface->scanning)
4337                 return -EALREADY;
4338
4339         switch (interface->state) {
4340         case G_SUPPLICANT_STATE_AUTHENTICATING:
4341         case G_SUPPLICANT_STATE_ASSOCIATING:
4342         case G_SUPPLICANT_STATE_ASSOCIATED:
4343         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4344         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4345                 return -EBUSY;
4346         case G_SUPPLICANT_STATE_UNKNOWN:
4347         case G_SUPPLICANT_STATE_DISABLED:
4348         case G_SUPPLICANT_STATE_DISCONNECTED:
4349         case G_SUPPLICANT_STATE_INACTIVE:
4350         case G_SUPPLICANT_STATE_SCANNING:
4351         case G_SUPPLICANT_STATE_COMPLETED:
4352                 break;
4353         }
4354
4355         return 0;
4356 }
4357
4358 int g_supplicant_interface_scan(GSupplicantInterface *interface,
4359                                 GSupplicantScanParams *scan_data,
4360                                 GSupplicantInterfaceCallback callback,
4361                                                         void *user_data)
4362 {
4363         struct interface_scan_data *data;
4364         int ret;
4365
4366         ret = interface_ready_to_scan(interface);
4367         if (ret)
4368                 return ret;
4369
4370         data = dbus_malloc0(sizeof(*data));
4371         if (!data)
4372                 return -ENOMEM;
4373
4374         data->interface = interface;
4375         data->path = g_strdup(interface->path);
4376         data->callback = callback;
4377         data->user_data = user_data;
4378         data->scan_params = scan_data;
4379
4380         interface->scan_callback = callback;
4381         interface->scan_data = user_data;
4382
4383         ret = supplicant_dbus_method_call(interface->path,
4384                         SUPPLICANT_INTERFACE ".Interface", "Scan",
4385                         interface_scan_params, interface_scan_result, data,
4386                         interface);
4387
4388         if (ret < 0) {
4389                 g_free(data->path);
4390                 dbus_free(data);
4391         }
4392
4393         return ret;
4394 }
4395
4396 static int parse_supplicant_error(DBusMessageIter *iter)
4397 {
4398         int err = -ECONNABORTED;
4399         char *key;
4400
4401         if (!iter)
4402                 return err;
4403
4404         /* If the given passphrase is malformed wpa_s returns
4405          * "invalid message format" but this error should be interpreted as
4406          * invalid-key.
4407          */
4408         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
4409                 dbus_message_iter_get_basic(iter, &key);
4410                 if (strncmp(key, "psk", 3) == 0 ||
4411                                 strncmp(key, "wep_key", 7) == 0 ||
4412                                 strcmp(key, "invalid message format") == 0) {
4413                         err = -ENOKEY;
4414                         break;
4415                 }
4416                 dbus_message_iter_next(iter);
4417         }
4418
4419         return err;
4420 }
4421
4422 static void interface_select_network_result(const char *error,
4423                                 DBusMessageIter *iter, void *user_data)
4424 {
4425         struct interface_connect_data *data = user_data;
4426         int err;
4427
4428         SUPPLICANT_DBG("");
4429
4430         err = 0;
4431         if (error) {
4432                 SUPPLICANT_DBG("SelectNetwork error %s", error);
4433                 err = parse_supplicant_error(iter);
4434         }
4435
4436         g_free(data->path);
4437
4438         if (data->callback)
4439                 data->callback(err, data->interface, data->user_data);
4440
4441         g_free(data->ssid);
4442         dbus_free(data);
4443 }
4444
4445 static void interface_select_network_params(DBusMessageIter *iter,
4446                                                         void *user_data)
4447 {
4448         struct interface_connect_data *data = user_data;
4449         GSupplicantInterface *interface = data->interface;
4450
4451         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
4452                                         &interface->network_path);
4453 }
4454
4455 static void interface_add_network_result(const char *error,
4456                                 DBusMessageIter *iter, void *user_data)
4457 {
4458         struct interface_connect_data *data = user_data;
4459         GSupplicantInterface *interface = data->interface;
4460         const char *path;
4461         int err;
4462
4463         if (error)
4464                 goto error;
4465
4466         dbus_message_iter_get_basic(iter, &path);
4467         if (!path)
4468                 goto error;
4469
4470         SUPPLICANT_DBG("PATH: %s", path);
4471
4472         interface->network_path = g_strdup(path);
4473
4474         store_network_information(interface, data->ssid);
4475
4476         supplicant_dbus_method_call(data->interface->path,
4477                         SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
4478                         interface_select_network_params,
4479                         interface_select_network_result, data,
4480                         interface);
4481
4482         return;
4483
4484 error:
4485         SUPPLICANT_DBG("AddNetwork error %s", error);
4486
4487         if (interface_exists(data->interface, data->interface->path)) {
4488                 err = parse_supplicant_error(iter);
4489                 if (data->callback)
4490                         data->callback(err, data->interface, data->user_data);
4491
4492                 g_free(interface->network_path);
4493                 interface->network_path = NULL;
4494         }
4495
4496         g_free(data->path);
4497         g_free(data->ssid);
4498         g_free(data);
4499 }
4500
4501 static void add_network_security_none(DBusMessageIter *dict)
4502 {
4503         const char *auth_alg = "OPEN";
4504
4505         supplicant_dbus_dict_append_basic(dict, "auth_alg",
4506                                         DBUS_TYPE_STRING, &auth_alg);
4507 }
4508
4509 static void add_network_security_wep(DBusMessageIter *dict,
4510                                         GSupplicantSSID *ssid)
4511 {
4512         const char *auth_alg = "OPEN SHARED";
4513         dbus_uint32_t key_index = 0;
4514
4515         supplicant_dbus_dict_append_basic(dict, "auth_alg",
4516                                         DBUS_TYPE_STRING, &auth_alg);
4517
4518         if (ssid->passphrase) {
4519                 int size = strlen(ssid->passphrase);
4520                 if (size == 10 || size == 26) {
4521                         unsigned char *key = g_try_malloc(13);
4522                         char tmp[3];
4523                         int i;
4524
4525                         memset(tmp, 0, sizeof(tmp));
4526                         if (!key)
4527                                 size = 0;
4528
4529                         for (i = 0; i < size / 2; i++) {
4530                                 memcpy(tmp, ssid->passphrase + (i * 2), 2);
4531                                 key[i] = (unsigned char) strtol(tmp, NULL, 16);
4532                         }
4533
4534                         supplicant_dbus_dict_append_fixed_array(dict,
4535                                                         "wep_key0",
4536                                                         DBUS_TYPE_BYTE,
4537                                                         &key, size / 2);
4538                         g_free(key);
4539                 } else if (size == 5 || size == 13) {
4540                         unsigned char *key = g_try_malloc(13);
4541                         int i;
4542
4543                         if (!key)
4544                                 size = 0;
4545
4546                         for (i = 0; i < size; i++)
4547                                 key[i] = (unsigned char) ssid->passphrase[i];
4548
4549                         supplicant_dbus_dict_append_fixed_array(dict,
4550                                                                 "wep_key0",
4551                                                                 DBUS_TYPE_BYTE,
4552                                                                 &key, size);
4553                         g_free(key);
4554                 } else
4555                         supplicant_dbus_dict_append_basic(dict,
4556                                                         "wep_key0",
4557                                                         DBUS_TYPE_STRING,
4558                                                         &ssid->passphrase);
4559
4560                 supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx",
4561                                         DBUS_TYPE_UINT32, &key_index);
4562         }
4563 }
4564
4565 static dbus_bool_t is_psk_raw_key(const char *psk)
4566 {
4567         int i;
4568
4569         /* A raw key is always 64 bytes length... */
4570         if (strlen(psk) != 64)
4571                 return FALSE;
4572
4573         /* ... and its content is in hex representation */
4574         for (i = 0; i < 64; i++)
4575                 if (!isxdigit((unsigned char) psk[i]))
4576                         return FALSE;
4577
4578         return TRUE;
4579 }
4580
4581 static unsigned char hexchar2bin(char c)
4582 {
4583         if ((c >= '0') && (c <= '9'))
4584                 return c - '0';
4585         else if ((c >= 'A') && (c <= 'F'))
4586                 return c - 'A' + 10;
4587         else if ((c >= 'a') && (c <= 'f'))
4588                 return c - 'a' + 10;
4589         else
4590                 return c;
4591 }
4592
4593 static void hexstring2bin(const char *string, unsigned char *data,
4594                                 size_t data_len)
4595 {
4596         size_t i;
4597
4598         for (i = 0; i < data_len; i++)
4599                 data[i] = (hexchar2bin(string[i * 2 + 0]) << 4 |
4600                            hexchar2bin(string[i * 2 + 1]) << 0);
4601 }
4602
4603 static void add_network_security_psk(DBusMessageIter *dict,
4604                                         GSupplicantSSID *ssid)
4605 {
4606         if (ssid->passphrase && strlen(ssid->passphrase) > 0) {
4607                 const char *key = "psk";
4608
4609                 if (is_psk_raw_key(ssid->passphrase)) {
4610                         unsigned char data[32];
4611                         unsigned char *datap = data;
4612
4613                         /* The above pointer alias is required by D-Bus because
4614                          * with D-Bus and GCC, non-heap-allocated arrays cannot
4615                          * be passed directly by their base pointer. */
4616
4617                         hexstring2bin(ssid->passphrase, datap, sizeof(data));
4618
4619                         supplicant_dbus_dict_append_fixed_array(dict,
4620                                                         key, DBUS_TYPE_BYTE,
4621                                                         &datap, sizeof(data));
4622                 } else
4623                         supplicant_dbus_dict_append_basic(dict,
4624                                                         key, DBUS_TYPE_STRING,
4625                                                         &ssid->passphrase);
4626         }
4627 }
4628
4629 static void add_network_security_tls(DBusMessageIter *dict,
4630                                         GSupplicantSSID *ssid)
4631 {
4632         /*
4633          * For TLS, we at least need:
4634          *              The client certificate
4635          *              The client private key file
4636          *              The client private key file password
4637          *
4638          * The Authority certificate is optional.
4639          */
4640         if (!ssid->client_cert_path)
4641                 return;
4642
4643         if (!ssid->private_key_path)
4644                 return;
4645
4646         if (!ssid->private_key_passphrase)
4647                 return;
4648
4649         if (ssid->ca_cert_path)
4650                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
4651                                         DBUS_TYPE_STRING, &ssid->ca_cert_path);
4652
4653         supplicant_dbus_dict_append_basic(dict, "private_key",
4654                                                 DBUS_TYPE_STRING,
4655                                                 &ssid->private_key_path);
4656         supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
4657                                                 DBUS_TYPE_STRING,
4658                                                 &ssid->private_key_passphrase);
4659         supplicant_dbus_dict_append_basic(dict, "client_cert",
4660                                                 DBUS_TYPE_STRING,
4661                                                 &ssid->client_cert_path);
4662 }
4663
4664 static void add_network_security_peap(DBusMessageIter *dict,
4665                                         GSupplicantSSID *ssid)
4666 {
4667         char *phase2_auth;
4668
4669         /*
4670          * For PEAP/TTLS, we at least need
4671          *              The authority certificate
4672          *              The 2nd phase authentication method
4673          *              The 2nd phase passphrase
4674          *
4675          * The Client certificate is optional although strongly recommended
4676          * When setting it, we need in addition
4677          *              The Client private key file
4678          *              The Client private key file password
4679          */
4680         if (!ssid->passphrase)
4681                 return;
4682
4683         if (!ssid->phase2_auth)
4684                 return;
4685
4686         if (ssid->client_cert_path) {
4687                 if (!ssid->private_key_path)
4688                         return;
4689
4690                 if (!ssid->private_key_passphrase)
4691                         return;
4692
4693                 supplicant_dbus_dict_append_basic(dict, "client_cert",
4694                                                 DBUS_TYPE_STRING,
4695                                                 &ssid->client_cert_path);
4696
4697                 supplicant_dbus_dict_append_basic(dict, "private_key",
4698                                                 DBUS_TYPE_STRING,
4699                                                 &ssid->private_key_path);
4700
4701                 supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
4702                                                 DBUS_TYPE_STRING,
4703                                                 &ssid->private_key_passphrase);
4704
4705         }
4706
4707         if(g_strcmp0(ssid->phase2_auth, "GTC") == 0 && g_strcmp0(ssid->eap, "ttls") == 0)
4708                 phase2_auth = g_strdup_printf("autheap=%s", ssid->phase2_auth);
4709         else if (g_str_has_prefix(ssid->phase2_auth, "EAP-")) {
4710                 phase2_auth = g_strdup_printf("autheap=%s",
4711                                         ssid->phase2_auth + strlen("EAP-"));
4712         } else
4713                 phase2_auth = g_strdup_printf("auth=%s", ssid->phase2_auth);
4714
4715         supplicant_dbus_dict_append_basic(dict, "password",
4716                                                 DBUS_TYPE_STRING,
4717                                                 &ssid->passphrase);
4718
4719         if (ssid->ca_cert_path)
4720                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
4721                                                 DBUS_TYPE_STRING,
4722                                                 &ssid->ca_cert_path);
4723
4724         supplicant_dbus_dict_append_basic(dict, "phase2",
4725                                                 DBUS_TYPE_STRING,
4726                                                 &phase2_auth);
4727
4728         g_free(phase2_auth);
4729 }
4730
4731 static void add_network_security_eap(DBusMessageIter *dict,
4732                                         GSupplicantSSID *ssid)
4733 {
4734         char *eap_value;
4735
4736         if (!ssid->eap || !ssid->identity)
4737                 return;
4738
4739         if (g_strcmp0(ssid->eap, "tls") == 0) {
4740                 add_network_security_tls(dict, ssid);
4741         } else if (g_strcmp0(ssid->eap, "peap") == 0 ||
4742                                 g_strcmp0(ssid->eap, "ttls") == 0) {
4743                 add_network_security_peap(dict, ssid);
4744         } else
4745                 return;
4746
4747         eap_value = g_ascii_strup(ssid->eap, -1);
4748
4749         supplicant_dbus_dict_append_basic(dict, "eap",
4750                                                 DBUS_TYPE_STRING,
4751                                                 &eap_value);
4752         supplicant_dbus_dict_append_basic(dict, "identity",
4753                                                 DBUS_TYPE_STRING,
4754                                                 &ssid->identity);
4755         if(ssid->anonymous_identity)
4756                 supplicant_dbus_dict_append_basic(dict, "anonymous_identity",
4757                                                      DBUS_TYPE_STRING,
4758                                                      &ssid->anonymous_identity);
4759
4760         if(ssid->subject_match)
4761                 supplicant_dbus_dict_append_basic(dict, "subject_match",
4762                                                      DBUS_TYPE_STRING,
4763                                                      &ssid->subject_match);
4764
4765         if(ssid->altsubject_match)
4766                 supplicant_dbus_dict_append_basic(dict, "altsubject_match",
4767                                                      DBUS_TYPE_STRING,
4768                                                      &ssid->altsubject_match);
4769
4770         if(ssid->domain_suffix_match)
4771                 supplicant_dbus_dict_append_basic(dict, "domain_suffix_match",
4772                                                      DBUS_TYPE_STRING,
4773                                                      &ssid->domain_suffix_match);
4774
4775         if(ssid->domain_match)
4776                 supplicant_dbus_dict_append_basic(dict, "domain_match",
4777                                                      DBUS_TYPE_STRING,
4778                                                      &ssid->domain_match);
4779
4780         g_free(eap_value);
4781 }
4782
4783 static void add_network_security_ciphers(DBusMessageIter *dict,
4784                                                 GSupplicantSSID *ssid)
4785 {
4786         unsigned int p_cipher, g_cipher, i;
4787         char *pairwise, *group;
4788         char *pair_ciphers[4];
4789         char *group_ciphers[5];
4790
4791         p_cipher = ssid->pairwise_cipher;
4792         g_cipher = ssid->group_cipher;
4793
4794         if (p_cipher == 0 && g_cipher == 0)
4795                 return;
4796
4797         i = 0;
4798
4799         if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP)
4800                 pair_ciphers[i++] = "CCMP";
4801
4802         if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP)
4803                 pair_ciphers[i++] = "TKIP";
4804
4805         if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE)
4806                 pair_ciphers[i++] = "NONE";
4807
4808         pair_ciphers[i] = NULL;
4809
4810         i = 0;
4811
4812         if (g_cipher & G_SUPPLICANT_GROUP_CCMP)
4813                 group_ciphers[i++] = "CCMP";
4814
4815         if (g_cipher & G_SUPPLICANT_GROUP_TKIP)
4816                 group_ciphers[i++] = "TKIP";
4817
4818         if (g_cipher & G_SUPPLICANT_GROUP_WEP104)
4819                 group_ciphers[i++] = "WEP104";
4820
4821         if (g_cipher & G_SUPPLICANT_GROUP_WEP40)
4822                 group_ciphers[i++] = "WEP40";
4823
4824         group_ciphers[i] = NULL;
4825
4826         pairwise = g_strjoinv(" ", pair_ciphers);
4827         group = g_strjoinv(" ", group_ciphers);
4828
4829         SUPPLICANT_DBG("cipher %s %s", pairwise, group);
4830
4831         supplicant_dbus_dict_append_basic(dict, "pairwise",
4832                                                 DBUS_TYPE_STRING,
4833                                                 &pairwise);
4834         supplicant_dbus_dict_append_basic(dict, "group",
4835                                                 DBUS_TYPE_STRING,
4836                                                 &group);
4837
4838         g_free(pairwise);
4839         g_free(group);
4840 }
4841
4842 static void add_network_security_proto(DBusMessageIter *dict,
4843                                                 GSupplicantSSID *ssid)
4844 {
4845         unsigned int protocol, i;
4846         char *proto;
4847         char *protos[3];
4848
4849         protocol = ssid->protocol;
4850
4851         if (protocol == 0)
4852                 return;
4853
4854         i = 0;
4855
4856         if (protocol & G_SUPPLICANT_PROTO_RSN)
4857                 protos[i++] = "RSN";
4858
4859         if (protocol & G_SUPPLICANT_PROTO_WPA)
4860                 protos[i++] = "WPA";
4861
4862         protos[i] = NULL;
4863
4864         proto = g_strjoinv(" ", protos);
4865
4866         SUPPLICANT_DBG("proto %s", proto);
4867
4868         supplicant_dbus_dict_append_basic(dict, "proto",
4869                                                 DBUS_TYPE_STRING,
4870                                                 &proto);
4871
4872         g_free(proto);
4873 }
4874
4875 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
4876 {
4877         char *key_mgmt;
4878
4879         switch (ssid->security) {
4880         case G_SUPPLICANT_SECURITY_NONE:
4881                 key_mgmt = "NONE";
4882                 add_network_security_none(dict);
4883                 add_network_security_ciphers(dict, ssid);
4884                 break;
4885         case G_SUPPLICANT_SECURITY_UNKNOWN:
4886         case G_SUPPLICANT_SECURITY_WEP:
4887                 key_mgmt = "NONE";
4888                 add_network_security_wep(dict, ssid);
4889                 add_network_security_ciphers(dict, ssid);
4890                 break;
4891         case G_SUPPLICANT_SECURITY_PSK:
4892                 key_mgmt = "WPA-PSK";
4893                 add_network_security_psk(dict, ssid);
4894                 add_network_security_ciphers(dict, ssid);
4895                 add_network_security_proto(dict, ssid);
4896                 break;
4897         case G_SUPPLICANT_SECURITY_IEEE8021X:
4898                 key_mgmt = "WPA-EAP";
4899                 add_network_security_eap(dict, ssid);
4900                 add_network_security_ciphers(dict, ssid);
4901                 add_network_security_proto(dict, ssid);
4902                 break;
4903         }
4904
4905         supplicant_dbus_dict_append_basic(dict, "key_mgmt",
4906                                 DBUS_TYPE_STRING, &key_mgmt);
4907 }
4908
4909 static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid)
4910 {
4911         dbus_uint32_t mode;
4912
4913         switch (ssid->mode) {
4914         case G_SUPPLICANT_MODE_UNKNOWN:
4915         case G_SUPPLICANT_MODE_INFRA:
4916                 mode = 0;
4917                 break;
4918         case G_SUPPLICANT_MODE_IBSS:
4919                 mode = 1;
4920                 break;
4921         case G_SUPPLICANT_MODE_MASTER:
4922                 mode = 2;
4923                 break;
4924         }
4925
4926         supplicant_dbus_dict_append_basic(dict, "mode",
4927                                 DBUS_TYPE_UINT32, &mode);
4928 }
4929
4930 static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
4931 {
4932         DBusMessageIter dict;
4933         struct interface_connect_data *data = user_data;
4934         GSupplicantSSID *ssid = data->ssid;
4935
4936         supplicant_dbus_dict_open(iter, &dict);
4937
4938         if (ssid->scan_ssid)
4939                 supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
4940                                          DBUS_TYPE_UINT32, &ssid->scan_ssid);
4941
4942         if (ssid->freq)
4943                 supplicant_dbus_dict_append_basic(&dict, "frequency",
4944                                          DBUS_TYPE_UINT32, &ssid->freq);
4945
4946         if (ssid->bgscan)
4947                 supplicant_dbus_dict_append_basic(&dict, "bgscan",
4948                                         DBUS_TYPE_STRING, &ssid->bgscan);
4949
4950         add_network_mode(&dict, ssid);
4951
4952         add_network_security(&dict, ssid);
4953
4954         supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
4955                                         DBUS_TYPE_BYTE, &ssid->ssid,
4956                                                 ssid->ssid_len);
4957
4958         supplicant_dbus_dict_close(iter, &dict);
4959 }
4960
4961 static void interface_wps_start_result(const char *error,
4962                                 DBusMessageIter *iter, void *user_data)
4963 {
4964         struct interface_connect_data *data = user_data;
4965         int err;
4966
4967         SUPPLICANT_DBG("");
4968
4969         err = 0;
4970         if (error) {
4971                 SUPPLICANT_DBG("error: %s", error);
4972                 err = parse_supplicant_error(iter);
4973         }
4974
4975         if(data->callback)
4976                 data->callback(err, data->interface, data->user_data);
4977
4978         g_free(data->path);
4979         g_free(data->ssid);
4980         dbus_free(data);
4981 }
4982
4983 static void interface_add_wps_params(DBusMessageIter *iter, void *user_data)
4984 {
4985         struct interface_connect_data *data = user_data;
4986         GSupplicantSSID *ssid = data->ssid;
4987         const char *role = "enrollee", *type;
4988         DBusMessageIter dict;
4989
4990         SUPPLICANT_DBG("");
4991
4992         supplicant_dbus_dict_open(iter, &dict);
4993
4994         supplicant_dbus_dict_append_basic(&dict, "Role",
4995                                                 DBUS_TYPE_STRING, &role);
4996
4997         type = "pbc";
4998         if (ssid->pin_wps) {
4999                 type = "pin";
5000                 supplicant_dbus_dict_append_basic(&dict, "Pin",
5001                                         DBUS_TYPE_STRING, &ssid->pin_wps);
5002         }
5003
5004         supplicant_dbus_dict_append_basic(&dict, "Type",
5005                                         DBUS_TYPE_STRING, &type);
5006
5007         supplicant_dbus_dict_close(iter, &dict);
5008 }
5009
5010 static void wps_start(const char *error, DBusMessageIter *iter, void *user_data)
5011 {
5012         struct interface_connect_data *data = user_data;
5013
5014         SUPPLICANT_DBG("");
5015
5016         if (error) {
5017                 SUPPLICANT_DBG("error: %s", error);
5018                 g_free(data->path);
5019                 g_free(data->ssid);
5020                 dbus_free(data);
5021                 return;
5022         }
5023
5024         supplicant_dbus_method_call(data->interface->path,
5025                         SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
5026                         interface_add_wps_params,
5027                         interface_wps_start_result, data, NULL);
5028 }
5029
5030 static void wps_process_credentials(DBusMessageIter *iter, void *user_data)
5031 {
5032         dbus_bool_t credentials = TRUE;
5033
5034         SUPPLICANT_DBG("");
5035
5036         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials);
5037 }
5038
5039
5040 int g_supplicant_interface_connect(GSupplicantInterface *interface,
5041                                 GSupplicantSSID *ssid,
5042                                 GSupplicantInterfaceCallback callback,
5043                                                         void *user_data)
5044 {
5045         struct interface_connect_data *data;
5046         struct interface_data *intf_data;
5047         int ret = 0;
5048
5049         SUPPLICANT_DBG("");
5050
5051         if (!interface)
5052                 return -EINVAL;
5053
5054         if (!system_available)
5055                 return -EFAULT;
5056
5057         /* TODO: Check if we're already connected and switch */
5058
5059         data = dbus_malloc0(sizeof(*data));
5060         if (!data)
5061                 return -ENOMEM;
5062
5063         data->interface = interface;
5064         data->path = g_strdup(interface->path);
5065         data->callback = callback;
5066         data->ssid = ssid;
5067         data->user_data = user_data;
5068
5069         if (ssid->use_wps) {
5070                 g_free(interface->wps_cred.key);
5071                 memset(&interface->wps_cred, 0,
5072                                 sizeof(struct _GSupplicantWpsCredentials));
5073
5074                 ret = supplicant_dbus_property_set(interface->path,
5075                         SUPPLICANT_INTERFACE ".Interface.WPS",
5076                         "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
5077                         wps_process_credentials, wps_start, data, interface);
5078         } else {
5079                 /* By the time there is a request for connect and the network
5080                  * path is not NULL it means that connman has not removed the
5081                  * previous network pointer. This can happen in the case AP
5082                  * deauthenticated client and connman does not remove the
5083                  * previously connected network pointer. This causes supplicant
5084                  * to reallocate the memory for struct wpa_ssid again even if it
5085                  * is the same SSID. This causes memory usage of wpa_supplicnat
5086                  * to go high. The idea here is that if the previously connected
5087                  * network is not removed at the time of next connection attempt
5088                  * check if the network path is not NULL. In case it is non-NULL
5089                  * first remove the network and then once removal is successful, add
5090                  * the network.
5091                  */
5092
5093                 if (interface->network_path != NULL) {
5094                         g_free(data->path);
5095                         dbus_free(data);
5096
5097                         /*
5098                          * If this add network is for the same network for
5099                          * which wpa_supplicant already has a profile then do
5100                          * not need to add another profile. Only if the
5101                          * profile that needs to get added is different from
5102                          * what is there in wpa_s delete the current one. A
5103                          * network is identified by its SSID, security_type
5104                          * and passphrase (private passphrase in case security
5105                          * type is 802.11x).
5106                          */
5107                         if (compare_network_parameters(interface, ssid)) {
5108                                 return -EALREADY;
5109                         }
5110
5111                         intf_data = dbus_malloc0(sizeof(*intf_data));
5112                         if (!intf_data)
5113                                 return -ENOMEM;
5114
5115                         intf_data->interface = interface;
5116                         intf_data->path = g_strdup(interface->path);
5117                         intf_data->callback = callback;
5118                         intf_data->ssid = ssid;
5119                         intf_data->user_data = user_data;
5120                         intf_data->network_remove_in_progress = TRUE;
5121                         network_remove(intf_data);
5122                 } else {
5123                         ret = supplicant_dbus_method_call(interface->path,
5124                                         SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
5125                                         interface_add_network_params,
5126                                         interface_add_network_result, data,
5127                                         interface);
5128                 }
5129         }
5130
5131         if (ret < 0) {
5132                 g_free(data->path);
5133                 dbus_free(data);
5134                 return ret;
5135         }
5136
5137         return -EINPROGRESS;
5138 }
5139
5140 static void network_remove_result(const char *error,
5141                                 DBusMessageIter *iter, void *user_data)
5142 {
5143         struct interface_data *data = user_data;
5144         struct interface_connect_data *connect_data;
5145         int result = 0;
5146
5147         SUPPLICANT_DBG("");
5148
5149         if (error) {
5150                 result = -EIO;
5151                 SUPPLICANT_DBG("error: %s", error);
5152
5153                 if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
5154                                                 error) == 0)
5155                         result = -ECONNABORTED;
5156         }
5157
5158         g_free(data->interface->network_path);
5159         data->interface->network_path = NULL;
5160
5161         remove_network_information(data->interface);
5162
5163         if (data->network_remove_in_progress == TRUE) {
5164                 data->network_remove_in_progress = FALSE;
5165                 connect_data = dbus_malloc0(sizeof(*connect_data));
5166                 if (!connect_data)
5167                         return;
5168
5169                 connect_data->interface = data->interface;
5170                 connect_data->path = g_strdup(data->path);
5171                 connect_data->callback = data->callback;
5172                 connect_data->ssid = data->ssid;
5173                 connect_data->user_data = data->user_data;
5174
5175                 supplicant_dbus_method_call(data->interface->path,
5176                         SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
5177                         interface_add_network_params,
5178                         interface_add_network_result, connect_data,
5179                         connect_data->interface);
5180         } else {
5181                 if (data->callback)
5182                         data->callback(result, data->interface, data->user_data);
5183         }
5184         g_free(data->path);
5185         dbus_free(data);
5186 }
5187
5188 static void network_remove_params(DBusMessageIter *iter, void *user_data)
5189 {
5190         struct interface_data *data = user_data;
5191         const char *path = data->interface->network_path;
5192
5193         SUPPLICANT_DBG("path %s", path);
5194
5195         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
5196 }
5197
5198 static int network_remove(struct interface_data *data)
5199 {
5200         GSupplicantInterface *interface = data->interface;
5201
5202         SUPPLICANT_DBG("");
5203
5204         return supplicant_dbus_method_call(interface->path,
5205                         SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
5206                         network_remove_params, network_remove_result, data,
5207                         interface);
5208 }
5209
5210 static void interface_disconnect_result(const char *error,
5211                                 DBusMessageIter *iter, void *user_data)
5212 {
5213         struct interface_data *data = user_data;
5214         int result = 0;
5215
5216         SUPPLICANT_DBG("");
5217
5218         if (error) {
5219                 result = -EIO;
5220                 SUPPLICANT_DBG("error: %s", error);
5221
5222                 if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
5223                                                 error) == 0)
5224                         result = -ECONNABORTED;
5225         }
5226
5227         /* If we are disconnecting from previous WPS successful
5228          * association. i.e.: it did not went through AddNetwork,
5229          * and interface->network_path was never set. */
5230         if (!data->interface->network_path) {
5231                 if (data->callback)
5232                         data->callback(result, data->interface,
5233                                                         data->user_data);
5234
5235                 g_free(data->path);
5236                 dbus_free(data);
5237                 return;
5238         }
5239
5240         if (result < 0 && data->callback) {
5241                 data->callback(result, data->interface, data->user_data);
5242                 data->callback = NULL;
5243         }
5244
5245         if (result != -ECONNABORTED) {
5246                 if (network_remove(data) < 0) {
5247                         g_free(data->path);
5248                         dbus_free(data);
5249                 }
5250         } else {
5251                 g_free(data->path);
5252                 dbus_free(data);
5253         }
5254 }
5255
5256 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
5257                                         GSupplicantInterfaceCallback callback,
5258                                                         void *user_data)
5259 {
5260         struct interface_data *data;
5261         int ret;
5262
5263         SUPPLICANT_DBG("");
5264
5265         if (!interface)
5266                 return -EINVAL;
5267
5268         if (!system_available)
5269                 return -EFAULT;
5270
5271         data = dbus_malloc0(sizeof(*data));
5272         if (!data)
5273                 return -ENOMEM;
5274
5275         data->interface = interface;
5276         data->path = g_strdup(interface->path);
5277         data->callback = callback;
5278         data->user_data = user_data;
5279
5280         ret = supplicant_dbus_method_call(interface->path,
5281                         SUPPLICANT_INTERFACE ".Interface", "Disconnect",
5282                         NULL, interface_disconnect_result, data,
5283                         interface);
5284
5285         if (ret < 0) {
5286                 g_free(data->path);
5287                 dbus_free(data);
5288         }
5289
5290         return ret;
5291 }
5292
5293 static void interface_p2p_find_result(const char *error,
5294                                         DBusMessageIter *iter, void *user_data)
5295 {
5296         struct interface_scan_data *data = user_data;
5297         int err = 0;
5298
5299         SUPPLICANT_DBG("error %s", error);
5300
5301         if (error)
5302                 err = -EIO;
5303
5304         if (interface_exists(data->interface, data->path)) {
5305                 if (!data->interface->ready)
5306                         err = -ENOLINK;
5307                 if (!err)
5308                         data->interface->p2p_finding = true;
5309         }
5310
5311         if (data->callback)
5312                 data->callback(err, data->interface, data->user_data);
5313
5314         g_free(data->path);
5315         dbus_free(data);
5316 }
5317
5318 static void interface_p2p_find_params(DBusMessageIter *iter, void *user_data)
5319 {
5320         DBusMessageIter dict;
5321
5322         supplicant_dbus_dict_open(iter, &dict);
5323         supplicant_dbus_dict_close(iter, &dict);
5324 }
5325
5326 int g_supplicant_interface_p2p_find(GSupplicantInterface *interface,
5327                                         GSupplicantInterfaceCallback callback,
5328                                                         void *user_data)
5329 {
5330         struct interface_scan_data *data;
5331         int ret;
5332
5333         if (!interface->p2p_support)
5334                 return -ENOTSUP;
5335
5336         ret = interface_ready_to_scan(interface);
5337         if (ret && ret != -EALREADY)
5338                 return ret;
5339
5340         data = dbus_malloc0(sizeof(*data));
5341         if (!data)
5342                 return -ENOMEM;
5343
5344         data->interface = interface;
5345         data->path = g_strdup(interface->path);
5346         data->callback = callback;
5347         data->user_data = user_data;
5348
5349         ret = supplicant_dbus_method_call(interface->path,
5350                         SUPPLICANT_INTERFACE ".Interface.P2PDevice", "Find",
5351                         interface_p2p_find_params, interface_p2p_find_result,
5352                         data, interface);
5353         if (ret < 0) {
5354                 g_free(data->path);
5355                 dbus_free(data);
5356         }
5357
5358         return ret;
5359 }
5360
5361 bool g_supplicant_interface_is_p2p_finding(GSupplicantInterface *interface)
5362 {
5363         if (!interface)
5364                 return false;
5365
5366         return interface->p2p_finding;
5367 }
5368
5369 int g_supplicant_interface_p2p_stop_find(GSupplicantInterface *interface)
5370 {
5371         if (!interface->p2p_finding)
5372                 return 0;
5373
5374         SUPPLICANT_DBG("");
5375
5376         interface->p2p_finding = false;
5377
5378         return supplicant_dbus_method_call(interface->path,
5379                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "StopFind",
5380                 NULL, NULL, NULL, NULL);
5381 }
5382
5383 static void interface_p2p_connect_result(const char *error,
5384                                         DBusMessageIter *iter, void *user_data)
5385 {
5386         struct interface_connect_data *data = user_data;
5387         int err = 0;
5388
5389         SUPPLICANT_DBG("");
5390
5391         if (error) {
5392                 SUPPLICANT_DBG("error: %s", error);
5393                 err = parse_supplicant_error(iter);
5394         }
5395
5396         if (data->callback)
5397                 data->callback(err, data->interface, data->user_data);
5398
5399         g_free(data->path);
5400         g_free(data->peer->wps_pin);
5401         g_free(data->peer->path);
5402         g_free(data->peer);
5403         g_free(data);
5404 }
5405
5406 static void interface_p2p_connect_params(DBusMessageIter *iter, void *user_data)
5407 {
5408         struct interface_connect_data *data = user_data;
5409         const char *wps = "pbc";
5410         DBusMessageIter dict;
5411         int go_intent = 7;
5412
5413         SUPPLICANT_DBG("");
5414
5415         supplicant_dbus_dict_open(iter, &dict);
5416
5417         if (data->peer->master)
5418                 go_intent = 15;
5419
5420         if (data->peer->wps_pin)
5421                 wps = "pin";
5422
5423         supplicant_dbus_dict_append_basic(&dict, "peer",
5424                                 DBUS_TYPE_OBJECT_PATH, &data->peer->path);
5425         supplicant_dbus_dict_append_basic(&dict, "wps_method",
5426                                 DBUS_TYPE_STRING, &wps);
5427         if (data->peer->wps_pin) {
5428                 supplicant_dbus_dict_append_basic(&dict, "pin",
5429                                 DBUS_TYPE_STRING, &data->peer->wps_pin);
5430         }
5431
5432         supplicant_dbus_dict_append_basic(&dict, "go_intent",
5433                                         DBUS_TYPE_INT32, &go_intent);
5434
5435         supplicant_dbus_dict_close(iter, &dict);
5436 }
5437
5438 int g_supplicant_interface_p2p_connect(GSupplicantInterface *interface,
5439                                         GSupplicantPeerParams *peer_params,
5440                                         GSupplicantInterfaceCallback callback,
5441                                         void *user_data)
5442 {
5443         struct interface_connect_data *data;
5444         int ret;
5445
5446         SUPPLICANT_DBG("");
5447
5448         if (!interface->p2p_support)
5449                 return -ENOTSUP;
5450
5451         data = dbus_malloc0(sizeof(*data));
5452         if (!data)
5453                 return -ENOMEM;
5454
5455         data->interface = interface;
5456         data->path = g_strdup(interface->path);
5457         data->peer = peer_params;
5458         data->callback = callback;
5459         data->user_data = user_data;
5460
5461         ret = supplicant_dbus_method_call(interface->path,
5462                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "Connect",
5463                 interface_p2p_connect_params, interface_p2p_connect_result,
5464                 data, interface);
5465         if (ret < 0) {
5466                 g_free(data->path);
5467                 dbus_free(data);
5468                 return ret;
5469         }
5470
5471         return -EINPROGRESS;
5472 }
5473
5474 int g_supplicant_interface_p2p_disconnect(GSupplicantInterface *interface,
5475                                         GSupplicantPeerParams *peer_params)
5476 {
5477         GSupplicantPeer *peer;
5478         int count = 0;
5479         GSList *list;
5480
5481         SUPPLICANT_DBG("");
5482
5483         if (!interface->p2p_support)
5484                 return -ENOTSUP;
5485
5486         peer = g_hash_table_lookup(interface->peer_table, peer_params->path);
5487         if (!peer)
5488                 return -ENODEV;
5489
5490         for (list = peer->groups; list; list = list->next, count++) {
5491                 const char *group_obj_path = list->data;
5492                 GSupplicantInterface *g_interface;
5493                 GSupplicantGroup *group;
5494
5495                 group = g_hash_table_lookup(group_mapping, group_obj_path);
5496                 if (!group || !group->interface)
5497                         continue;
5498
5499                 g_interface = group->interface;
5500                 supplicant_dbus_method_call(g_interface->path,
5501                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
5502                                 "Disconnect", NULL, NULL, NULL, g_interface);
5503         }
5504
5505         if (count == 0 && peer->current_group_iface) {
5506                 supplicant_dbus_method_call(peer->current_group_iface->path,
5507                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
5508                                 "Disconnect", NULL, NULL, NULL,
5509                                 peer->current_group_iface->path);
5510         }
5511
5512         peer->current_group_iface = NULL;
5513
5514         return -EINPROGRESS;
5515 }
5516
5517 struct p2p_service_data {
5518         bool registration;
5519         GSupplicantInterface *interface;
5520         GSupplicantP2PServiceParams *service;
5521         GSupplicantInterfaceCallback callback;
5522         void *user_data;
5523 };
5524
5525 static void interface_p2p_service_result(const char *error,
5526                                         DBusMessageIter *iter, void *user_data)
5527 {
5528         struct p2p_service_data *data = user_data;
5529         int result = 0;
5530
5531         SUPPLICANT_DBG("%s result - %s", data->registration ?
5532                                 "Registration" : "Deletion",
5533                                 error ? error : "Success");
5534         if (error)
5535                 result = -EINVAL;
5536
5537         if (data->callback)
5538                 data->callback(result, data->interface, data->user_data);
5539
5540         g_free(data->service->query);
5541         g_free(data->service->response);
5542         g_free(data->service->service);
5543         g_free(data->service->wfd_ies);
5544         g_free(data->service);
5545         dbus_free(data);
5546 }
5547
5548 static void interface_p2p_service_params(DBusMessageIter *iter,
5549                                                         void *user_data)
5550 {
5551         struct p2p_service_data *data = user_data;
5552         GSupplicantP2PServiceParams *service;
5553         DBusMessageIter dict;
5554         const char *type;
5555
5556         SUPPLICANT_DBG("");
5557
5558         service = data->service;
5559
5560         supplicant_dbus_dict_open(iter, &dict);
5561
5562         if (service->query && service->response) {
5563                 type = "bonjour";
5564                 supplicant_dbus_dict_append_basic(&dict, "service_type",
5565                                                 DBUS_TYPE_STRING, &type);
5566                 supplicant_dbus_dict_append_fixed_array(&dict, "query",
5567                                         DBUS_TYPE_BYTE, &service->query,
5568                                         service->query_length);
5569                 supplicant_dbus_dict_append_fixed_array(&dict, "response",
5570                                         DBUS_TYPE_BYTE, &service->response,
5571                                         service->response_length);
5572         } else if (service->version && service->service) {
5573                 type = "upnp";
5574                 supplicant_dbus_dict_append_basic(&dict, "service_type",
5575                                                 DBUS_TYPE_STRING, &type);
5576                 supplicant_dbus_dict_append_basic(&dict, "version",
5577                                         DBUS_TYPE_INT32, &service->version);
5578                 supplicant_dbus_dict_append_basic(&dict, "service",
5579                                         DBUS_TYPE_STRING, &service->service);
5580         }
5581
5582         supplicant_dbus_dict_close(iter, &dict);
5583 }
5584
5585 int g_supplicant_interface_p2p_add_service(GSupplicantInterface *interface,
5586                                 GSupplicantInterfaceCallback callback,
5587                                 GSupplicantP2PServiceParams *p2p_service_params,
5588                                 void *user_data)
5589 {
5590         struct p2p_service_data *data;
5591         int ret;
5592
5593         SUPPLICANT_DBG("");
5594
5595         if (!interface->p2p_support)
5596                 return -ENOTSUP;
5597
5598         data = dbus_malloc0(sizeof(*data));
5599         if (!data)
5600                 return -ENOMEM;
5601
5602         data->registration = true;
5603         data->interface = interface;
5604         data->service = p2p_service_params;
5605         data->callback = callback;
5606         data->user_data = user_data;
5607
5608         ret = supplicant_dbus_method_call(interface->path,
5609                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "AddService",
5610                 interface_p2p_service_params, interface_p2p_service_result,
5611                 data, interface);
5612         if (ret < 0) {
5613                 dbus_free(data);
5614                 return ret;
5615         }
5616
5617         return -EINPROGRESS;
5618 }
5619
5620 int g_supplicant_interface_p2p_del_service(GSupplicantInterface *interface,
5621                                 GSupplicantP2PServiceParams *p2p_service_params)
5622 {
5623         struct p2p_service_data *data;
5624         int ret;
5625
5626         SUPPLICANT_DBG("");
5627
5628         if (!interface->p2p_support)
5629                 return -ENOTSUP;
5630
5631         data = dbus_malloc0(sizeof(*data));
5632         if (!data)
5633                 return -ENOMEM;
5634
5635         data->interface = interface;
5636         data->service = p2p_service_params;
5637
5638         ret = supplicant_dbus_method_call(interface->path,
5639                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeleteService",
5640                 interface_p2p_service_params, interface_p2p_service_result,
5641                 data, interface);
5642         if (ret < 0) {
5643                 dbus_free(data);
5644                 return ret;
5645         }
5646
5647         return -EINPROGRESS;
5648 }
5649
5650 struct p2p_listen_data {
5651         int period;
5652         int interval;
5653 };
5654
5655 static void interface_p2p_listen_params(DBusMessageIter *iter, void *user_data)
5656 {
5657         struct p2p_listen_data *params = user_data;
5658         DBusMessageIter dict;
5659
5660         supplicant_dbus_dict_open(iter, &dict);
5661
5662         supplicant_dbus_dict_append_basic(&dict, "period",
5663                                         DBUS_TYPE_INT32, &params->period);
5664         supplicant_dbus_dict_append_basic(&dict, "interval",
5665                                         DBUS_TYPE_INT32, &params->interval);
5666         supplicant_dbus_dict_close(iter, &dict);
5667 }
5668
5669 int g_supplicant_interface_p2p_listen(GSupplicantInterface *interface,
5670                                                 int period, int interval)
5671 {
5672         struct p2p_listen_data params;
5673
5674         SUPPLICANT_DBG("");
5675
5676         if (!interface->p2p_support)
5677                 return -ENOTSUP;
5678
5679         params.period = period;
5680         params.interval = interval;
5681
5682         return supplicant_dbus_method_call(interface->path,
5683                         SUPPLICANT_INTERFACE ".Interface.P2PDevice",
5684                         "ExtendedListen", interface_p2p_listen_params,
5685                         NULL, &params, NULL);
5686 }
5687
5688 static void widi_ies_params(DBusMessageIter *iter, void *user_data)
5689 {
5690         struct p2p_service_data *data = user_data;
5691         GSupplicantP2PServiceParams *service = data->service;
5692         DBusMessageIter array;
5693
5694         SUPPLICANT_DBG("%p - %d", service->wfd_ies, service->wfd_ies_length);
5695
5696         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
5697                                         DBUS_TYPE_BYTE_AS_STRING, &array);
5698
5699         if (service->wfd_ies && service->wfd_ies_length > 0) {
5700                 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
5701                                 &service->wfd_ies, service->wfd_ies_length);
5702         }
5703
5704         dbus_message_iter_close_container(iter, &array);
5705 }
5706
5707 int g_supplicant_set_widi_ies(GSupplicantP2PServiceParams *p2p_service_params,
5708                                         GSupplicantInterfaceCallback callback,
5709                                         void *user_data)
5710 {
5711         struct p2p_service_data *data;
5712         int ret;
5713
5714         SUPPLICANT_DBG("");
5715
5716         if (!system_available)
5717                 return -EFAULT;
5718
5719         data = dbus_malloc0(sizeof(*data));
5720         if (!data)
5721                 return -ENOMEM;
5722
5723         data->service = p2p_service_params;
5724         data->callback = callback;
5725         data->user_data = user_data;
5726
5727         if (p2p_service_params->wfd_ies)
5728                 data->registration = true;
5729
5730         ret = supplicant_dbus_property_set(SUPPLICANT_PATH,
5731                                         SUPPLICANT_INTERFACE, "WFDIEs",
5732                                         DBUS_TYPE_ARRAY_AS_STRING
5733                                         DBUS_TYPE_BYTE_AS_STRING,
5734                                         widi_ies_params,
5735                                         interface_p2p_service_result,
5736                                         data, NULL);
5737         if (ret < 0 && ret != -EINPROGRESS) {
5738                 dbus_free(data);
5739                 return ret;
5740         }
5741
5742         return -EINPROGRESS;
5743 }
5744
5745
5746 static const char *g_supplicant_rule0 = "type=signal,"
5747                                         "path=" DBUS_PATH_DBUS ","
5748                                         "sender=" DBUS_SERVICE_DBUS ","
5749                                         "interface=" DBUS_INTERFACE_DBUS ","
5750                                         "member=NameOwnerChanged,"
5751                                         "arg0=" SUPPLICANT_SERVICE;
5752 static const char *g_supplicant_rule1 = "type=signal,"
5753                         "interface=" SUPPLICANT_INTERFACE;
5754 static const char *g_supplicant_rule2 = "type=signal,"
5755                         "interface=" SUPPLICANT_INTERFACE ".Interface";
5756 static const char *g_supplicant_rule3 = "type=signal,"
5757                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
5758 static const char *g_supplicant_rule4 = "type=signal,"
5759                         "interface=" SUPPLICANT_INTERFACE ".BSS";
5760 static const char *g_supplicant_rule5 = "type=signal,"
5761                         "interface=" SUPPLICANT_INTERFACE ".Network";
5762 static const char *g_supplicant_rule6 = "type=signal,"
5763                 "interface=" SUPPLICANT_INTERFACE ".Interface.P2PDevice";
5764 static const char *g_supplicant_rule7 = "type=signal,"
5765                 "interface=" SUPPLICANT_INTERFACE ".Peer";
5766 static const char *g_supplicant_rule8 = "type=signal,"
5767                 "interface=" SUPPLICANT_INTERFACE ".Group";
5768
5769 static void invoke_introspect_method(void)
5770 {
5771         DBusMessage *message;
5772
5773         message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
5774                                         SUPPLICANT_PATH,
5775                                         DBUS_INTERFACE_INTROSPECTABLE,
5776                                         "Introspect");
5777
5778         if (!message)
5779                 return;
5780
5781         dbus_message_set_no_reply(message, TRUE);
5782         dbus_connection_send(connection, message, NULL);
5783         dbus_message_unref(message);
5784 }
5785
5786 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
5787 {
5788         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
5789         if (!connection)
5790                 return -EIO;
5791
5792         if (!dbus_connection_add_filter(connection, g_supplicant_filter,
5793                                                 NULL, NULL)) {
5794                 dbus_connection_unref(connection);
5795                 connection = NULL;
5796                 return -EIO;
5797         }
5798
5799         callbacks_pointer = callbacks;
5800         eap_methods = 0;
5801
5802         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
5803                                                 NULL, remove_interface);
5804
5805         bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
5806                                                                 NULL, NULL);
5807         peer_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
5808                                                                 NULL, NULL);
5809         group_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
5810                                                                 NULL, NULL);
5811         pending_peer_connection = g_hash_table_new_full(g_str_hash, g_str_equal,
5812                                                                 NULL, NULL);
5813         config_file_table = g_hash_table_new_full(g_str_hash, g_str_equal,
5814                                                                 g_free, g_free);
5815
5816         supplicant_dbus_setup(connection);
5817
5818         dbus_bus_add_match(connection, g_supplicant_rule0, NULL);
5819         dbus_bus_add_match(connection, g_supplicant_rule1, NULL);
5820         dbus_bus_add_match(connection, g_supplicant_rule2, NULL);
5821         dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
5822         dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
5823         dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
5824         dbus_bus_add_match(connection, g_supplicant_rule6, NULL);
5825         dbus_bus_add_match(connection, g_supplicant_rule7, NULL);
5826         dbus_bus_add_match(connection, g_supplicant_rule8, NULL);
5827         dbus_connection_flush(connection);
5828
5829         if (dbus_bus_name_has_owner(connection,
5830                                         SUPPLICANT_SERVICE, NULL)) {
5831                 system_available = TRUE;
5832                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
5833                                                 SUPPLICANT_INTERFACE,
5834                                                 service_property, NULL, NULL);
5835         } else
5836                 invoke_introspect_method();
5837
5838         return 0;
5839 }
5840
5841 static void unregister_interface_remove_params(DBusMessageIter *iter,
5842                                                 void *user_data)
5843 {
5844         const char *path = user_data;
5845
5846         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
5847                                                         &path);
5848 }
5849
5850
5851 static void unregister_remove_interface(gpointer key, gpointer value,
5852                                                 gpointer user_data)
5853 {
5854         GSupplicantInterface *interface = value;
5855
5856         supplicant_dbus_method_call(SUPPLICANT_PATH,
5857                                         SUPPLICANT_INTERFACE,
5858                                         "RemoveInterface",
5859                                         unregister_interface_remove_params,
5860                                         NULL, interface->path, NULL);
5861 }
5862
5863 void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
5864 {
5865         SUPPLICANT_DBG("");
5866
5867         if (connection) {
5868                 dbus_bus_remove_match(connection, g_supplicant_rule8, NULL);
5869                 dbus_bus_remove_match(connection, g_supplicant_rule7, NULL);
5870                 dbus_bus_remove_match(connection, g_supplicant_rule6, NULL);
5871                 dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
5872                 dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
5873                 dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);
5874                 dbus_bus_remove_match(connection, g_supplicant_rule2, NULL);
5875                 dbus_bus_remove_match(connection, g_supplicant_rule1, NULL);
5876                 dbus_bus_remove_match(connection, g_supplicant_rule0, NULL);
5877                 dbus_connection_flush(connection);
5878
5879                 dbus_connection_remove_filter(connection,
5880                                                 g_supplicant_filter, NULL);
5881         }
5882
5883         if (config_file_table) {
5884                 g_hash_table_destroy(config_file_table);
5885                 config_file_table = NULL;
5886         }
5887
5888         if (bss_mapping) {
5889                 g_hash_table_destroy(bss_mapping);
5890                 bss_mapping = NULL;
5891         }
5892
5893         if (peer_mapping) {
5894                 g_hash_table_destroy(peer_mapping);
5895                 peer_mapping = NULL;
5896         }
5897
5898         if (group_mapping) {
5899                 g_hash_table_destroy(group_mapping);
5900                 group_mapping = NULL;
5901         }
5902
5903         if (interface_table) {
5904                 g_hash_table_foreach(interface_table,
5905                                         unregister_remove_interface, NULL);
5906                 g_hash_table_destroy(interface_table);
5907                 interface_table = NULL;
5908         }
5909
5910         if (system_available)
5911                 callback_system_killed();
5912
5913         if (connection) {
5914                 dbus_connection_unref(connection);
5915                 connection = NULL;
5916         }
5917
5918         callbacks_pointer = NULL;
5919         eap_methods = 0;
5920 }