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