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