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