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