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