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