a017e732b2c876a282439f1b308097fe3583e668
[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 #if defined TIZEN_EXT
48 #define WLAN_EID_HT_CAP 45
49 #define WLAN_EID_VHT_CAP 191
50 #define WLAN_EID_SUPP_RATES 1
51 #define WLAN_EID_EXT_SUPP_RATES 50
52 #define COUNTRY_CODE_LENGTH     2
53 #define WIFI_BSSID_LEN_MAX 6
54 #endif
55
56 #define BSS_UNKNOWN_STRENGTH    -90
57
58 static DBusConnection *connection;
59
60 static const GSupplicantCallbacks *callbacks_pointer;
61
62 static dbus_bool_t system_available = FALSE;
63 static dbus_bool_t system_ready = FALSE;
64
65 static dbus_int32_t debug_level;
66 static dbus_bool_t debug_timestamp = FALSE;
67 static dbus_bool_t debug_showkeys = FALSE;
68
69 static const char *debug_strings[] = {
70         "msgdump", "debug", "info", "warning", "error", NULL
71 };
72
73 static unsigned int eap_methods;
74
75 struct strvalmap {
76         const char *str;
77         unsigned int val;
78 };
79
80 static struct strvalmap eap_method_map[] = {
81         { "MD5",        G_SUPPLICANT_EAP_METHOD_MD5     },
82         { "TLS",        G_SUPPLICANT_EAP_METHOD_TLS     },
83         { "MSCHAPV2",   G_SUPPLICANT_EAP_METHOD_MSCHAPV2        },
84         { "PEAP",       G_SUPPLICANT_EAP_METHOD_PEAP    },
85         { "TTLS",       G_SUPPLICANT_EAP_METHOD_TTLS    },
86         { "GTC",        G_SUPPLICANT_EAP_METHOD_GTC     },
87         { "OTP",        G_SUPPLICANT_EAP_METHOD_OTP     },
88         { "LEAP",       G_SUPPLICANT_EAP_METHOD_LEAP    },
89         { "WSC",        G_SUPPLICANT_EAP_METHOD_WSC     },
90         { }
91 };
92
93 static struct strvalmap keymgmt_map[] = {
94         { "none",               G_SUPPLICANT_KEYMGMT_NONE               },
95         { "ieee8021x",          G_SUPPLICANT_KEYMGMT_IEEE8021X  },
96         { "wpa-none",           G_SUPPLICANT_KEYMGMT_WPA_NONE   },
97         { "wpa-psk",            G_SUPPLICANT_KEYMGMT_WPA_PSK    },
98         { "wpa-psk-sha256",     G_SUPPLICANT_KEYMGMT_WPA_PSK_256        },
99         { "wpa-ft-psk",         G_SUPPLICANT_KEYMGMT_WPA_FT_PSK },
100         { "wpa-ft-eap",         G_SUPPLICANT_KEYMGMT_WPA_FT_EAP },
101         { "wpa-eap",            G_SUPPLICANT_KEYMGMT_WPA_EAP    },
102         { "wpa-eap-sha256",     G_SUPPLICANT_KEYMGMT_WPA_EAP_256        },
103         { "wps",                G_SUPPLICANT_KEYMGMT_WPS                },
104 #if defined TIZEN_EXT_WIFI_MESH
105         { "sae",                G_SUPPLICANT_KEYMGMT_SAE                },
106 #endif
107         { }
108 };
109
110 static struct strvalmap authalg_capa_map[] = {
111         { "open",       G_SUPPLICANT_CAPABILITY_AUTHALG_OPEN    },
112         { "shared",     G_SUPPLICANT_CAPABILITY_AUTHALG_SHARED  },
113         { "leap",       G_SUPPLICANT_CAPABILITY_AUTHALG_LEAP    },
114         { }
115 };
116
117 static struct strvalmap proto_capa_map[] = {
118         { "wpa",        G_SUPPLICANT_CAPABILITY_PROTO_WPA               },
119         { "rsn",        G_SUPPLICANT_CAPABILITY_PROTO_RSN               },
120         { }
121 };
122
123 static struct strvalmap group_map[] = {
124         { "wep40",      G_SUPPLICANT_GROUP_WEP40        },
125         { "wep104",     G_SUPPLICANT_GROUP_WEP104       },
126         { "tkip",       G_SUPPLICANT_GROUP_TKIP },
127         { "ccmp",       G_SUPPLICANT_GROUP_CCMP },
128         { }
129 };
130
131 static struct strvalmap pairwise_map[] = {
132         { "none",       G_SUPPLICANT_PAIRWISE_NONE      },
133         { "tkip",       G_SUPPLICANT_PAIRWISE_TKIP      },
134         { "ccmp",       G_SUPPLICANT_PAIRWISE_CCMP      },
135         { }
136 };
137
138 static struct strvalmap scan_capa_map[] = {
139         { "active",     G_SUPPLICANT_CAPABILITY_SCAN_ACTIVE     },
140         { "passive",    G_SUPPLICANT_CAPABILITY_SCAN_PASSIVE    },
141         { "ssid",       G_SUPPLICANT_CAPABILITY_SCAN_SSID               },
142         { }
143 };
144
145 static struct strvalmap mode_capa_map[] = {
146         { "infrastructure",     G_SUPPLICANT_CAPABILITY_MODE_INFRA      },
147         { "ad-hoc",             G_SUPPLICANT_CAPABILITY_MODE_IBSS       },
148         { "ap",                 G_SUPPLICANT_CAPABILITY_MODE_AP         },
149         { "p2p",                G_SUPPLICANT_CAPABILITY_MODE_P2P        },
150 #if defined TIZEN_EXT_WIFI_MESH
151         { "mesh",               G_SUPPLICANT_CAPABILITY_MODE_MESH       },
152 #endif
153         { }
154 };
155
156 static GHashTable *interface_table;
157 static GHashTable *bss_mapping;
158 static GHashTable *peer_mapping;
159 static GHashTable *group_mapping;
160 static GHashTable *pending_peer_connection;
161 static GHashTable *config_file_table;
162
163 struct _GSupplicantWpsCredentials {
164         unsigned char ssid[32];
165         unsigned int ssid_len;
166         char *key;
167 };
168
169 struct added_network_information {
170         char * ssid;
171         GSupplicantSecurity security;
172         char * passphrase;
173         char * private_passphrase;
174 };
175
176 #if defined TIZEN_EXT_WIFI_MESH
177 struct _GSupplicantMeshGroupInfo {
178         unsigned char ssid[32];
179         unsigned int ssid_len;
180         int disconnect_reason;
181 };
182 #endif
183
184 struct _GSupplicantInterface {
185         char *path;
186         char *network_path;
187         unsigned int keymgmt_capa;
188         unsigned int authalg_capa;
189         unsigned int proto_capa;
190         unsigned int group_capa;
191         unsigned int pairwise_capa;
192         unsigned int scan_capa;
193         unsigned int mode_capa;
194         unsigned int max_scan_ssids;
195         bool p2p_support;
196         bool p2p_finding;
197         bool ap_create_in_progress;
198         dbus_bool_t ready;
199         GSupplicantState state;
200         dbus_bool_t scanning;
201         GSupplicantInterfaceCallback scan_callback;
202         void *scan_data;
203         int apscan;
204         char *ifname;
205         char *driver;
206         char *bridge;
207         struct _GSupplicantWpsCredentials wps_cred;
208         GSupplicantWpsState wps_state;
209         GHashTable *network_table;
210         GHashTable *peer_table;
211         GHashTable *group_table;
212         GHashTable *bss_mapping;
213         void *data;
214         const char *pending_peer_path;
215         GSupplicantNetwork *current_network;
216         struct added_network_information network_info;
217 #if defined TIZEN_EXT
218         dbus_bool_t is_5_0_Ghz_supported;
219         int disconnect_reason;
220 #endif
221 #if defined TIZEN_EXT_WIFI_MESH
222         bool mesh_support;
223         struct _GSupplicantMeshGroupInfo group_info;
224 #endif
225 };
226
227 struct g_supplicant_bss {
228         GSupplicantInterface *interface;
229         char *path;
230         unsigned char bssid[6];
231         unsigned char ssid[32];
232         unsigned int ssid_len;
233         dbus_uint16_t frequency;
234         dbus_uint32_t maxrate;
235         dbus_int16_t signal;
236         GSupplicantMode mode;
237         GSupplicantSecurity security;
238         dbus_bool_t rsn_selected;
239         unsigned int wpa_keymgmt;
240         unsigned int wpa_pairwise;
241         unsigned int wpa_group;
242         unsigned int rsn_keymgmt;
243         unsigned int rsn_pairwise;
244         unsigned int rsn_group;
245         unsigned int keymgmt;
246         dbus_bool_t privacy;
247         dbus_bool_t psk;
248         dbus_bool_t ieee8021x;
249 #if defined TIZEN_EXT
250         dbus_bool_t ft_psk;
251         dbus_bool_t ft_ieee8021x;
252         GSList *vsie_list;
253         dbus_bool_t hs20;
254         unsigned char country_code[COUNTRY_CODE_LENGTH];
255         GSupplicantPhy_mode phy_mode;
256 #endif
257         unsigned int wps_capabilities;
258 #if defined TIZEN_EXT_WIFI_MESH
259         dbus_bool_t sae;
260 #endif
261 };
262
263 struct _GSupplicantNetwork {
264         GSupplicantInterface *interface;
265         char *path;
266         char *group;
267         char *name;
268         unsigned char ssid[32];
269         unsigned int ssid_len;
270         dbus_int16_t signal;
271         dbus_uint16_t frequency;
272         struct g_supplicant_bss *best_bss;
273         GSupplicantMode mode;
274         GSupplicantSecurity security;
275         dbus_bool_t wps;
276         unsigned int wps_capabilities;
277         GHashTable *bss_table;
278         GHashTable *config_table;
279 #if defined TIZEN_EXT
280         bool isHS20AP;
281         char *eap;
282         char *identity;
283         char *phase2;
284         unsigned int keymgmt;
285         GSList *vsie_list;
286         unsigned char country_code[COUNTRY_CODE_LENGTH];
287         GSupplicantPhy_mode phy_mode;
288 #endif
289 };
290
291 struct _GSupplicantPeer {
292         GSupplicantInterface *interface;
293         char *path;
294         unsigned char device_address[ETH_ALEN];
295         unsigned char iface_address[ETH_ALEN];
296         char *name;
297         unsigned char *widi_ies;
298         int widi_ies_length;
299         char *identifier;
300         unsigned int wps_capabilities;
301         GSList *groups;
302         const GSupplicantInterface *current_group_iface;
303         bool connection_requested;
304 };
305
306 struct _GSupplicantGroup {
307         GSupplicantInterface *interface;
308         GSupplicantInterface *orig_interface;
309         char *path;
310         int role;
311         GSList *members;
312 };
313
314 struct interface_data {
315         GSupplicantInterface *interface;
316         char *path; /* Interface path cannot be taken from interface (above) as
317                      * it might have been freed already.
318                      */
319         GSupplicantInterfaceCallback callback;
320         void *user_data;
321         bool network_remove_in_progress;
322         GSupplicantSSID *ssid;
323 };
324
325 #if defined TIZEN_EXT
326 struct interface_signalpoll_data {
327         GSupplicantInterface *interface;
328         char *path;
329         GSupplicantMaxSpeedCallback callback;
330         void *user_data;
331 };
332 #endif
333
334 struct interface_create_data {
335         char *ifname;
336         char *driver;
337         char *bridge;
338 #if defined TIZEN_EXT_WIFI_MESH
339         char *parent_ifname;
340         bool is_mesh_interface;
341 #endif
342         GSupplicantInterface *interface;
343         GSupplicantInterfaceCallback callback;
344         void *user_data;
345 };
346
347 struct interface_connect_data {
348         GSupplicantInterface *interface;
349         char *path;
350         GSupplicantInterfaceCallback callback;
351         void *user_data;
352         union {
353                 GSupplicantSSID *ssid;
354                 GSupplicantPeerParams *peer;
355         };
356 };
357
358 struct interface_scan_data {
359         GSupplicantInterface *interface;
360         char *path;
361         GSupplicantInterfaceCallback callback;
362         GSupplicantScanParams *scan_params;
363         void *user_data;
364 };
365
366 #if defined TIZEN_EXT
367 struct g_connman_bssids {
368         unsigned char bssid[WIFI_BSSID_LEN_MAX];
369         uint16_t strength;
370         uint16_t frequency;
371 };
372 #endif
373
374 static int network_remove(struct interface_data *data);
375
376 #if defined TIZEN_EXT_WIFI_MESH
377 struct _GSupplicantMeshPeer {
378         GSupplicantInterface *interface;
379         char *peer_address;
380         int disconnect_reason;
381 };
382 #endif
383
384 static inline void debug(const char *format, ...)
385 {
386         char str[256];
387         va_list ap;
388
389         if (!callbacks_pointer || !callbacks_pointer->debug)
390                 return;
391
392         va_start(ap, format);
393
394         if (vsnprintf(str, sizeof(str), format, ap) > 0)
395                 callbacks_pointer->debug(str);
396
397         va_end(ap);
398 }
399
400 #define SUPPLICANT_DBG(fmt, arg...) \
401         debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg);
402
403 static GSupplicantMode string2mode(const char *mode)
404 {
405         if (!mode)
406                 return G_SUPPLICANT_MODE_UNKNOWN;
407
408         if (g_str_equal(mode, "infrastructure"))
409                 return G_SUPPLICANT_MODE_INFRA;
410         else if (g_str_equal(mode, "ad-hoc"))
411                 return G_SUPPLICANT_MODE_IBSS;
412 #if defined TIZEN_EXT_WIFI_MESH
413         else if (g_str_equal(mode, "mesh"))
414                 return G_SUPPLICANT_MODE_MESH;
415 #endif
416
417         return G_SUPPLICANT_MODE_UNKNOWN;
418 }
419
420 static const char *mode2string(GSupplicantMode mode)
421 {
422         switch (mode) {
423         case G_SUPPLICANT_MODE_UNKNOWN:
424                 break;
425         case G_SUPPLICANT_MODE_INFRA:
426                 return "managed";
427         case G_SUPPLICANT_MODE_IBSS:
428                 return "adhoc";
429         case G_SUPPLICANT_MODE_MASTER:
430                 return "ap";
431 #if defined TIZEN_EXT_WIFI_MESH
432         case G_SUPPLICANT_MODE_MESH:
433                 return "mesh";
434 #endif
435         }
436
437         return NULL;
438 }
439
440 static const char *security2string(GSupplicantSecurity security)
441 {
442         switch (security) {
443         case G_SUPPLICANT_SECURITY_UNKNOWN:
444                 break;
445         case G_SUPPLICANT_SECURITY_NONE:
446                 return "none";
447         case G_SUPPLICANT_SECURITY_WEP:
448                 return "wep";
449         case G_SUPPLICANT_SECURITY_PSK:
450                 return "psk";
451         case G_SUPPLICANT_SECURITY_IEEE8021X:
452                 return "ieee8021x";
453 #if defined TIZEN_EXT
454         case G_SUPPLICANT_SECURITY_FT_PSK:
455                 return "ft_psk";
456         case G_SUPPLICANT_SECURITY_FT_IEEE8021X:
457                 return "ft_ieee8021x";
458 #endif
459 #if defined TIZEN_EXT_WIFI_MESH
460         case G_SUPPLICANT_SECURITY_SAE:
461                 return "sae";
462 #endif
463         }
464
465         return NULL;
466 }
467
468 static GSupplicantState string2state(const char *state)
469 {
470         if (!state)
471                 return G_SUPPLICANT_STATE_UNKNOWN;
472
473         if (g_str_equal(state, "unknown"))
474                 return G_SUPPLICANT_STATE_UNKNOWN;
475         else if (g_str_equal(state, "interface_disabled"))
476                 return G_SUPPLICANT_STATE_DISABLED;
477         else if (g_str_equal(state, "disconnected"))
478                 return G_SUPPLICANT_STATE_DISCONNECTED;
479         else if (g_str_equal(state, "inactive"))
480                 return G_SUPPLICANT_STATE_INACTIVE;
481         else if (g_str_equal(state, "scanning"))
482                 return G_SUPPLICANT_STATE_SCANNING;
483         else if (g_str_equal(state, "authenticating"))
484                 return G_SUPPLICANT_STATE_AUTHENTICATING;
485         else if (g_str_equal(state, "associating"))
486                 return G_SUPPLICANT_STATE_ASSOCIATING;
487         else if (g_str_equal(state, "associated"))
488                 return G_SUPPLICANT_STATE_ASSOCIATED;
489         else if (g_str_equal(state, "group_handshake"))
490                 return G_SUPPLICANT_STATE_GROUP_HANDSHAKE;
491         else if (g_str_equal(state, "4way_handshake"))
492                 return G_SUPPLICANT_STATE_4WAY_HANDSHAKE;
493         else if (g_str_equal(state, "completed"))
494                 return G_SUPPLICANT_STATE_COMPLETED;
495
496         return G_SUPPLICANT_STATE_UNKNOWN;
497 }
498
499 static bool compare_network_parameters(GSupplicantInterface *interface,
500                                 GSupplicantSSID *ssid)
501 {
502 #if defined TIZEN_EXT
503         if (!interface->network_info.ssid)
504                 return FALSE;
505 #endif
506
507         if (memcmp(interface->network_info.ssid, ssid->ssid, ssid->ssid_len))
508                 return FALSE;
509
510         if (interface->network_info.security != ssid->security)
511                 return FALSE;
512
513         if (interface->network_info.passphrase &&
514                         g_strcmp0(interface->network_info.passphrase,
515                                 ssid->passphrase) != 0) {
516                 return FALSE;
517         }
518
519         if (interface->network_info.private_passphrase &&
520                         g_strcmp0(interface->network_info.private_passphrase,
521                                 ssid->private_key_passphrase) != 0) {
522                 return FALSE;
523         }
524
525         return TRUE;
526 }
527
528 static void remove_network_information(GSupplicantInterface * interface)
529 {
530         g_free(interface->network_info.ssid);
531         g_free(interface->network_info.passphrase);
532         g_free(interface->network_info.private_passphrase);
533         interface->network_info.ssid = NULL;
534         interface->network_info.passphrase = NULL;
535         interface->network_info.private_passphrase = NULL;
536 }
537
538 static int store_network_information(GSupplicantInterface * interface,
539                                 GSupplicantSSID *ssid)
540 {
541         interface->network_info.ssid = g_malloc(ssid->ssid_len + 1);
542         if (interface->network_info.ssid != NULL) {
543                 memcpy(interface->network_info.ssid, ssid->ssid,
544                         ssid->ssid_len);
545                 interface->network_info.ssid[ssid->ssid_len] = '\0';
546         } else {
547                 return -ENOMEM;
548         }
549
550         interface->network_info.security = ssid->security;
551
552         if ((ssid->security == G_SUPPLICANT_SECURITY_WEP ||
553                 ssid->security == G_SUPPLICANT_SECURITY_PSK ||
554                 ssid->security == G_SUPPLICANT_SECURITY_NONE) &&
555                 ssid->passphrase) {
556                 interface->network_info.passphrase = g_strdup(ssid->passphrase);
557         }
558
559         if (ssid->security == G_SUPPLICANT_SECURITY_IEEE8021X &&
560                         ssid->private_key_passphrase) {
561                 interface->network_info.private_passphrase =
562                         g_strdup(ssid->private_key_passphrase);
563         }
564
565         return 0;
566 }
567
568 static void callback_system_ready(void)
569 {
570         if (system_ready)
571                 return;
572
573         system_ready = TRUE;
574
575         if (!callbacks_pointer)
576                 return;
577
578         if (!callbacks_pointer->system_ready)
579                 return;
580
581         callbacks_pointer->system_ready();
582 }
583
584 static void callback_system_killed(void)
585 {
586         system_ready = FALSE;
587
588         if (!callbacks_pointer)
589                 return;
590
591         if (!callbacks_pointer->system_killed)
592                 return;
593
594         callbacks_pointer->system_killed();
595 }
596
597 static void callback_interface_added(GSupplicantInterface *interface)
598 {
599         SUPPLICANT_DBG("");
600
601         if (!callbacks_pointer)
602                 return;
603
604         if (!callbacks_pointer->interface_added)
605                 return;
606
607         callbacks_pointer->interface_added(interface);
608 }
609
610 static void callback_interface_state(GSupplicantInterface *interface)
611 {
612         if (!callbacks_pointer)
613                 return;
614
615         if (!callbacks_pointer->interface_state)
616                 return;
617
618         callbacks_pointer->interface_state(interface);
619 }
620
621 static void callback_interface_removed(GSupplicantInterface *interface)
622 {
623         if (!callbacks_pointer)
624                 return;
625
626         if (!callbacks_pointer->interface_removed)
627                 return;
628
629         callbacks_pointer->interface_removed(interface);
630 }
631
632 #if !defined TIZEN_EXT
633 static void callback_p2p_support(GSupplicantInterface *interface)
634 {
635         SUPPLICANT_DBG("");
636
637         if (!interface->p2p_support)
638                 return;
639
640         if (callbacks_pointer && callbacks_pointer->p2p_support)
641                 callbacks_pointer->p2p_support(interface);
642 }
643 #endif
644
645 #if defined TIZEN_EXT_WIFI_MESH
646 static void callback_mesh_support(GSupplicantInterface *interface)
647 {
648         SUPPLICANT_DBG("");
649
650         if (!interface->mesh_support)
651                 return;
652
653         if (callbacks_pointer && callbacks_pointer->mesh_support)
654                 callbacks_pointer->mesh_support(interface);
655 }
656
657 bool g_supplicant_interface_has_mesh(GSupplicantInterface *interface)
658 {
659         if (!interface)
660                 return false;
661
662         return interface->mesh_support;
663 }
664 #endif
665
666 static void callback_scan_started(GSupplicantInterface *interface)
667 {
668         if (!callbacks_pointer)
669                 return;
670
671         if (!callbacks_pointer->scan_started)
672                 return;
673
674         callbacks_pointer->scan_started(interface);
675 }
676
677 static void callback_ap_create_fail(GSupplicantInterface *interface)
678 {
679         if (!callbacks_pointer)
680                 return;
681
682         if (!callbacks_pointer->ap_create_fail)
683                 return;
684
685         callbacks_pointer->ap_create_fail(interface);
686 }
687
688 static void callback_scan_finished(GSupplicantInterface *interface)
689 {
690         if (!callbacks_pointer)
691                 return;
692
693         if (!callbacks_pointer->scan_finished)
694                 return;
695
696         callbacks_pointer->scan_finished(interface);
697 }
698
699 static void callback_network_added(GSupplicantNetwork *network)
700 {
701         if (!callbacks_pointer)
702                 return;
703
704         if (!callbacks_pointer->network_added)
705                 return;
706
707         callbacks_pointer->network_added(network);
708 }
709
710 static void callback_network_removed(GSupplicantNetwork *network)
711 {
712         if (!callbacks_pointer)
713                 return;
714
715         if (!callbacks_pointer->network_removed)
716                 return;
717
718         callbacks_pointer->network_removed(network);
719 }
720
721 #if defined TIZEN_EXT
722 static void callback_network_merged(GSupplicantNetwork *network)
723 {
724         if (!callbacks_pointer)
725                 return;
726
727         if (!callbacks_pointer->network_merged)
728                 return;
729
730         callbacks_pointer->network_merged(network);
731 }
732
733 static void callback_assoc_failed(void *user_data)
734 {
735         if (!callbacks_pointer)
736                 return;
737
738         if (!callbacks_pointer->assoc_failed)
739                 return;
740
741         callbacks_pointer->assoc_failed(user_data);
742 }
743 #endif
744
745 static void callback_network_changed(GSupplicantNetwork *network,
746                                         const char *property)
747 {
748         if (!callbacks_pointer)
749                 return;
750
751         if (!callbacks_pointer->network_changed)
752                 return;
753
754         callbacks_pointer->network_changed(network, property);
755 }
756
757 static void callback_network_associated(GSupplicantNetwork *network)
758 {
759         if (!callbacks_pointer)
760                 return;
761
762         if (!callbacks_pointer->network_associated)
763                 return;
764
765         callbacks_pointer->network_associated(network);
766 }
767
768 static void callback_peer_found(GSupplicantPeer *peer)
769 {
770         if (!callbacks_pointer)
771                 return;
772
773         if (!callbacks_pointer->peer_found)
774                 return;
775
776         callbacks_pointer->peer_found(peer);
777 }
778
779 static void callback_peer_lost(GSupplicantPeer *peer)
780 {
781         if (!callbacks_pointer)
782                 return;
783
784         if (!callbacks_pointer->peer_lost)
785                 return;
786
787         callbacks_pointer->peer_lost(peer);
788 }
789
790 static void callback_peer_changed(GSupplicantPeer *peer,
791                                                 GSupplicantPeerState state)
792 {
793         if (!callbacks_pointer)
794                 return;
795
796         if (!callbacks_pointer->peer_changed)
797                 return;
798
799         callbacks_pointer->peer_changed(peer, state);
800 }
801
802 static void callback_peer_request(GSupplicantPeer *peer)
803 {
804         if (!callbacks_pointer)
805                 return;
806
807         if (!callbacks_pointer->peer_request)
808                 return;
809
810         peer->connection_requested = true;
811
812         callbacks_pointer->peer_request(peer);
813 }
814
815 static void callback_disconnect_reason_code(GSupplicantInterface *interface,
816                                         int reason_code)
817 {
818         if (!callbacks_pointer)
819                 return;
820
821         if (!callbacks_pointer->disconnect_reasoncode)
822                 return;
823
824         if (reason_code != 0)
825                 callbacks_pointer->disconnect_reasoncode(interface,
826                                                         reason_code);
827 }
828
829 static void callback_assoc_status_code(GSupplicantInterface *interface,
830                                 int status_code)
831 {
832         if (!callbacks_pointer)
833                 return;
834
835         if (!callbacks_pointer->assoc_status_code)
836                 return;
837
838         callbacks_pointer->assoc_status_code(interface, status_code);
839
840 }
841
842 static void remove_group(gpointer data)
843 {
844         GSupplicantGroup *group = data;
845
846         if (group->members)
847                 g_slist_free_full(group->members, g_free);
848
849         g_free(group->path);
850         g_free(group);
851 }
852
853 static void remove_interface(gpointer data)
854 {
855         GSupplicantInterface *interface = data;
856
857         g_hash_table_destroy(interface->bss_mapping);
858         g_hash_table_destroy(interface->network_table);
859         g_hash_table_destroy(interface->peer_table);
860         g_hash_table_destroy(interface->group_table);
861
862         if (interface->scan_callback) {
863                 SUPPLICANT_DBG("call interface %p callback %p scanning %d",
864                                 interface, interface->scan_callback,
865                                 interface->scanning);
866
867                 interface->scan_callback(-EIO, interface, interface->scan_data);
868                 interface->scan_callback = NULL;
869                 interface->scan_data = NULL;
870
871                 if (interface->scanning) {
872                         interface->scanning = FALSE;
873                         callback_scan_finished(interface);
874                 }
875         }
876
877         callback_interface_removed(interface);
878
879         g_free(interface->wps_cred.key);
880         g_free(interface->path);
881         g_free(interface->network_path);
882 #if defined TIZEN_EXT
883         interface->network_path = NULL;
884 #endif
885         g_free(interface->ifname);
886         g_free(interface->driver);
887         g_free(interface->bridge);
888         remove_network_information(interface);
889         g_free(interface);
890 }
891
892 static void remove_network(gpointer data)
893 {
894         GSupplicantNetwork *network = data;
895
896         g_hash_table_destroy(network->bss_table);
897
898         callback_network_removed(network);
899
900         g_hash_table_destroy(network->config_table);
901
902         g_free(network->path);
903         g_free(network->group);
904         g_free(network->name);
905 #if defined TIZEN_EXT
906         g_free(network->eap);
907         g_free(network->identity);
908         g_free(network->phase2);
909 #endif
910 #if defined TIZEN_EXT
911         g_slist_free_full(network->vsie_list, g_free);
912 #endif
913
914         g_free(network);
915 }
916
917 static void remove_bss(gpointer data)
918 {
919         struct g_supplicant_bss *bss = data;
920
921         g_free(bss->path);
922 #if defined TIZEN_EXT
923         g_slist_free_full(bss->vsie_list, g_free);
924 #endif
925         g_free(bss);
926 }
927
928 static void remove_peer(gpointer data)
929 {
930         GSupplicantPeer *peer = data;
931
932         callback_peer_lost(peer);
933
934         if (peer->groups)
935                 g_slist_free_full(peer->groups, g_free);
936
937         if (peer_mapping)
938                 g_hash_table_remove(peer_mapping, peer->path);
939
940         if (pending_peer_connection)
941                 g_hash_table_remove(pending_peer_connection, peer->path);
942
943         g_free(peer->path);
944         g_free(peer->name);
945         g_free(peer->identifier);
946         g_free(peer->widi_ies);
947
948         g_free(peer);
949 }
950
951 static void debug_strvalmap(const char *label, struct strvalmap *map,
952                                                         unsigned int val)
953 {
954         int i;
955
956         for (i = 0; map[i].str; i++) {
957                 if (val & map[i].val)
958                         SUPPLICANT_DBG("%s: %s", label, map[i].str);
959         }
960 }
961
962 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
963 {
964         GSupplicantInterface *interface = user_data;
965         const char *str = NULL;
966         int i;
967
968         dbus_message_iter_get_basic(iter, &str);
969         if (!str)
970                 return;
971
972         for (i = 0; keymgmt_map[i].str; i++)
973                 if (strcmp(str, keymgmt_map[i].str) == 0) {
974                         interface->keymgmt_capa |= keymgmt_map[i].val;
975                         break;
976                 }
977 }
978
979 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
980 {
981         GSupplicantInterface *interface = user_data;
982         const char *str = NULL;
983         int i;
984
985         dbus_message_iter_get_basic(iter, &str);
986         if (!str)
987                 return;
988
989         for (i = 0; authalg_capa_map[i].str; i++)
990                 if (strcmp(str, authalg_capa_map[i].str) == 0) {
991                         interface->authalg_capa |= authalg_capa_map[i].val;
992                         break;
993                 }
994 }
995
996 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
997 {
998         GSupplicantInterface *interface = user_data;
999         const char *str = NULL;
1000         int i;
1001
1002         dbus_message_iter_get_basic(iter, &str);
1003         if (!str)
1004                 return;
1005
1006         for (i = 0; proto_capa_map[i].str; i++)
1007                 if (strcmp(str, proto_capa_map[i].str) == 0) {
1008                         interface->proto_capa |= proto_capa_map[i].val;
1009                         break;
1010                 }
1011 }
1012
1013 static void interface_capability_pairwise(DBusMessageIter *iter,
1014                                                         void *user_data)
1015 {
1016         GSupplicantInterface *interface = user_data;
1017         const char *str = NULL;
1018         int i;
1019
1020         dbus_message_iter_get_basic(iter, &str);
1021         if (!str)
1022                 return;
1023
1024         for (i = 0; pairwise_map[i].str; i++)
1025                 if (strcmp(str, pairwise_map[i].str) == 0) {
1026                         interface->pairwise_capa |= pairwise_map[i].val;
1027                         break;
1028                 }
1029 }
1030
1031 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
1032 {
1033         GSupplicantInterface *interface = user_data;
1034         const char *str = NULL;
1035         int i;
1036
1037         dbus_message_iter_get_basic(iter, &str);
1038         if (!str)
1039                 return;
1040
1041         for (i = 0; group_map[i].str; i++)
1042                 if (strcmp(str, group_map[i].str) == 0) {
1043                         interface->group_capa |= group_map[i].val;
1044                         break;
1045                 }
1046 }
1047
1048 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
1049 {
1050         GSupplicantInterface *interface = user_data;
1051         const char *str = NULL;
1052         int i;
1053
1054         dbus_message_iter_get_basic(iter, &str);
1055         if (!str)
1056                 return;
1057
1058         for (i = 0; scan_capa_map[i].str; i++)
1059                 if (strcmp(str, scan_capa_map[i].str) == 0) {
1060                         interface->scan_capa |= scan_capa_map[i].val;
1061                         break;
1062                 }
1063 }
1064
1065 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
1066 {
1067         GSupplicantInterface *interface = user_data;
1068         const char *str = NULL;
1069         int i;
1070
1071         dbus_message_iter_get_basic(iter, &str);
1072         if (!str)
1073                 return;
1074
1075         for (i = 0; mode_capa_map[i].str; i++)
1076                 if (strcmp(str, mode_capa_map[i].str) == 0) {
1077                         interface->mode_capa |= mode_capa_map[i].val;
1078                         break;
1079                 }
1080 }
1081
1082 static void interface_capability(const char *key, DBusMessageIter *iter,
1083                                                         void *user_data)
1084 {
1085         GSupplicantInterface *interface = user_data;
1086
1087         if (!key)
1088                 return;
1089
1090         if (g_strcmp0(key, "KeyMgmt") == 0)
1091                 supplicant_dbus_array_foreach(iter,
1092                                 interface_capability_keymgmt, interface);
1093         else if (g_strcmp0(key, "AuthAlg") == 0)
1094                 supplicant_dbus_array_foreach(iter,
1095                                 interface_capability_authalg, interface);
1096         else if (g_strcmp0(key, "Protocol") == 0)
1097                 supplicant_dbus_array_foreach(iter,
1098                                 interface_capability_proto, interface);
1099         else if (g_strcmp0(key, "Pairwise") == 0)
1100                 supplicant_dbus_array_foreach(iter,
1101                                 interface_capability_pairwise, interface);
1102         else if (g_strcmp0(key, "Group") == 0)
1103                 supplicant_dbus_array_foreach(iter,
1104                                 interface_capability_group, interface);
1105         else if (g_strcmp0(key, "Scan") == 0)
1106                 supplicant_dbus_array_foreach(iter,
1107                                 interface_capability_scan, interface);
1108         else if (g_strcmp0(key, "Modes") == 0)
1109                 supplicant_dbus_array_foreach(iter,
1110                                 interface_capability_mode, interface);
1111         else if (g_strcmp0(key, "MaxScanSSID") == 0) {
1112                 dbus_int32_t max_scan_ssid;
1113
1114                 dbus_message_iter_get_basic(iter, &max_scan_ssid);
1115                 if (max_scan_ssid < 2)
1116                         max_scan_ssid = 0;
1117                 interface->max_scan_ssids = max_scan_ssid;
1118 #if defined TIZEN_EXT
1119         } else if (g_strcmp0(key, "Is5GhzSupported") == 0) {
1120                 dbus_bool_t is_5_0_Ghz_supported;
1121
1122                 dbus_message_iter_get_basic(iter, &is_5_0_Ghz_supported);
1123                 interface->is_5_0_Ghz_supported = is_5_0_Ghz_supported;
1124 #endif
1125         } else
1126                 SUPPLICANT_DBG("key %s type %c",
1127                                 key, dbus_message_iter_get_arg_type(iter));
1128 }
1129
1130 struct set_apscan_data
1131 {
1132         unsigned int ap_scan;
1133         GSupplicantInterface *interface;
1134 };
1135
1136 static void set_apscan(DBusMessageIter *iter, void *user_data)
1137 {
1138         struct set_apscan_data *data = user_data;
1139         unsigned int ap_scan = data->ap_scan;
1140
1141         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ap_scan);
1142 }
1143
1144 static void set_apscan_complete(const char *error,
1145                 DBusMessageIter *iter, void *user_data)
1146 {
1147         struct set_apscan_data *data = user_data;
1148         GSupplicantInterface *interface = data->interface;
1149
1150         if (error) {
1151                 interface->ap_create_in_progress = false;
1152                 SUPPLICANT_DBG("Set AP scan error %s", error);
1153                 goto error;
1154         }
1155
1156         interface->ap_create_in_progress = true;
1157 error:
1158         dbus_free(data);
1159 }
1160
1161 int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
1162                                                         unsigned int ap_scan)
1163 {
1164         struct set_apscan_data *data;
1165         int ret;
1166
1167         data = dbus_malloc0(sizeof(*data));
1168
1169         if (!data)
1170                 return -ENOMEM;
1171
1172         data->ap_scan = ap_scan;
1173         data->interface = interface;
1174
1175         ret = supplicant_dbus_property_set(interface->path,
1176                         SUPPLICANT_INTERFACE ".Interface",
1177                         "ApScan", DBUS_TYPE_UINT32_AS_STRING,
1178                         set_apscan, set_apscan_complete, data, NULL);
1179         if (ret < 0)
1180                 dbus_free(data);
1181
1182         return ret;
1183 }
1184
1185 void g_supplicant_interface_set_data(GSupplicantInterface *interface,
1186                                                                 void *data)
1187 {
1188         if (!interface)
1189                 return;
1190
1191         interface->data = data;
1192
1193         if (!data)
1194                 interface->scan_callback = NULL;
1195 }
1196
1197 void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
1198 {
1199         if (!interface)
1200                 return NULL;
1201
1202         return interface->data;
1203 }
1204
1205 const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface)
1206 {
1207         if (!interface)
1208                 return NULL;
1209
1210         return interface->ifname;
1211 }
1212
1213 #if defined TIZEN_EXT
1214 bool g_supplicant_interface_get_is_5_0_ghz_supported(GSupplicantInterface *interface)
1215 {
1216         if (!interface)
1217                 return NULL;
1218
1219         return interface->is_5_0_Ghz_supported;
1220 }
1221 #endif
1222
1223 const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface)
1224 {
1225         if (!interface)
1226                 return NULL;
1227
1228         return interface->driver;
1229 }
1230
1231 GSupplicantState g_supplicant_interface_get_state(
1232                                         GSupplicantInterface *interface)
1233 {
1234         if (!interface)
1235                 return G_SUPPLICANT_STATE_UNKNOWN;
1236
1237         return interface->state;
1238 }
1239
1240 const char *g_supplicant_interface_get_wps_key(GSupplicantInterface *interface)
1241 {
1242         if (!interface)
1243                 return NULL;
1244
1245         return (const char *)interface->wps_cred.key;
1246 }
1247
1248 const void *g_supplicant_interface_get_wps_ssid(GSupplicantInterface *interface,
1249                                                         unsigned int *ssid_len)
1250 {
1251         if (!ssid_len)
1252                 return NULL;
1253
1254         if (!interface || interface->wps_cred.ssid_len == 0) {
1255                 *ssid_len = 0;
1256                 return NULL;
1257         }
1258
1259         *ssid_len = interface->wps_cred.ssid_len;
1260         return interface->wps_cred.ssid;
1261 }
1262
1263 GSupplicantWpsState g_supplicant_interface_get_wps_state(
1264                                         GSupplicantInterface *interface)
1265 {
1266         if (!interface)
1267                 return G_SUPPLICANT_WPS_STATE_UNKNOWN;
1268
1269         return interface->wps_state;
1270 }
1271
1272 unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface)
1273 {
1274         if (!interface)
1275                 return 0;
1276
1277         return interface->mode_capa;
1278 }
1279
1280 unsigned int g_supplicant_interface_get_max_scan_ssids(
1281                                 GSupplicantInterface *interface)
1282 {
1283         if (!interface)
1284                 return 0;
1285
1286         if (interface->max_scan_ssids == 0)
1287                 return WPAS_MAX_SCAN_SSIDS;
1288
1289         return interface->max_scan_ssids;
1290 }
1291
1292 static void set_network_enabled(DBusMessageIter *iter, void *user_data)
1293 {
1294         dbus_bool_t enable = *(dbus_bool_t *)user_data;
1295
1296         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &enable);
1297 }
1298
1299 int g_supplicant_interface_enable_selected_network(GSupplicantInterface *interface,
1300                                                         dbus_bool_t enable)
1301 {
1302         if (!interface)
1303                 return -1;
1304
1305         if (!interface->network_path)
1306                 return -1;
1307
1308         SUPPLICANT_DBG(" ");
1309         return supplicant_dbus_property_set(interface->network_path,
1310                                 SUPPLICANT_INTERFACE ".Network",
1311                                 "Enabled", DBUS_TYPE_BOOLEAN_AS_STRING,
1312                                 set_network_enabled, NULL, &enable, NULL);
1313 }
1314
1315 dbus_bool_t g_supplicant_interface_get_ready(GSupplicantInterface *interface)
1316 {
1317         if (!interface)
1318                 return FALSE;
1319
1320         return interface->ready;
1321 }
1322
1323 GSupplicantInterface *g_supplicant_network_get_interface(
1324                                         GSupplicantNetwork *network)
1325 {
1326         if (!network)
1327                 return NULL;
1328
1329         return network->interface;
1330 }
1331
1332 const char *g_supplicant_network_get_name(GSupplicantNetwork *network)
1333 {
1334         if (!network || !network->name)
1335                 return "";
1336
1337         return network->name;
1338 }
1339
1340 const char *g_supplicant_network_get_identifier(GSupplicantNetwork *network)
1341 {
1342         if (!network || !network->group)
1343                 return "";
1344
1345         return network->group;
1346 }
1347
1348 const char *g_supplicant_network_get_path(GSupplicantNetwork *network)
1349 {
1350         if (!network || !network->path)
1351                 return NULL;
1352
1353         return network->path;
1354 }
1355
1356 const char *g_supplicant_network_get_mode(GSupplicantNetwork *network)
1357 {
1358         if (!network)
1359                 return G_SUPPLICANT_MODE_UNKNOWN;
1360
1361         return mode2string(network->mode);
1362 }
1363
1364 const char *g_supplicant_network_get_security(GSupplicantNetwork *network)
1365 {
1366         if (!network)
1367                 return G_SUPPLICANT_SECURITY_UNKNOWN;
1368
1369         return security2string(network->security);
1370 }
1371
1372 const void *g_supplicant_network_get_ssid(GSupplicantNetwork *network,
1373                                                 unsigned int *ssid_len)
1374 {
1375         if (!network) {
1376                 *ssid_len = 0;
1377                 return NULL;
1378         }
1379
1380         *ssid_len = network->ssid_len;
1381         return network->ssid;
1382 }
1383
1384 dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network)
1385 {
1386         if (!network)
1387                 return 0;
1388
1389         return network->signal;
1390 }
1391
1392 dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network)
1393 {
1394         if (!network)
1395                 return 0;
1396
1397         return network->frequency;
1398 }
1399
1400 dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network)
1401 {
1402         if (!network)
1403                 return FALSE;
1404
1405         return network->wps;
1406 }
1407
1408 dbus_bool_t g_supplicant_network_is_wps_active(GSupplicantNetwork *network)
1409 {
1410         if (!network)
1411                 return FALSE;
1412
1413         if (network->wps_capabilities & G_SUPPLICANT_WPS_CONFIGURED)
1414                 return TRUE;
1415
1416         return FALSE;
1417 }
1418
1419 dbus_bool_t g_supplicant_network_is_wps_pbc(GSupplicantNetwork *network)
1420 {
1421         if (!network)
1422                 return FALSE;
1423
1424         if (network->wps_capabilities & G_SUPPLICANT_WPS_PBC)
1425                 return TRUE;
1426
1427         return FALSE;
1428 }
1429
1430 dbus_bool_t g_supplicant_network_is_wps_advertizing(GSupplicantNetwork *network)
1431 {
1432         if (!network)
1433                 return FALSE;
1434
1435         if (network->wps_capabilities & G_SUPPLICANT_WPS_REGISTRAR)
1436                 return TRUE;
1437
1438         return FALSE;
1439 }
1440
1441 #ifdef TIZEN_EXT
1442 GSupplicantPhy_mode g_supplicant_network_get_phy_mode(GSupplicantNetwork *network)
1443 {
1444         if (!network)
1445                 return G_SUPPLICANT_MODE_IEEE80211_UNKNOWN;
1446
1447         return network->phy_mode;
1448 }
1449 #endif
1450
1451 GSupplicantInterface *g_supplicant_peer_get_interface(GSupplicantPeer *peer)
1452 {
1453         if (!peer)
1454                 return NULL;
1455
1456         return peer->interface;
1457 }
1458
1459 const char *g_supplicant_peer_get_path(GSupplicantPeer *peer)
1460 {
1461         if (!peer)
1462                 return NULL;
1463
1464         return peer->path;
1465 }
1466
1467 const char *g_supplicant_peer_get_identifier(GSupplicantPeer *peer)
1468 {
1469         if (!peer)
1470                 return NULL;
1471
1472         return peer->identifier;
1473 }
1474
1475 const void *g_supplicant_peer_get_device_address(GSupplicantPeer *peer)
1476 {
1477         if (!peer)
1478                 return NULL;
1479
1480         return peer->device_address;
1481 }
1482
1483 const void *g_supplicant_peer_get_iface_address(GSupplicantPeer *peer)
1484 {
1485         if (!peer)
1486                 return NULL;
1487
1488         return peer->iface_address;
1489 }
1490
1491 const char *g_supplicant_peer_get_name(GSupplicantPeer *peer)
1492 {
1493         if (!peer)
1494                 return NULL;
1495
1496         return peer->name;
1497 }
1498
1499 #if defined TIZEN_EXT
1500 bool g_supplicant_network_is_hs20AP(GSupplicantNetwork *network)
1501 {
1502         if (!network)
1503                 return 0;
1504
1505         return network->isHS20AP;
1506 }
1507
1508 const char *g_supplicant_network_get_eap(GSupplicantNetwork *network)
1509 {
1510         if (!network || !network->eap)
1511                 return NULL;
1512
1513         return network->eap;
1514 }
1515
1516 const char *g_supplicant_network_get_identity(GSupplicantNetwork *network)
1517 {
1518         if (!network || !network->identity)
1519                 return NULL;
1520
1521         return network->identity;
1522 }
1523
1524 const char *g_supplicant_network_get_phase2(GSupplicantNetwork *network)
1525 {
1526         if (!network || !network->phase2)
1527                 return NULL;
1528
1529         return network->phase2;
1530 }
1531
1532 unsigned int g_supplicant_network_get_keymgmt(GSupplicantNetwork *network)
1533 {
1534         if (network == NULL)
1535                 return 0;
1536
1537         return network->keymgmt;
1538 }
1539
1540 const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork
1541                                                           *network)
1542 {
1543         if (!network)
1544                 return NULL;
1545
1546         return network->country_code;
1547 }
1548 #endif
1549
1550 const unsigned char *g_supplicant_peer_get_widi_ies(GSupplicantPeer *peer,
1551                                                                 int *length)
1552 {
1553         if (!peer || !length)
1554                 return NULL;
1555
1556         *length = peer->widi_ies_length;
1557         return peer->widi_ies;
1558 }
1559
1560 bool g_supplicant_peer_is_wps_pbc(GSupplicantPeer *peer)
1561 {
1562         if (!peer)
1563                 return false;
1564
1565         if (peer->wps_capabilities & G_SUPPLICANT_WPS_PBC)
1566                 return true;
1567
1568         return false;
1569 }
1570
1571 bool g_supplicant_peer_is_wps_pin(GSupplicantPeer *peer)
1572 {
1573         if (!peer)
1574                 return false;
1575
1576         if (peer->wps_capabilities & G_SUPPLICANT_WPS_PIN)
1577                 return true;
1578
1579         return false;
1580 }
1581
1582 bool g_supplicant_peer_is_in_a_group(GSupplicantPeer *peer)
1583 {
1584         if (!peer || !peer->groups)
1585                 return false;
1586
1587         return true;
1588 }
1589
1590 GSupplicantInterface *g_supplicant_peer_get_group_interface(GSupplicantPeer *peer)
1591 {
1592         if (!peer)
1593                 return NULL;
1594
1595         return (GSupplicantInterface *) peer->current_group_iface;
1596 }
1597
1598 bool g_supplicant_peer_is_client(GSupplicantPeer *peer)
1599 {
1600         GSupplicantGroup *group;
1601         GSList *list;
1602
1603         if (!peer)
1604                 return false;
1605
1606         for (list = peer->groups; list; list = list->next) {
1607                 const char *path = list->data;
1608
1609                 group = g_hash_table_lookup(group_mapping, path);
1610                 if (!group)
1611                         continue;
1612
1613                 if (group->role != G_SUPPLICANT_GROUP_ROLE_CLIENT ||
1614                                 group->orig_interface != peer->interface)
1615                         continue;
1616
1617                 if (group->interface == peer->current_group_iface)
1618                         return true;
1619         }
1620
1621         return false;
1622 }
1623
1624 bool g_supplicant_peer_has_requested_connection(GSupplicantPeer *peer)
1625 {
1626         if (!peer)
1627                 return false;
1628
1629         return peer->connection_requested;
1630 }
1631
1632 #if defined TIZEN_EXT
1633 /*
1634  * Description: Network client requires additional wifi specific info
1635  */
1636 const unsigned char *g_supplicant_network_get_bssid(GSupplicantNetwork *network)
1637 {
1638         if (network == NULL || network->best_bss == NULL)
1639                 return NULL;
1640
1641         return (const unsigned char *)network->best_bss->bssid;
1642 }
1643
1644 unsigned int g_supplicant_network_get_maxrate(GSupplicantNetwork *network)
1645 {
1646         if (network == NULL || network->best_bss == NULL)
1647                 return 0;
1648
1649         return network->best_bss->maxrate;
1650 }
1651
1652 const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network)
1653 {
1654         if (network == NULL || network->best_bss == NULL)
1655                 return NULL;
1656
1657         if (network->best_bss->security == G_SUPPLICANT_SECURITY_PSK ||
1658             network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) {
1659                 unsigned int pairwise;
1660
1661                 pairwise = network->best_bss->rsn_pairwise |
1662                                 network->best_bss->wpa_pairwise;
1663
1664                 if ((pairwise & G_SUPPLICANT_PAIRWISE_CCMP) &&
1665                     (pairwise & G_SUPPLICANT_PAIRWISE_TKIP))
1666                         return "mixed";
1667                 else if (pairwise & G_SUPPLICANT_PAIRWISE_CCMP)
1668                         return "aes";
1669                 else if (pairwise & G_SUPPLICANT_PAIRWISE_TKIP)
1670                         return "tkip";
1671
1672         } else if (network->best_bss->security == G_SUPPLICANT_SECURITY_WEP)
1673                 return "wep";
1674         else if (network->best_bss->security == G_SUPPLICANT_SECURITY_NONE)
1675                 return "none";
1676
1677         return NULL;
1678 }
1679
1680 bool g_supplicant_network_get_rsn_mode(GSupplicantNetwork *network)
1681 {
1682         if (network == NULL || network->best_bss == NULL)
1683                 return 0;
1684
1685         if (network->best_bss->rsn_selected) {
1686                 const char *mode = g_supplicant_network_get_enc_mode(network);
1687                 if (g_strcmp0(mode, "aes") == 0 ||
1688                                 g_strcmp0(mode, "mixed") == 0)
1689                         return true;
1690                 else
1691                         return false;
1692         } else
1693                 return false;
1694 }
1695
1696 void *g_supplicant_network_get_wifi_vsie(GSupplicantNetwork *network)
1697 {
1698         GSList *vsie_list = NULL;
1699
1700         if (!network)
1701                 return NULL;
1702
1703         if (g_slist_length(network->vsie_list) > 0) {
1704                 GSList *list = NULL;
1705                 unsigned char *vsie = NULL;
1706                 for (list = network->vsie_list; list; list = list->next) {
1707                         unsigned char *ie = (unsigned char *)list->data;
1708                         if (ie == NULL)
1709                                 continue;
1710                         vsie = (unsigned char *)g_try_malloc0(ie[1]+2); // tag number size(1), tag length size(1)
1711
1712                         if (vsie) {
1713                                 memcpy(vsie, ie, ie[1]+2);
1714                                 vsie_list = g_slist_append(vsie_list, vsie);
1715                         } else
1716                                 SUPPLICANT_DBG("Failed to allocate memory");
1717                 }
1718         }
1719
1720         return vsie_list;
1721 }
1722
1723 static void update_bssid_list(gpointer key, gpointer value, gpointer user_data)
1724 {
1725         struct g_supplicant_bss *bss = value;
1726         struct g_connman_bssids *bssids = NULL;
1727         GSList **list = (GSList **)user_data;
1728
1729         bssids = (struct g_connman_bssids *)g_try_malloc0(sizeof(struct g_connman_bssids));
1730
1731         if (bssids) {
1732                 memcpy(bssids->bssid, bss->bssid, WIFI_BSSID_LEN_MAX);
1733
1734                 bssids->strength = bss->signal;
1735                 bssids->strength += 120;
1736
1737                 if (bssids->strength > 100)
1738                         bssids->strength = 100;
1739
1740                 bssids->frequency = bss->frequency;
1741                 *list = g_slist_append(*list, bssids);
1742         } else
1743                 SUPPLICANT_DBG("Failed to allocate memory");
1744 }
1745
1746 static gint cmp_bss(gconstpointer a, gconstpointer b)
1747 {
1748         struct g_connman_bssids *entry_a = (struct g_connman_bssids *)a;
1749         struct g_connman_bssids *entry_b = (struct g_connman_bssids *)b;
1750
1751         if (entry_a->strength > entry_b->strength)
1752                 return -1;
1753
1754         if (entry_a->strength < entry_b->strength)
1755                 return 1;
1756
1757         return 0;
1758 }
1759
1760 void *g_supplicant_network_get_bssid_list(GSupplicantNetwork *network)
1761 {
1762         GSList *bssid_list = NULL;
1763
1764         if (g_hash_table_size(network->bss_table) < 1)
1765                 return NULL;
1766
1767         g_hash_table_foreach(network->bss_table, update_bssid_list, &bssid_list);
1768         bssid_list = g_slist_sort(bssid_list, cmp_bss);
1769
1770         return bssid_list;
1771 }
1772 #endif
1773
1774 static void merge_network(GSupplicantNetwork *network)
1775 {
1776         GString *str;
1777         const char *ssid, *mode, *key_mgmt;
1778 #if defined TIZEN_EXT
1779         const char *isHS20AP;
1780         const char *eap, *identity, *phase2;
1781 #endif
1782         unsigned int i, ssid_len;
1783         char *group;
1784
1785         ssid = g_hash_table_lookup(network->config_table, "ssid");
1786         mode = g_hash_table_lookup(network->config_table, "mode");
1787         key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
1788 #if defined TIZEN_EXT
1789         isHS20AP = g_hash_table_lookup(network->config_table, "isHS20AP");
1790         eap = g_hash_table_lookup(network->config_table, "eap");
1791         identity = g_hash_table_lookup(network->config_table, "identity");
1792         phase2 = g_hash_table_lookup(network->config_table, "phase2");
1793 #endif
1794
1795         SUPPLICANT_DBG("ssid %s mode %s", ssid, mode);
1796
1797         if (ssid)
1798                 ssid_len = strlen(ssid);
1799         else
1800                 ssid_len = 0;
1801
1802         str = g_string_sized_new((ssid_len * 2) + 24);
1803         if (!str)
1804                 return;
1805
1806         for (i = 0; i < ssid_len; i++)
1807 #if defined TIZEN_EXT
1808         {
1809                 if (ssid[i] != '"')
1810 #endif
1811                 g_string_append_printf(str, "%02x", ssid[i]);
1812 #if defined TIZEN_EXT
1813         }
1814 #endif
1815
1816         if (g_strcmp0(mode, "0") == 0)
1817                 g_string_append_printf(str, "_managed");
1818         else if (g_strcmp0(mode, "1") == 0)
1819                 g_string_append_printf(str, "_adhoc");
1820 #if defined TIZEN_EXT_WIFI_MESH
1821         else if (g_strcmp0(mode, "5") == 0)
1822                 g_string_append_printf(str, "_mesh");
1823 #endif
1824
1825         if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
1826                 g_string_append_printf(str, "_psk");
1827 #if defined TIZEN_EXT
1828         else if (g_strcmp0(key_mgmt, "WPA-EAP") == 0)
1829                 g_string_append_printf(str, "_ieee8021x");
1830         else
1831                 g_string_append_printf(str, "_none");
1832 #endif
1833
1834         group = g_string_free(str, FALSE);
1835
1836         SUPPLICANT_DBG("%s", group);
1837
1838 #if defined TIZEN_EXT
1839         if (g_strcmp0(isHS20AP, "1") == 0) {
1840                 network->isHS20AP = 1;
1841                 if (network->eap)
1842                         g_free(network->eap);
1843                 network->eap = g_strdup(eap);
1844
1845                 if (network->identity)
1846                         g_free(network->identity);
1847                 network->identity = g_strdup(identity);
1848
1849                 if (network->phase2)
1850                         g_free(network->phase2);
1851                 network->phase2 = g_strdup(phase2);
1852         } else
1853                 network->isHS20AP = 0;
1854
1855         network->group = g_strdup(group);
1856         callback_network_merged(network);
1857         g_free(network->group);
1858 #endif
1859
1860         g_free(group);
1861
1862         g_hash_table_destroy(network->config_table);
1863
1864         g_free(network->path);
1865         g_free(network);
1866 }
1867
1868 static void network_property(const char *key, DBusMessageIter *iter,
1869                                                         void *user_data)
1870 {
1871         GSupplicantNetwork *network = user_data;
1872
1873         if (!network->interface)
1874                 return;
1875
1876         if (!key) {
1877                 merge_network(network);
1878                 return;
1879         }
1880
1881         if (g_strcmp0(key, "Enabled") == 0) {
1882                 dbus_bool_t enabled = FALSE;
1883
1884                 dbus_message_iter_get_basic(iter, &enabled);
1885         } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
1886                 const char *str = NULL;
1887
1888                 dbus_message_iter_get_basic(iter, &str);
1889                 if (str) {
1890                         g_hash_table_replace(network->config_table,
1891                                                 g_strdup(key), g_strdup(str));
1892                 }
1893         } else
1894                 SUPPLICANT_DBG("key %s type %c",
1895                                 key, dbus_message_iter_get_arg_type(iter));
1896 }
1897
1898 static void interface_network_added(DBusMessageIter *iter, void *user_data)
1899 {
1900         GSupplicantInterface *interface = user_data;
1901         GSupplicantNetwork *network;
1902         const char *path = NULL;
1903
1904         SUPPLICANT_DBG("");
1905
1906         dbus_message_iter_get_basic(iter, &path);
1907         if (!path)
1908                 return;
1909
1910         if (g_strcmp0(path, "/") == 0)
1911                 return;
1912
1913         network = g_try_new0(GSupplicantNetwork, 1);
1914         if (!network)
1915                 return;
1916
1917         network->interface = interface;
1918         network->path = g_strdup(path);
1919
1920         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1921                                                         g_free, g_free);
1922
1923         dbus_message_iter_next(iter);
1924         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1925                 supplicant_dbus_property_foreach(iter, network_property,
1926                                                                 network);
1927                 network_property(NULL, NULL, network);
1928                 return;
1929         }
1930
1931         supplicant_dbus_property_get_all(path,
1932                                 SUPPLICANT_INTERFACE ".Network",
1933                                         network_property, network, NULL);
1934 }
1935
1936 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
1937 {
1938         SUPPLICANT_DBG("");
1939         return;
1940 }
1941
1942 static char *create_name(unsigned char *ssid, int ssid_len)
1943 {
1944         GString *string;
1945         const gchar *remainder, *invalid;
1946         int valid_bytes, remaining_bytes;
1947
1948         if (ssid_len < 1 || ssid[0] == '\0')
1949                 return g_strdup("");
1950
1951         string = NULL;
1952         remainder = (const gchar *)ssid;
1953         remaining_bytes = ssid_len;
1954
1955         while (remaining_bytes != 0) {
1956                 if (g_utf8_validate(remainder, remaining_bytes,
1957                                         &invalid)) {
1958                         break;
1959                 }
1960
1961                 valid_bytes = invalid - remainder;
1962
1963                 if (!string)
1964                         string = g_string_sized_new(remaining_bytes);
1965
1966                 g_string_append_len(string, remainder, valid_bytes);
1967
1968                 /* append U+FFFD REPLACEMENT CHARACTER */
1969                 g_string_append(string, "\357\277\275");
1970
1971                 remaining_bytes -= valid_bytes + 1;
1972                 remainder = invalid + 1;
1973         }
1974
1975         if (!string)
1976                 return g_strndup((const gchar *)ssid, ssid_len + 1);
1977
1978         g_string_append(string, remainder);
1979
1980         return g_string_free(string, FALSE);
1981 }
1982
1983 static char *create_group(struct g_supplicant_bss *bss)
1984 {
1985         GString *str;
1986         unsigned int i;
1987         const char *mode, *security;
1988
1989         str = g_string_sized_new((bss->ssid_len * 2) + 24);
1990         if (!str)
1991                 return NULL;
1992
1993         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
1994                 for (i = 0; i < bss->ssid_len; i++)
1995                         g_string_append_printf(str, "%02x", bss->ssid[i]);
1996         } else
1997                 g_string_append_printf(str, "hidden");
1998
1999         mode = mode2string(bss->mode);
2000         if (mode)
2001                 g_string_append_printf(str, "_%s", mode);
2002
2003         security = security2string(bss->security);
2004         if (security)
2005                 g_string_append_printf(str, "_%s", security);
2006
2007         return g_string_free(str, FALSE);
2008 }
2009
2010 static int add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
2011 {
2012         GSupplicantInterface *interface = bss->interface;
2013         GSupplicantNetwork *network;
2014         char *group;
2015
2016         group = create_group(bss);
2017         SUPPLICANT_DBG("New group created: %s", group);
2018
2019         if (!group)
2020                 return -ENOMEM;
2021
2022         network = g_hash_table_lookup(interface->network_table, group);
2023         if (network) {
2024                 g_free(group);
2025                 SUPPLICANT_DBG("Network %s already exist", network->name);
2026
2027                 goto done;
2028         }
2029
2030         network = g_try_new0(GSupplicantNetwork, 1);
2031         if (!network) {
2032                 g_free(group);
2033                 return -ENOMEM;
2034         }
2035
2036         network->interface = interface;
2037         if (!network->path)
2038                 network->path = g_strdup(bss->path);
2039         network->group = group;
2040         network->name = create_name(bss->ssid, bss->ssid_len);
2041         network->mode = bss->mode;
2042         network->security = bss->security;
2043         network->ssid_len = bss->ssid_len;
2044         memcpy(network->ssid, bss->ssid, bss->ssid_len);
2045         network->signal = bss->signal;
2046         network->frequency = bss->frequency;
2047         network->best_bss = bss;
2048
2049 #if defined TIZEN_EXT
2050         network->keymgmt = bss->keymgmt;
2051
2052         if (g_slist_length(bss->vsie_list) > 0) {
2053                 GSList *list = NULL;
2054                 unsigned char *vsie = NULL;
2055                 for (list = bss->vsie_list; list; list = list->next) {
2056                         unsigned char *ie = (unsigned char *)list->data;
2057                         vsie = (unsigned char *)g_try_malloc0(ie[1]+2); // tag number size(1), tag length size(1)
2058
2059                         if (vsie) {
2060                                 memcpy(vsie, ie, ie[1]+2);
2061                                 network->vsie_list = g_slist_append(network->vsie_list, vsie);
2062                         } else
2063                                 SUPPLICANT_DBG("Failed to allocate memory.");
2064                 }
2065         }
2066
2067         network->isHS20AP = bss->hs20;
2068         memcpy(network->country_code, bss->country_code, COUNTRY_CODE_LENGTH);
2069         network->phy_mode = bss->phy_mode;
2070 #endif
2071
2072         SUPPLICANT_DBG("New network %s created", network->name);
2073
2074         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
2075                                                         NULL, remove_bss);
2076
2077         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
2078                                                         g_free, g_free);
2079
2080         g_hash_table_replace(interface->network_table,
2081                                                 network->group, network);
2082
2083         callback_network_added(network);
2084
2085 done:
2086         /* We update network's WPS properties if only bss provides WPS. */
2087         if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) {
2088                 network->wps = TRUE;
2089                 network->wps_capabilities |= bss->wps_capabilities;
2090         }
2091
2092         /*
2093          * Do not change best BSS if we are connected. It will be done through
2094          * CurrentBSS property in case of misalignment with wpa_s or roaming.
2095          */
2096         if (network != interface->current_network &&
2097                                 bss->signal > network->signal) {
2098                 network->signal = bss->signal;
2099                 network->best_bss = bss;
2100                 callback_network_changed(network, "Signal");
2101         }
2102
2103         g_hash_table_replace(interface->bss_mapping, bss->path, network);
2104         g_hash_table_replace(network->bss_table, bss->path, bss);
2105
2106         g_hash_table_replace(bss_mapping, bss->path, interface);
2107
2108         return 0;
2109 }
2110
2111 static void bss_rates(DBusMessageIter *iter, void *user_data)
2112 {
2113         struct g_supplicant_bss *bss = user_data;
2114         dbus_uint32_t rate = 0;
2115
2116         dbus_message_iter_get_basic(iter, &rate);
2117         if (rate == 0)
2118                 return;
2119
2120         if (rate > bss->maxrate)
2121                 bss->maxrate = rate;
2122 }
2123
2124 static void bss_keymgmt(DBusMessageIter *iter, void *user_data)
2125 {
2126         unsigned int *keymgmt = user_data;
2127         const char *str = NULL;
2128         int i;
2129
2130         dbus_message_iter_get_basic(iter, &str);
2131         if (!str)
2132                 return;
2133
2134         for (i = 0; keymgmt_map[i].str; i++)
2135                 if (strcmp(str, keymgmt_map[i].str) == 0) {
2136                         SUPPLICANT_DBG("Keymgmt: %s", str);
2137                         *keymgmt |= keymgmt_map[i].val;
2138                         break;
2139                 }
2140 }
2141
2142 static void bss_group(DBusMessageIter *iter, void *user_data)
2143 {
2144         unsigned int *group = user_data;
2145         const char *str = NULL;
2146         int i;
2147
2148         dbus_message_iter_get_basic(iter, &str);
2149         if (!str)
2150                 return;
2151
2152         for (i = 0; group_map[i].str; i++)
2153                 if (strcmp(str, group_map[i].str) == 0) {
2154                         SUPPLICANT_DBG("Group: %s", str);
2155                         *group |= group_map[i].val;
2156                         break;
2157                 }
2158 }
2159
2160 static void bss_pairwise(DBusMessageIter *iter, void *user_data)
2161 {
2162         unsigned int *pairwise = user_data;
2163         const char *str = NULL;
2164         int i;
2165
2166         dbus_message_iter_get_basic(iter, &str);
2167         if (!str)
2168                 return;
2169
2170         for (i = 0; pairwise_map[i].str; i++)
2171                 if (strcmp(str, pairwise_map[i].str) == 0) {
2172                         SUPPLICANT_DBG("Pairwise: %s", str);
2173                         *pairwise |= pairwise_map[i].val;
2174                         break;
2175                 }
2176 }
2177
2178 static void bss_wpa(const char *key, DBusMessageIter *iter,
2179                         void *user_data)
2180 {
2181         struct g_supplicant_bss *bss = user_data;
2182         unsigned int value = 0;
2183
2184         SUPPLICANT_DBG("Key: %s", key);
2185
2186         if (g_strcmp0(key, "KeyMgmt") == 0) {
2187                 supplicant_dbus_array_foreach(iter, bss_keymgmt, &value);
2188
2189                 if (bss->rsn_selected)
2190                         bss->rsn_keymgmt = value;
2191                 else
2192                         bss->wpa_keymgmt = value;
2193         } else if (g_strcmp0(key, "Group") == 0) {
2194                 supplicant_dbus_array_foreach(iter, bss_group, &value);
2195
2196                 if (bss->rsn_selected)
2197                         bss->rsn_group = value;
2198                 else
2199                         bss->wpa_group = value;
2200         } else if (g_strcmp0(key, "Pairwise") == 0) {
2201                 supplicant_dbus_array_foreach(iter, bss_pairwise, &value);
2202
2203                 if (bss->rsn_selected)
2204                         bss->rsn_pairwise = value;
2205                 else
2206                         bss->wpa_pairwise = value;
2207         }
2208 }
2209
2210 static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size,
2211                                                         unsigned int type)
2212 {
2213         unsigned int len = 0;
2214
2215         while (len + 4 < ie_size) {
2216                 unsigned int hi = ie[len];
2217                 unsigned int lo = ie[len + 1];
2218                 unsigned int tmp_type = (hi << 8) + lo;
2219                 unsigned int v_len = 0;
2220
2221                 /* hi and lo are used to recreate an unsigned int
2222                  * based on 2 8bits length unsigned int. */
2223
2224                 hi = ie[len + 2];
2225                 lo = ie[len + 3];
2226                 v_len = (hi << 8) + lo;
2227
2228                 if (tmp_type == type) {
2229                         unsigned int ret_value = 0;
2230                         unsigned char *value = (unsigned char *)&ret_value;
2231
2232                         SUPPLICANT_DBG("IE: match type 0x%x", type);
2233
2234                         /* Verifying length relevance */
2235                         if (v_len > sizeof(unsigned int) ||
2236                                 len + 4 + v_len > ie_size)
2237                                 break;
2238
2239                         memcpy(value, ie + len + 4, v_len);
2240
2241                         SUPPLICANT_DBG("returning 0x%x", ret_value);
2242                         return ret_value;
2243                 }
2244
2245                 len += v_len + 4;
2246         }
2247
2248         SUPPLICANT_DBG("returning 0");
2249         return 0;
2250 }
2251
2252 #if defined TIZEN_EXT
2253 static void get_bss_phy_mode(unsigned int max_rate,
2254                 unsigned int max_ext_rate, bool ht, bool vht, void *data)
2255 {
2256         struct g_supplicant_bss *bss = data;
2257         unsigned int freq = bss->frequency;
2258
2259         /* Following conditions are used to determine
2260          * IEEE 802.11 Protocol Modes:-
2261          *
2262          * 1. If “Supported rates” is only till 11 Mbps,
2263          *    and frequency is in 2.4GHz band, then protocol is 11B.
2264          * 2. If “Supported rates” is till 54Mbps or
2265          *    “Extended supported rates” are present,
2266          *    and frequency is in 2.4GHz band, then protocol is 11G.
2267          * 3. If “Supported rates” is only till 54 Mbps,
2268          *    frequency is in 5GHz band , then protocol is 11A.
2269          * 4. If “HT capabilities” is supported , then protocol is 11N.
2270          * 5. If “HT capabilities” & “VHT” is supported and
2271          *    frequency is in 5 GHz band, then protocol is 11AC.
2272          * */
2273
2274         if (freq >= 2412 && freq <= 2484) { /* 2.4 Ghz Band */
2275                 if (max_rate <= 11 && max_ext_rate <= 0 && !ht)
2276                         bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211B;
2277                 else if ((max_rate <= 54 || max_ext_rate > 0) && !ht)
2278                         bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211BG;
2279                 else if ((max_rate >= 54 || max_ext_rate > 0) && ht)
2280                         bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211BGN;
2281                 else
2282                         bss->phy_mode = G_SUPPLICANT_MODE_UNKNOWN;
2283         } else if (freq >= 5180 && freq <= 5825) { /* 5 Ghz Band */
2284                 if (max_rate <= 54 && !ht)
2285                         bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211A;
2286                 else if ((max_rate >= 54 || max_ext_rate > 0) && ht && !vht)
2287                         bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211AN;
2288                 else if ((max_rate >= 54 || max_ext_rate > 0) && ht && vht)
2289                         bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211ANAC;
2290                 else
2291                         bss->phy_mode = G_SUPPLICANT_MODE_UNKNOWN;
2292         }
2293 }
2294 #endif
2295
2296 static void bss_process_ies(DBusMessageIter *iter, void *user_data)
2297 {
2298         struct g_supplicant_bss *bss = user_data;
2299         const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
2300         unsigned char *ie, *ie_end;
2301         DBusMessageIter array;
2302         unsigned int value;
2303         int ie_len;
2304 #if defined TIZEN_EXT
2305         int r_len, j;
2306         unsigned char *rates = NULL;
2307         unsigned char *ext_rates = NULL;
2308         unsigned int max_rate = 0;
2309         unsigned int max_ext_rate = 0;
2310         bool ht = false;
2311         bool vht = false;
2312 #endif
2313
2314 #define WMM_WPA1_WPS_INFO 221
2315 #define WPS_INFO_MIN_LEN  6
2316 #define WPS_VERSION_TLV   0x104A
2317 #define WPS_STATE_TLV     0x1044
2318 #define WPS_METHODS_TLV   0x1012
2319 #define WPS_REGISTRAR_TLV 0x1041
2320 #define WPS_VERSION       0x10
2321 #define WPS_PBC           0x04
2322 #define WPS_PIN           0x00
2323 #define WPS_CONFIGURED    0x02
2324 #if defined TIZEN_EXT
2325 #define VENDOR_SPECIFIC_INFO 0xDD
2326 #define WLAN_EID_COUNTRY 7
2327 #endif
2328
2329         dbus_message_iter_recurse(iter, &array);
2330         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
2331
2332         if (!ie || ie_len < 2)
2333                 return;
2334
2335         bss->wps_capabilities = 0;
2336         bss->keymgmt = 0;
2337         memset(bss->country_code, 0, COUNTRY_CODE_LENGTH);
2338
2339         for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end;
2340                                                         ie += ie[1] + 2) {
2341 #if defined TIZEN_EXT
2342                 unsigned char *vsie;
2343                 int vsie_len = 0;
2344                 if(ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) {
2345                         SUPPLICANT_DBG("IE: match vendor specific data");
2346
2347                         vsie_len = ie[1]+2;     // tag number size(1), tag length size(1)
2348                         vsie = (unsigned char *)g_try_malloc0(vsie_len);
2349
2350                         if (vsie) {
2351                                 memcpy(vsie, ie, vsie_len);
2352                                 bss->vsie_list = g_slist_append(bss->vsie_list, vsie);
2353                         } else
2354                                 SUPPLICANT_DBG("Failed to allocate memory");
2355                         continue;
2356                 }
2357
2358                 if(ie[0] == WLAN_EID_COUNTRY && ie[1] >= 2) {
2359                         /* Add country code only if it is a valid alphabet */
2360                         if (ie[2] >= 65 && ie[2] <= 90 && ie[3] >= 65 && ie[3] <= 90) {
2361                                 memcpy(bss->country_code, ie+2, COUNTRY_CODE_LENGTH);
2362                                 continue;
2363                         }
2364                 }
2365
2366                 if (ie[0] == WLAN_EID_HT_CAP && ie[1]) {
2367                         ht = true;
2368                         continue;
2369                 }
2370
2371                 if (ie[0] == WLAN_EID_VHT_CAP && ie[1]) {
2372                         vht = true;
2373                         continue;
2374                 }
2375
2376                 if (ie[0] == WLAN_EID_SUPP_RATES && ie[1]) {
2377                         r_len = ie[1];
2378                         rates = g_malloc0(r_len);
2379                         if (!rates)
2380                                 continue;
2381
2382                         for (j = 0; ie && j < r_len; j++) {
2383                                 rates[j] = ((ie[j + 2] & 0x7f) * 500000)/1000000;
2384                                 if (max_rate < rates[j])
2385                                         max_rate = rates[j];
2386                         }
2387                         continue;
2388                 }
2389
2390                 if (ie[0] == WLAN_EID_EXT_SUPP_RATES && ie[1] > 0) {
2391                         r_len = ie[1];
2392                         ext_rates = g_malloc0(r_len);
2393                         if (!ext_rates)
2394                                 continue;
2395
2396                         for (j = 0; ie && j < r_len; j++) {
2397                                 ext_rates[j] = ((ie[j + 2] & 0x7f) * 500000)/1000000;
2398                                 if (max_ext_rate < ext_rates[j])
2399                                         max_ext_rate = ext_rates[j];
2400                         }
2401                         continue;
2402                 }
2403 #endif
2404                 if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
2405                         memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
2406                         continue;
2407
2408                 SUPPLICANT_DBG("IE: match WPS_OUI");
2409
2410                 value = get_tlv(&ie[6], ie[1], WPS_STATE_TLV);
2411                 if (get_tlv(&ie[6], ie[1], WPS_VERSION_TLV) == WPS_VERSION &&
2412                                                                 value != 0) {
2413                         bss->keymgmt |= G_SUPPLICANT_KEYMGMT_WPS;
2414
2415                         if (value == WPS_CONFIGURED)
2416                                 bss->wps_capabilities |=
2417                                         G_SUPPLICANT_WPS_CONFIGURED;
2418                 }
2419
2420                 value = get_tlv(&ie[6], ie[1], WPS_METHODS_TLV);
2421                 if (value != 0) {
2422                         if (GUINT16_FROM_BE(value) == WPS_PBC)
2423                                 bss->wps_capabilities |= G_SUPPLICANT_WPS_PBC;
2424                         if (GUINT16_FROM_BE(value) == WPS_PIN)
2425                                 bss->wps_capabilities |= G_SUPPLICANT_WPS_PIN;
2426                 } else
2427                         bss->wps_capabilities |=
2428                                 G_SUPPLICANT_WPS_PBC | G_SUPPLICANT_WPS_PIN;
2429
2430                 /* If the AP sends this it means it's advertizing
2431                  * as a registrar and the WPS process is launched
2432                  * on its side */
2433                 if (get_tlv(&ie[6], ie[1], WPS_REGISTRAR_TLV) != 0)
2434                         bss->wps_capabilities |= G_SUPPLICANT_WPS_REGISTRAR;
2435
2436                 SUPPLICANT_DBG("WPS Methods 0x%x", bss->wps_capabilities);
2437         }
2438 #ifdef TIZEN_EXT
2439         get_bss_phy_mode(max_rate, max_ext_rate, ht, vht, user_data);
2440         if (rates)
2441                 g_free(rates);
2442         if (ext_rates)
2443                 g_free(ext_rates);
2444 #endif
2445 }
2446
2447 static void bss_compute_security(struct g_supplicant_bss *bss)
2448 {
2449         /*
2450          * Combining RSN and WPA keymgmt
2451          * We combine it since parsing IEs might have set something for WPS. */
2452         bss->keymgmt |= bss->rsn_keymgmt | bss->wpa_keymgmt;
2453
2454         bss->ieee8021x = FALSE;
2455         bss->psk = FALSE;
2456 #if defined TIZEN_EXT
2457         bss->ft_ieee8021x = FALSE;
2458         bss->ft_psk = FALSE;
2459 #endif
2460
2461 #if defined TIZEN_EXT
2462         if (bss->keymgmt &
2463                         (G_SUPPLICANT_KEYMGMT_WPA_EAP |
2464                                         G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
2465                 bss->ieee8021x = TRUE;
2466         else if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_EAP)
2467                 bss->ft_ieee8021x = TRUE;
2468 #else
2469         if (bss->keymgmt &
2470                         (G_SUPPLICANT_KEYMGMT_WPA_EAP |
2471                                 G_SUPPLICANT_KEYMGMT_WPA_FT_EAP |
2472                                 G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
2473                 bss->ieee8021x = TRUE;
2474 #endif
2475
2476 #if defined TIZEN_EXT
2477         if (bss->keymgmt &
2478                         (G_SUPPLICANT_KEYMGMT_WPA_PSK |
2479                                         G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
2480                 bss->psk = TRUE;
2481         else if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_PSK)
2482                 bss->ft_psk = TRUE;
2483 #else
2484         if (bss->keymgmt &
2485                         (G_SUPPLICANT_KEYMGMT_WPA_PSK |
2486                                 G_SUPPLICANT_KEYMGMT_WPA_FT_PSK |
2487                                 G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
2488                 bss->psk = TRUE;
2489 #endif
2490
2491 #if defined TIZEN_EXT_WIFI_MESH
2492         if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_SAE)
2493                 bss->sae = TRUE;
2494 #endif
2495
2496         if (bss->ieee8021x)
2497                 bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
2498         else if (bss->psk)
2499                 bss->security = G_SUPPLICANT_SECURITY_PSK;
2500 #if defined TIZEN_EXT
2501         else if (bss->ft_psk)
2502                 bss->security = G_SUPPLICANT_SECURITY_FT_PSK;
2503         else if (bss->ft_ieee8021x == TRUE)
2504                 bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
2505 #endif
2506 #if defined TIZEN_EXT_WIFI_MESH
2507         else if (bss->sae)
2508                 bss->security = G_SUPPLICANT_SECURITY_SAE;
2509 #endif
2510         else if (bss->privacy)
2511                 bss->security = G_SUPPLICANT_SECURITY_WEP;
2512         else
2513                 bss->security = G_SUPPLICANT_SECURITY_NONE;
2514 }
2515
2516
2517 static void bss_property(const char *key, DBusMessageIter *iter,
2518                                                         void *user_data)
2519 {
2520         struct g_supplicant_bss *bss = user_data;
2521
2522         if (!bss->interface)
2523                 return;
2524
2525         SUPPLICANT_DBG("key %s", key);
2526
2527         if (!key)
2528                 return;
2529
2530         if (g_strcmp0(key, "BSSID") == 0) {
2531                 DBusMessageIter array;
2532                 unsigned char *addr;
2533                 int addr_len;
2534
2535                 dbus_message_iter_recurse(iter, &array);
2536                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
2537
2538                 if (addr_len == 6)
2539                         memcpy(bss->bssid, addr, addr_len);
2540         } else if (g_strcmp0(key, "SSID") == 0) {
2541                 DBusMessageIter array;
2542                 unsigned char *ssid;
2543                 int ssid_len;
2544
2545                 dbus_message_iter_recurse(iter, &array);
2546                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
2547
2548                 if (ssid_len > 0 && ssid_len < 33) {
2549                         memcpy(bss->ssid, ssid, ssid_len);
2550                         bss->ssid_len = ssid_len;
2551                 } else {
2552                         memset(bss->ssid, 0, sizeof(bss->ssid));
2553                         bss->ssid_len = 0;
2554                 }
2555         } else if (g_strcmp0(key, "Capabilities") == 0) {
2556                 dbus_uint16_t capabilities = 0x0000;
2557
2558                 dbus_message_iter_get_basic(iter, &capabilities);
2559
2560                 if (capabilities & IEEE80211_CAP_ESS)
2561                         bss->mode = G_SUPPLICANT_MODE_INFRA;
2562                 else if (capabilities & IEEE80211_CAP_IBSS)
2563                         bss->mode = G_SUPPLICANT_MODE_IBSS;
2564
2565                 if (capabilities & IEEE80211_CAP_PRIVACY)
2566                         bss->privacy = TRUE;
2567         } else if (g_strcmp0(key, "Mode") == 0) {
2568                 const char *mode = NULL;
2569
2570                 dbus_message_iter_get_basic(iter, &mode);
2571                 bss->mode = string2mode(mode);
2572         } else if (g_strcmp0(key, "Frequency") == 0) {
2573                 dbus_uint16_t frequency = 0;
2574
2575                 dbus_message_iter_get_basic(iter, &frequency);
2576                 bss->frequency = frequency;
2577         } else if (g_strcmp0(key, "Signal") == 0) {
2578                 dbus_int16_t signal = 0;
2579
2580                 dbus_message_iter_get_basic(iter, &signal);
2581
2582                 bss->signal = signal;
2583                 if (!bss->signal)
2584                         bss->signal = BSS_UNKNOWN_STRENGTH;
2585
2586         } else if (g_strcmp0(key, "Level") == 0) {
2587                 dbus_int32_t level = 0;
2588
2589                 dbus_message_iter_get_basic(iter, &level);
2590         } else if (g_strcmp0(key, "Rates") == 0) {
2591                 supplicant_dbus_array_foreach(iter, bss_rates, bss);
2592         } else if (g_strcmp0(key, "MaxRate") == 0) {
2593                 dbus_uint32_t maxrate = 0;
2594
2595                 dbus_message_iter_get_basic(iter, &maxrate);
2596                 if (maxrate != 0)
2597                         bss->maxrate = maxrate;
2598         } else if (g_strcmp0(key, "Privacy") == 0) {
2599                 dbus_bool_t privacy = FALSE;
2600
2601                 dbus_message_iter_get_basic(iter, &privacy);
2602                 bss->privacy = privacy;
2603         } else if (g_strcmp0(key, "RSN") == 0) {
2604                 bss->rsn_selected = TRUE;
2605
2606                 supplicant_dbus_property_foreach(iter, bss_wpa, bss);
2607         } else if (g_strcmp0(key, "WPA") == 0) {
2608                 bss->rsn_selected = FALSE;
2609
2610                 supplicant_dbus_property_foreach(iter, bss_wpa, bss);
2611 #if defined TIZEN_EXT
2612         } else if (g_strcmp0(key, "HS20") == 0) {
2613                 dbus_bool_t hs20 = FALSE;
2614                 dbus_message_iter_get_basic(iter, &hs20);
2615                 bss->hs20 = hs20;
2616 #endif
2617         } else if (g_strcmp0(key, "IEs") == 0)
2618                 bss_process_ies(iter, bss);
2619         else
2620                 SUPPLICANT_DBG("key %s type %c",
2621                                 key, dbus_message_iter_get_arg_type(iter));
2622 }
2623
2624 static struct g_supplicant_bss *interface_bss_added(DBusMessageIter *iter,
2625                                                         void *user_data)
2626 {
2627         GSupplicantInterface *interface = user_data;
2628         GSupplicantNetwork *network;
2629         struct g_supplicant_bss *bss;
2630         const char *path = NULL;
2631
2632         SUPPLICANT_DBG("");
2633
2634         dbus_message_iter_get_basic(iter, &path);
2635         if (!path)
2636                 return NULL;
2637
2638         if (g_strcmp0(path, "/") == 0)
2639                 return NULL;
2640
2641         SUPPLICANT_DBG("%s", path);
2642
2643         network = g_hash_table_lookup(interface->bss_mapping, path);
2644         if (network) {
2645                 bss = g_hash_table_lookup(network->bss_table, path);
2646                 if (bss)
2647                         return NULL;
2648         }
2649
2650         bss = g_try_new0(struct g_supplicant_bss, 1);
2651         if (!bss)
2652                 return NULL;
2653
2654         bss->interface = interface;
2655         bss->path = g_strdup(path);
2656         bss->signal = BSS_UNKNOWN_STRENGTH;
2657
2658         return bss;
2659 }
2660
2661 static void interface_bss_added_with_keys(DBusMessageIter *iter,
2662                                                 void *user_data)
2663 {
2664         struct g_supplicant_bss *bss;
2665
2666         SUPPLICANT_DBG("");
2667
2668         bss = interface_bss_added(iter, user_data);
2669         if (!bss)
2670                 return;
2671
2672         dbus_message_iter_next(iter);
2673
2674         if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID)
2675                 return;
2676
2677         supplicant_dbus_property_foreach(iter, bss_property, bss);
2678
2679         bss_compute_security(bss);
2680         if (add_or_replace_bss_to_network(bss) < 0)
2681                 SUPPLICANT_DBG("add_or_replace_bss_to_network failed");
2682 }
2683
2684 static void interface_bss_added_without_keys(DBusMessageIter *iter,
2685                                                 void *user_data)
2686 {
2687         struct g_supplicant_bss *bss;
2688
2689         SUPPLICANT_DBG("");
2690
2691         bss = interface_bss_added(iter, user_data);
2692         if (!bss)
2693                 return;
2694
2695         supplicant_dbus_property_get_all(bss->path,
2696                                         SUPPLICANT_INTERFACE ".BSS",
2697                                         bss_property, bss, NULL);
2698
2699         bss_compute_security(bss);
2700         if (add_or_replace_bss_to_network(bss) < 0)
2701                         SUPPLICANT_DBG("add_or_replace_bss_to_network failed");
2702 }
2703
2704 static void update_signal(gpointer key, gpointer value,
2705                                                 gpointer user_data)
2706 {
2707         struct g_supplicant_bss *bss = value;
2708         GSupplicantNetwork *network = user_data;
2709
2710         if (bss->signal > network->signal) {
2711                 network->signal = bss->signal;
2712                 network->best_bss = bss;
2713         }
2714 }
2715
2716 static void update_network_signal(GSupplicantNetwork *network)
2717 {
2718         if (g_hash_table_size(network->bss_table) <= 1 && network->best_bss)
2719                 return;
2720
2721         g_hash_table_foreach(network->bss_table,
2722                                 update_signal, network);
2723
2724         SUPPLICANT_DBG("New network signal %d", network->signal);
2725 }
2726
2727 static void interface_current_bss(GSupplicantInterface *interface,
2728                                                 DBusMessageIter *iter)
2729 {
2730         GSupplicantNetwork *network;
2731         struct g_supplicant_bss *bss;
2732         const char *path;
2733
2734         dbus_message_iter_get_basic(iter, &path);
2735         if (g_strcmp0(path, "/") == 0) {
2736                 interface->current_network = NULL;
2737                 return;
2738         }
2739
2740         interface_bss_added_without_keys(iter, interface);
2741
2742         network = g_hash_table_lookup(interface->bss_mapping, path);
2743         if (!network)
2744                 return;
2745
2746         bss = g_hash_table_lookup(network->bss_table, path);
2747         if (!bss)
2748                 return;
2749
2750         interface->current_network = network;
2751
2752         if (bss != network->best_bss) {
2753                 /*
2754                  * This is the case where either wpa_s got associated
2755                  * to a BSS different than the one ConnMan considers
2756                  * the best, or we are roaming.
2757                  */
2758                 SUPPLICANT_DBG("Update best BSS for %s", network->name);
2759
2760                 network->best_bss = bss;
2761
2762                 if (network->signal != bss->signal) {
2763                         SUPPLICANT_DBG("New network signal %d dBm",
2764                                                 bss->signal);
2765
2766                         network->signal = bss->signal;
2767                         callback_network_changed(network, "Signal");
2768                 }
2769         }
2770
2771         /*
2772          * wpa_s could notify about CurrentBSS in any state once
2773          * it got associated. It is not sure such notification will
2774          * arrive together with transition to ASSOCIATED state.
2775          * In fact, for networks with security WEP or OPEN, it
2776          * always arrives together with transition to COMPLETED.
2777          */
2778         switch (interface->state) {
2779         case G_SUPPLICANT_STATE_UNKNOWN:
2780         case G_SUPPLICANT_STATE_DISABLED:
2781         case G_SUPPLICANT_STATE_DISCONNECTED:
2782         case G_SUPPLICANT_STATE_INACTIVE:
2783         case G_SUPPLICANT_STATE_SCANNING:
2784         case G_SUPPLICANT_STATE_AUTHENTICATING:
2785         case G_SUPPLICANT_STATE_ASSOCIATING:
2786                 return;
2787         case G_SUPPLICANT_STATE_ASSOCIATED:
2788         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2789         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2790         case G_SUPPLICANT_STATE_COMPLETED:
2791                 callback_network_associated(network);
2792                 break;
2793         }
2794 }
2795
2796 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
2797 {
2798         GSupplicantInterface *interface = user_data;
2799         GSupplicantNetwork *network;
2800         struct g_supplicant_bss *bss = NULL;
2801         const char *path = NULL;
2802         bool is_current_network_bss = false;
2803
2804         dbus_message_iter_get_basic(iter, &path);
2805         if (!path)
2806                 return;
2807
2808         network = g_hash_table_lookup(interface->bss_mapping, path);
2809         if (!network)
2810                 return;
2811
2812         bss = g_hash_table_lookup(network->bss_table, path);
2813         if (network->best_bss == bss) {
2814                 network->best_bss = NULL;
2815                 network->signal = BSS_UNKNOWN_STRENGTH;
2816                 is_current_network_bss = true;
2817         }
2818
2819         g_hash_table_remove(bss_mapping, path);
2820
2821         g_hash_table_remove(interface->bss_mapping, path);
2822         g_hash_table_remove(network->bss_table, path);
2823
2824         update_network_signal(network);
2825
2826         if (g_hash_table_size(network->bss_table) == 0) {
2827                 g_hash_table_remove(interface->network_table, network->group);
2828         } else {
2829                 if (is_current_network_bss && network->best_bss)
2830 #if defined TIZEN_EXT
2831                         callback_network_changed(network, "CheckMultiBssidConnect");
2832 #else
2833                         callback_network_changed(network, "");
2834 #endif
2835         }
2836 }
2837
2838 static void set_config_methods(DBusMessageIter *iter, void *user_data)
2839 {
2840         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, user_data);
2841 }
2842
2843 static void wps_property(const char *key, DBusMessageIter *iter,
2844                                                         void *user_data)
2845 {
2846         GSupplicantInterface *interface = user_data;
2847
2848         if (!interface)
2849                 return;
2850
2851         SUPPLICANT_DBG("key: %s", key);
2852
2853         if (g_strcmp0(key, "ConfigMethods") == 0) {
2854                 const char *config_methods = "push_button", *str = NULL;
2855
2856                 dbus_message_iter_get_basic(iter, &str);
2857                 if (str && strlen(str) > 0) {
2858                         /* It was already set at wpa_s level, don't modify it. */
2859                         SUPPLICANT_DBG("%s", str);
2860                         return;
2861                 }
2862
2863                 supplicant_dbus_property_set(interface->path,
2864                         SUPPLICANT_INTERFACE ".Interface.WPS",
2865                         "ConfigMethods", DBUS_TYPE_STRING_AS_STRING,
2866                         set_config_methods, NULL, &config_methods, NULL);
2867
2868                 SUPPLICANT_DBG("No value. Set %s", config_methods);
2869         }
2870
2871 }
2872
2873 static void interface_property(const char *key, DBusMessageIter *iter,
2874                                                         void *user_data)
2875 {
2876         GSupplicantInterface *interface = user_data;
2877
2878         if (!interface)
2879                 return;
2880
2881         SUPPLICANT_DBG("%s", key);
2882
2883         if (!key) {
2884                 debug_strvalmap("KeyMgmt capability", keymgmt_map,
2885                                                 interface->keymgmt_capa);
2886                 debug_strvalmap("AuthAlg capability", authalg_capa_map,
2887                                                 interface->authalg_capa);
2888                 debug_strvalmap("Protocol capability", proto_capa_map,
2889                                                 interface->proto_capa);
2890                 debug_strvalmap("Pairwise capability", pairwise_map,
2891                                                 interface->pairwise_capa);
2892                 debug_strvalmap("Group capability", group_map,
2893                                                 interface->group_capa);
2894                 debug_strvalmap("Scan capability", scan_capa_map,
2895                                                 interface->scan_capa);
2896                 debug_strvalmap("Mode capability", mode_capa_map,
2897                                                 interface->mode_capa);
2898
2899                 supplicant_dbus_property_get_all(interface->path,
2900                                 SUPPLICANT_INTERFACE ".Interface.WPS",
2901                                 wps_property, interface, interface);
2902
2903                 if (interface->ready)
2904                         callback_interface_added(interface);
2905
2906                 return;
2907         }
2908
2909         if (g_strcmp0(key, "Capabilities") == 0) {
2910                 supplicant_dbus_property_foreach(iter, interface_capability,
2911                                                                 interface);
2912 #if !defined TIZEN_EXT
2913                 if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_P2P)
2914                         interface->p2p_support = true;
2915 #endif
2916 #if defined TIZEN_EXT_WIFI_MESH
2917                 if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_MESH)
2918                         interface->mesh_support = true;
2919 #endif
2920         } else if (g_strcmp0(key, "State") == 0) {
2921                 const char *str = NULL;
2922
2923                 dbus_message_iter_get_basic(iter, &str);
2924                 if (str)
2925                         if (string2state(str) != interface->state) {
2926                                 interface->state = string2state(str);
2927                                 callback_interface_state(interface);
2928                         }
2929
2930                 if (interface->ap_create_in_progress) {
2931                         if (interface->state == G_SUPPLICANT_STATE_DISCONNECTED)
2932                                 callback_ap_create_fail(interface);
2933
2934                         interface->ap_create_in_progress = false;
2935                 }
2936
2937                 if (interface->state == G_SUPPLICANT_STATE_DISABLED)
2938                         interface->ready = FALSE;
2939                 else
2940                         interface->ready = TRUE;
2941
2942                 SUPPLICANT_DBG("state %s (%d)", str, interface->state);
2943         } else if (g_strcmp0(key, "Scanning") == 0) {
2944                 dbus_bool_t scanning = FALSE;
2945
2946                 dbus_message_iter_get_basic(iter, &scanning);
2947                 interface->scanning = scanning;
2948
2949                 if (interface->ready) {
2950                         if (interface->scanning)
2951                                 callback_scan_started(interface);
2952                         else
2953                                 callback_scan_finished(interface);
2954                 }
2955         } else if (g_strcmp0(key, "ApScan") == 0) {
2956                 int apscan = 1;
2957
2958                 dbus_message_iter_get_basic(iter, &apscan);
2959                 interface->apscan = apscan;
2960         } else if (g_strcmp0(key, "Ifname") == 0) {
2961                 const char *str = NULL;
2962
2963                 dbus_message_iter_get_basic(iter, &str);
2964                 if (str) {
2965                         g_free(interface->ifname);
2966                         interface->ifname = g_strdup(str);
2967                 }
2968         } else if (g_strcmp0(key, "Driver") == 0) {
2969                 const char *str = NULL;
2970
2971                 dbus_message_iter_get_basic(iter, &str);
2972                 if (str) {
2973                         g_free(interface->driver);
2974                         interface->driver = g_strdup(str);
2975                 }
2976         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
2977                 const char *str = NULL;
2978
2979                 dbus_message_iter_get_basic(iter, &str);
2980                 if (str) {
2981                         g_free(interface->bridge);
2982                         interface->bridge = g_strdup(str);
2983                 }
2984         } else if (g_strcmp0(key, "ConfigFile") == 0) {
2985                 const char *str = NULL;
2986
2987                 dbus_message_iter_get_basic(iter, &str);
2988                 if (str && strlen(str) > 0 && interface->ifname) {
2989                         SUPPLICANT_DBG("New {%s, %s}", interface->ifname, str);
2990                         g_hash_table_replace(config_file_table,
2991                                 g_strdup(interface->ifname), g_strdup(str));
2992                 }
2993         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
2994                 interface_current_bss(interface, iter);
2995         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
2996 #if defined TIZEN_EXT
2997                 if (interface->state != G_SUPPLICANT_STATE_COMPLETED)
2998 #endif
2999                 interface_network_added(iter, interface);
3000         } else if (g_strcmp0(key, "BSSs") == 0) {
3001                 supplicant_dbus_array_foreach(iter,
3002                                         interface_bss_added_without_keys,
3003                                         interface);
3004         } else if (g_strcmp0(key, "Blobs") == 0) {
3005                 /* Nothing */
3006         } else if (g_strcmp0(key, "Networks") == 0) {
3007                 supplicant_dbus_array_foreach(iter, interface_network_added,
3008                                                                 interface);
3009         } else if (g_strcmp0(key, "DisconnectReason") == 0) {
3010                 int reason_code;
3011                 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
3012                         dbus_message_iter_get_basic(iter, &reason_code);
3013                         callback_disconnect_reason_code(interface, reason_code);
3014                 }
3015         } else if (g_strcmp0(key, "AssocStatusCode") == 0) {
3016                 int status_code;
3017                 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
3018                         dbus_message_iter_get_basic(iter, &status_code);
3019                         callback_assoc_status_code(interface, status_code);
3020                 }
3021         } else {
3022                 SUPPLICANT_DBG("key %s type %c",
3023                                 key, dbus_message_iter_get_arg_type(iter));
3024         }
3025 }
3026
3027 static void scan_network_update(DBusMessageIter *iter, void *user_data)
3028 {
3029         GSupplicantInterface *interface = user_data;
3030         GSupplicantNetwork *network;
3031         char *path;
3032
3033         if (!iter)
3034                 return;
3035
3036         dbus_message_iter_get_basic(iter, &path);
3037
3038         if (!path)
3039                 return;
3040
3041         if (g_strcmp0(path, "/") == 0)
3042                 return;
3043
3044         /* Update the network details based on scan BSS data */
3045         network = g_hash_table_lookup(interface->bss_mapping, path);
3046         if (network)
3047                 callback_network_added(network);
3048 }
3049
3050 static void scan_bss_data(const char *key, DBusMessageIter *iter,
3051                                 void *user_data)
3052 {
3053         GSupplicantInterface *interface = user_data;
3054
3055 /*Fixed : stucking in scanning state when scan failed*/
3056 #if defined TIZEN_EXT
3057                 GSupplicantInterfaceCallback scan_callback;
3058 #endif
3059
3060         if (iter)
3061                 supplicant_dbus_array_foreach(iter, scan_network_update,
3062                                                 interface);
3063
3064 #if defined TIZEN_EXT
3065                 scan_callback = interface->scan_callback;
3066 #endif
3067
3068         if (interface->scan_callback)
3069                 interface->scan_callback(0, interface, interface->scan_data);
3070
3071 #if defined TIZEN_EXT
3072                 if (interface->scan_callback == scan_callback) {
3073 #endif
3074         interface->scan_callback = NULL;
3075         interface->scan_data = NULL;
3076 #if defined TIZEN_EXT
3077         }
3078 #endif
3079 }
3080
3081 static GSupplicantInterface *interface_alloc(const char *path)
3082 {
3083         GSupplicantInterface *interface;
3084
3085         interface = g_try_new0(GSupplicantInterface, 1);
3086         if (!interface)
3087                 return NULL;
3088
3089         interface->path = g_strdup(path);
3090
3091         interface->network_table = g_hash_table_new_full(g_str_hash,
3092                                         g_str_equal, NULL, remove_network);
3093         interface->peer_table = g_hash_table_new_full(g_str_hash,
3094                                         g_str_equal, NULL, remove_peer);
3095         interface->group_table = g_hash_table_new_full(g_str_hash,
3096                                         g_str_equal, NULL, remove_group);
3097         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
3098                                                                 NULL, NULL);
3099
3100         g_hash_table_replace(interface_table, interface->path, interface);
3101
3102         return interface;
3103 }
3104
3105 static void interface_added(DBusMessageIter *iter, void *user_data)
3106 {
3107         GSupplicantInterface *interface;
3108         const char *path = NULL;
3109         bool properties_appended = GPOINTER_TO_UINT(user_data);
3110
3111         SUPPLICANT_DBG("");
3112
3113         dbus_message_iter_get_basic(iter, &path);
3114         if (!path)
3115                 return;
3116
3117         if (g_strcmp0(path, "/") == 0)
3118                 return;
3119
3120         interface = g_hash_table_lookup(interface_table, path);
3121         if (interface)
3122                 return;
3123
3124         interface = interface_alloc(path);
3125         if (!interface)
3126                 return;
3127
3128         if (!properties_appended) {
3129                 supplicant_dbus_property_get_all(path,
3130                                                 SUPPLICANT_INTERFACE ".Interface",
3131                                                 interface_property, interface,
3132                                                 interface);
3133                 return;
3134         }
3135
3136         dbus_message_iter_next(iter);
3137         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
3138                 supplicant_dbus_property_foreach(iter, interface_property,
3139                                                                 interface);
3140                 interface_property(NULL, NULL, interface);
3141         }
3142 }
3143
3144 static void interface_removed(DBusMessageIter *iter, void *user_data)
3145 {
3146         const char *path = NULL;
3147         GSupplicantInterface *interface = user_data;
3148
3149         dbus_message_iter_get_basic(iter, &path);
3150         if (!path)
3151                 return;
3152
3153         interface = g_hash_table_lookup(interface_table, path);
3154         g_supplicant_interface_cancel(interface);
3155
3156         g_hash_table_remove(interface_table, path);
3157 }
3158
3159 static void eap_method(DBusMessageIter *iter, void *user_data)
3160 {
3161         const char *str = NULL;
3162         int i;
3163
3164         dbus_message_iter_get_basic(iter, &str);
3165         if (!str)
3166                 return;
3167
3168         for (i = 0; eap_method_map[i].str; i++)
3169                 if (strcmp(str, eap_method_map[i].str) == 0) {
3170                         eap_methods |= eap_method_map[i].val;
3171                         break;
3172                 }
3173 }
3174
3175 static void service_property(const char *key, DBusMessageIter *iter,
3176                                                         void *user_data)
3177 {
3178         if (!key) {
3179                 callback_system_ready();
3180                 return;
3181         }
3182
3183         if (g_strcmp0(key, "DebugLevel") == 0) {
3184                 const char *str = NULL;
3185                 int i;
3186
3187                 dbus_message_iter_get_basic(iter, &str);
3188                 for (i = 0; debug_strings[i]; i++)
3189                         if (g_strcmp0(debug_strings[i], str) == 0) {
3190                                 debug_level = i;
3191                                 break;
3192                         }
3193                 SUPPLICANT_DBG("Debug level %d", debug_level);
3194         } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
3195                 dbus_message_iter_get_basic(iter, &debug_timestamp);
3196                 SUPPLICANT_DBG("Debug timestamp %u", debug_timestamp);
3197         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
3198                 dbus_message_iter_get_basic(iter, &debug_showkeys);
3199                 SUPPLICANT_DBG("Debug show keys %u", debug_showkeys);
3200         } else if (g_strcmp0(key, "Interfaces") == 0) {
3201                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
3202         } else if (g_strcmp0(key, "EapMethods") == 0) {
3203                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
3204                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
3205         } else if (g_strcmp0(key, "Country") == 0) {
3206                 const char *country = NULL;
3207
3208                 dbus_message_iter_get_basic(iter, &country);
3209                 SUPPLICANT_DBG("Country %s", country);
3210         } else
3211                 SUPPLICANT_DBG("key %s type %c",
3212                                 key, dbus_message_iter_get_arg_type(iter));
3213 }
3214
3215 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
3216 {
3217         const char *name = NULL, *old = NULL, *new = NULL;
3218
3219         SUPPLICANT_DBG("");
3220
3221         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
3222                 return;
3223
3224         dbus_message_iter_get_basic(iter, &name);
3225         if (!name)
3226                 return;
3227
3228         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
3229                 return;
3230
3231         dbus_message_iter_next(iter);
3232         dbus_message_iter_get_basic(iter, &old);
3233         dbus_message_iter_next(iter);
3234         dbus_message_iter_get_basic(iter, &new);
3235
3236         if (!old || !new)
3237                 return;
3238
3239         if (strlen(old) > 0 && strlen(new) == 0) {
3240                 system_available = FALSE;
3241                 g_hash_table_remove_all(bss_mapping);
3242                 g_hash_table_remove_all(peer_mapping);
3243                 g_hash_table_remove_all(group_mapping);
3244                 g_hash_table_remove_all(config_file_table);
3245                 g_hash_table_remove_all(interface_table);
3246                 callback_system_killed();
3247         }
3248
3249         if (strlen(new) > 0 && strlen(old) == 0) {
3250                 system_available = TRUE;
3251                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
3252                                                 SUPPLICANT_INTERFACE,
3253                                                 service_property, NULL, NULL);
3254         }
3255 }
3256
3257 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
3258 {
3259         SUPPLICANT_DBG("");
3260
3261         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
3262                 return;
3263
3264         supplicant_dbus_property_foreach(iter, service_property, NULL);
3265 }
3266
3267 static void signal_interface_added(const char *path, DBusMessageIter *iter)
3268 {
3269         SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
3270
3271         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
3272                 interface_added(iter, GUINT_TO_POINTER(true));
3273 }
3274
3275 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
3276 {
3277         SUPPLICANT_DBG("");
3278
3279         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
3280                 interface_removed(iter, NULL);
3281 }
3282
3283 static void signal_interface_changed(const char *path, DBusMessageIter *iter)
3284 {
3285         GSupplicantInterface *interface;
3286
3287         SUPPLICANT_DBG("");
3288
3289         interface = g_hash_table_lookup(interface_table, path);
3290         if (!interface)
3291                 return;
3292
3293         supplicant_dbus_property_foreach(iter, interface_property, interface);
3294 }
3295
3296 static void signal_scan_done(const char *path, DBusMessageIter *iter)
3297 {
3298         GSupplicantInterface *interface;
3299         dbus_bool_t success = FALSE;
3300
3301         SUPPLICANT_DBG("");
3302
3303         interface = g_hash_table_lookup(interface_table, path);
3304         if (!interface)
3305                 return;
3306
3307         dbus_message_iter_get_basic(iter, &success);
3308
3309         if (interface->scanning) {
3310                 callback_scan_finished(interface);
3311                 interface->scanning = FALSE;
3312         }
3313
3314         /*
3315          * If scan is unsuccessful return -EIO else get the scanned BSSs
3316          * and update the network details accordingly
3317          */
3318         if (!success) {
3319                 if (interface->scan_callback)
3320                         interface->scan_callback(-EIO, interface,
3321                                                 interface->scan_data);
3322
3323                 interface->scan_callback = NULL;
3324                 interface->scan_data = NULL;
3325
3326                 return;
3327         }
3328
3329         supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface",
3330                                 "BSSs", scan_bss_data, interface, interface);
3331 }
3332
3333 static void signal_bss_added(const char *path, DBusMessageIter *iter)
3334 {
3335         GSupplicantInterface *interface;
3336
3337         SUPPLICANT_DBG("");
3338
3339         interface = g_hash_table_lookup(interface_table, path);
3340         if (!interface)
3341                 return;
3342
3343         interface_bss_added_with_keys(iter, interface);
3344 }
3345
3346 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
3347 {
3348         GSupplicantInterface *interface;
3349
3350         SUPPLICANT_DBG("");
3351
3352         interface = g_hash_table_lookup(interface_table, path);
3353         if (!interface)
3354                 return;
3355
3356         interface_bss_removed(iter, interface);
3357 }
3358
3359 static void signal_network_added(const char *path, DBusMessageIter *iter)
3360 {
3361         GSupplicantInterface *interface;
3362
3363         SUPPLICANT_DBG("");
3364
3365         interface = g_hash_table_lookup(interface_table, path);
3366         if (!interface)
3367                 return;
3368
3369         interface_network_added(iter, interface);
3370 }
3371
3372 static void signal_network_removed(const char *path, DBusMessageIter *iter)
3373 {
3374         GSupplicantInterface *interface;
3375
3376         SUPPLICANT_DBG("");
3377
3378         interface = g_hash_table_lookup(interface_table, path);
3379         if (!interface)
3380                 return;
3381
3382         interface_network_removed(iter, interface);
3383 }
3384 #if defined TIZEN_EXT
3385 void *copy_vsie_list(gconstpointer src, gpointer data)
3386 {
3387         return g_strdup(src);
3388 }
3389 #endif
3390
3391
3392 static void signal_bss_changed(const char *path, DBusMessageIter *iter)
3393 {
3394         GSupplicantInterface *interface;
3395         GSupplicantNetwork *network;
3396         GSupplicantSecurity old_security;
3397         struct g_supplicant_bss *bss;
3398
3399         SUPPLICANT_DBG("");
3400
3401         interface = g_hash_table_lookup(bss_mapping, path);
3402         if (!interface)
3403                 return;
3404
3405         network = g_hash_table_lookup(interface->bss_mapping, path);
3406         if (!network)
3407                 return;
3408
3409         bss = g_hash_table_lookup(network->bss_table, path);
3410         if (!bss)
3411                 return;
3412
3413         supplicant_dbus_property_foreach(iter, bss_property, bss);
3414 #if defined TIZEN_EXT
3415         network->frequency = bss->frequency;
3416         network->phy_mode = bss->phy_mode;
3417 #endif
3418         old_security = network->security;
3419         bss_compute_security(bss);
3420
3421         if (old_security != bss->security) {
3422                 struct g_supplicant_bss *new_bss;
3423
3424                 SUPPLICANT_DBG("New network security for %s", bss->ssid);
3425
3426                 /* Security change policy:
3427                  * - we first copy the current bss into a new one with
3428                  * its own pointer (path)
3429                  * - we remove the current bss related network which will
3430                  * tell the plugin about such removal. This is done due
3431                  * to the fact that a security change means a group change
3432                  * so a complete network change.
3433                  * (current bss becomes invalid as well)
3434                  * - we add the new bss: it adds new network and tell the
3435                  * plugin about it. */
3436
3437                 new_bss = g_try_new0(struct g_supplicant_bss, 1);
3438                 if (!new_bss)
3439                         return;
3440
3441                 memcpy(new_bss, bss, sizeof(struct g_supplicant_bss));
3442                 new_bss->path = g_strdup(bss->path);
3443 #if defined TIZEN_EXT
3444                 new_bss->vsie_list = g_slist_copy_deep(bss->vsie_list, copy_vsie_list, NULL);
3445 #endif
3446
3447                 g_hash_table_remove(interface->network_table, network->group);
3448
3449                 if (add_or_replace_bss_to_network(new_bss) < 0) {
3450                         /* Remove entries in hash tables to handle the
3451                          * failure in add_or_replace_bss_to_network
3452                          */
3453                         g_hash_table_remove(bss_mapping, path);
3454                         g_hash_table_remove(interface->bss_mapping, path);
3455                         g_hash_table_remove(network->bss_table, path);
3456                 }
3457
3458                 return;
3459         }
3460
3461 #if defined TIZEN_EXT
3462         if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) {
3463                 network->wps = TRUE;
3464                 network->wps_capabilities |= bss->wps_capabilities;
3465         } else
3466                 network->wps = FALSE;
3467 #endif
3468
3469         /* Consider only property changes of the connected BSS */
3470         if (network == interface->current_network && bss != network->best_bss)
3471                 return;
3472
3473         if (bss->signal == network->signal)
3474 #ifndef TIZEN_EXT
3475                 return;
3476 #else
3477         {
3478                 callback_network_changed(network, "");
3479                 return;
3480         }
3481 #endif
3482
3483         /*
3484          * If the new signal is lower than the SSID signal, we need
3485          * to check for the new maximum.
3486          */
3487         if (bss->signal < network->signal) {
3488                 if (bss != network->best_bss)
3489 #ifndef TIZEN_EXT
3490                         return;
3491 #else
3492                 {
3493                         callback_network_changed(network, "");
3494                         return;
3495                 }
3496 #endif
3497                 network->signal = bss->signal;
3498                 update_network_signal(network);
3499         } else {
3500                 network->signal = bss->signal;
3501                 network->best_bss = bss;
3502         }
3503
3504         SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid,
3505                         network->signal);
3506
3507         callback_network_changed(network, "Signal");
3508 }
3509
3510 static void wps_credentials(const char *key, DBusMessageIter *iter,
3511                         void *user_data)
3512 {
3513         GSupplicantInterface *interface = user_data;
3514
3515         if (!key)
3516                 return;
3517
3518         SUPPLICANT_DBG("key %s", key);
3519
3520         if (g_strcmp0(key, "Key") == 0) {
3521                 DBusMessageIter array;
3522                 unsigned char *key_val;
3523                 int key_len;
3524
3525                 dbus_message_iter_recurse(iter, &array);
3526                 dbus_message_iter_get_fixed_array(&array, &key_val, &key_len);
3527
3528                 g_free(interface->wps_cred.key);
3529                 interface->wps_cred.key = g_try_malloc0(
3530                                                 sizeof(char) * key_len + 1);
3531
3532                 if (!interface->wps_cred.key)
3533                         return;
3534
3535                 memcpy(interface->wps_cred.key, key_val,
3536                                                 sizeof(char) * key_len);
3537
3538                 SUPPLICANT_DBG("WPS key present");
3539         } else if (g_strcmp0(key, "SSID") == 0) {
3540                 DBusMessageIter array;
3541                 unsigned char *ssid;
3542                 int ssid_len;
3543
3544                 dbus_message_iter_recurse(iter, &array);
3545                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
3546
3547                 if (ssid_len > 0 && ssid_len < 33) {
3548                         memcpy(interface->wps_cred.ssid, ssid, ssid_len);
3549                         interface->wps_cred.ssid_len = ssid_len;
3550                 } else {
3551                         memset(interface->wps_cred.ssid, 0, 32);
3552                         interface->wps_cred.ssid_len = 0;
3553                 }
3554         }
3555 }
3556
3557 static void signal_wps_credentials(const char *path, DBusMessageIter *iter)
3558 {
3559         GSupplicantInterface *interface;
3560
3561         SUPPLICANT_DBG("");
3562
3563         interface = g_hash_table_lookup(interface_table, path);
3564         if (!interface)
3565                 return;
3566
3567         supplicant_dbus_property_foreach(iter, wps_credentials, interface);
3568 }
3569
3570 static void wps_event_args(const char *key, DBusMessageIter *iter,
3571                         void *user_data)
3572 {
3573         GSupplicantInterface *interface = user_data;
3574
3575         if (!key || !interface)
3576                 return;
3577
3578         SUPPLICANT_DBG("Arg Key %s", key);
3579 }
3580
3581 static void signal_wps_event(const char *path, DBusMessageIter *iter)
3582 {
3583         GSupplicantInterface *interface;
3584         const char *name = NULL;
3585
3586         SUPPLICANT_DBG("");
3587
3588         interface = g_hash_table_lookup(interface_table, path);
3589         if (!interface)
3590                 return;
3591
3592         dbus_message_iter_get_basic(iter, &name);
3593
3594         SUPPLICANT_DBG("Name: %s", name);
3595
3596         if (g_strcmp0(name, "success") == 0)
3597                 interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
3598         else if (g_strcmp0(name, "failed") == 0)
3599                 interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
3600         else
3601                 interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
3602
3603         if (!dbus_message_iter_has_next(iter))
3604                 return;
3605
3606         dbus_message_iter_next(iter);
3607
3608         supplicant_dbus_property_foreach(iter, wps_event_args, interface);
3609 }
3610
3611 #if defined TIZEN_EXT
3612 static void signal_power_off(const char *path, DBusMessageIter *iter)
3613 {
3614         int poweroff_state = 0;
3615
3616         dbus_message_iter_get_basic(iter, &poweroff_state);
3617
3618         SUPPLICANT_DBG("poweroff_state(%d)", poweroff_state);
3619
3620         /* POWER_OFF_DIRECT 2 && POWER_OFF_RESTART 3 */
3621         if (poweroff_state != 2 && poweroff_state != 3)
3622                 return;
3623
3624         if (callbacks_pointer == NULL)
3625                 return;
3626
3627         if (callbacks_pointer->system_power_off == NULL)
3628                 return;
3629
3630         callbacks_pointer->system_power_off();
3631 }
3632 #endif
3633
3634 static void signal_station_connected(const char *path, DBusMessageIter *iter)
3635 {
3636         GSupplicantInterface *interface;
3637         const char *sta_mac = NULL;
3638
3639         SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
3640
3641         if (callbacks_pointer->add_station == NULL)
3642                 return;
3643
3644         if (g_strcmp0(path, "/") == 0)
3645                 return;
3646
3647         interface = g_hash_table_lookup(interface_table, path);
3648         if (interface == NULL)
3649                 return;
3650
3651         dbus_message_iter_get_basic(iter, &sta_mac);
3652         if (sta_mac == NULL)
3653                 return;
3654
3655         SUPPLICANT_DBG("New station %s connected", sta_mac);
3656         callbacks_pointer->add_station(sta_mac);
3657 }
3658
3659 static void signal_station_disconnected(const char *path, DBusMessageIter *iter)
3660 {
3661         GSupplicantInterface *interface;
3662         const char *sta_mac = NULL;
3663
3664         SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
3665
3666         if (callbacks_pointer->remove_station == NULL)
3667                 return;
3668
3669         if (g_strcmp0(path, "/") == 0)
3670                 return;
3671
3672         interface = g_hash_table_lookup(interface_table, path);
3673         if (interface == NULL)
3674                 return;
3675
3676         dbus_message_iter_get_basic(iter, &sta_mac);
3677         if (sta_mac == NULL)
3678                 return;
3679
3680         SUPPLICANT_DBG("Station %s disconnected", sta_mac);
3681         callbacks_pointer->remove_station(sta_mac);
3682 }
3683
3684 static void create_peer_identifier(GSupplicantPeer *peer)
3685 {
3686         const unsigned char test[ETH_ALEN] = {};
3687
3688         if (!peer)
3689                 return;
3690
3691         if (!memcmp(peer->device_address, test, ETH_ALEN)) {
3692                 peer->identifier = g_strdup(peer->name);
3693                 return;
3694         }
3695
3696         peer->identifier = g_malloc0(19);
3697         snprintf(peer->identifier, 19, "%02x%02x%02x%02x%02x%02x",
3698                                                 peer->device_address[0],
3699                                                 peer->device_address[1],
3700                                                 peer->device_address[2],
3701                                                 peer->device_address[3],
3702                                                 peer->device_address[4],
3703                                                 peer->device_address[5]);
3704 }
3705
3706 struct peer_property_data {
3707         GSupplicantPeer *peer;
3708         GSList *old_groups;
3709         bool groups_changed;
3710         bool services_changed;
3711 };
3712
3713 static void peer_groups_relation(DBusMessageIter *iter, void *user_data)
3714 {
3715         struct peer_property_data *data = user_data;
3716         GSupplicantPeer *peer = data->peer;
3717         GSupplicantGroup *group;
3718         const char *str = NULL;
3719         GSList *elem;
3720
3721         dbus_message_iter_get_basic(iter, &str);
3722         if (!str)
3723                 return;
3724
3725         group = g_hash_table_lookup(group_mapping, str);
3726         if (!group)
3727                 return;
3728
3729         elem = g_slist_find_custom(data->old_groups, str, (GCompareFunc)g_strcmp0);
3730         if (elem) {
3731                 data->old_groups = g_slist_remove_link(data->old_groups, elem);
3732                 peer->groups = g_slist_concat(elem, peer->groups);
3733         } else {
3734                 peer->groups = g_slist_prepend(peer->groups, g_strdup(str));
3735                 data->groups_changed = true;
3736         }
3737 }
3738
3739 static void peer_property(const char *key, DBusMessageIter *iter,
3740                                                         void *user_data)
3741 {
3742         GSupplicantPeer *pending_peer;
3743         struct peer_property_data *data = user_data;
3744         GSupplicantPeer *peer = data->peer;
3745
3746         SUPPLICANT_DBG("key: %s", key);
3747
3748         if (!peer->interface)
3749                 return;
3750
3751         if (!key) {
3752                 if (peer->name) {
3753                         create_peer_identifier(peer);
3754                         callback_peer_found(peer);
3755                         pending_peer = g_hash_table_lookup(
3756                                         pending_peer_connection, peer->path);
3757
3758                         if (pending_peer && pending_peer == peer) {
3759                                 callback_peer_request(peer);
3760                                 g_hash_table_remove(pending_peer_connection,
3761                                                 peer->path);
3762                         }
3763
3764                         dbus_free(data);
3765                 }
3766
3767                 return;
3768         }
3769
3770         if (g_strcmp0(key, "DeviceAddress") == 0) {
3771                 unsigned char *dev_addr;
3772                 DBusMessageIter array;
3773                 int len;
3774
3775                 dbus_message_iter_recurse(iter, &array);
3776                 dbus_message_iter_get_fixed_array(&array, &dev_addr, &len);
3777
3778                 if (len == ETH_ALEN)
3779                         memcpy(peer->device_address, dev_addr, len);
3780         } else if (g_strcmp0(key, "DeviceName") == 0) {
3781                 const char *str = NULL;
3782
3783                 dbus_message_iter_get_basic(iter, &str);
3784                 if (str)
3785                         peer->name = g_strdup(str);
3786         } else if (g_strcmp0(key, "config_method") == 0) {
3787                 uint16_t wps_config;
3788
3789                 dbus_message_iter_get_basic(iter, &wps_config);
3790
3791                 if (wps_config & G_SUPPLICANT_WPS_CONFIG_PBC)
3792                         peer->wps_capabilities |= G_SUPPLICANT_WPS_PBC;
3793                 if (wps_config & ~G_SUPPLICANT_WPS_CONFIG_PBC)
3794                         peer->wps_capabilities |= G_SUPPLICANT_WPS_PIN;
3795         } else if (g_strcmp0(key, "Groups") == 0) {
3796                 data->old_groups = peer->groups;
3797                 peer->groups = NULL;
3798
3799                 supplicant_dbus_array_foreach(iter,
3800                                                 peer_groups_relation, data);
3801                 if (g_slist_length(data->old_groups) > 0) {
3802                         g_slist_free_full(data->old_groups, g_free);
3803                         data->groups_changed = true;
3804                 }
3805         } else if (g_strcmp0(key, "IEs") == 0) {
3806                 DBusMessageIter array;
3807                 unsigned char *ie;
3808                 int ie_len;
3809
3810                 dbus_message_iter_recurse(iter, &array);
3811                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
3812
3813                 if (!ie || ie_len < 2)
3814                         return;
3815
3816                 if (peer->widi_ies) {
3817                         if (memcmp(peer->widi_ies, ie, ie_len) == 0)
3818                                 return;
3819
3820                         g_free(peer->widi_ies);
3821                         peer->widi_ies_length = 0;
3822                 }
3823
3824                 peer->widi_ies = g_malloc0(ie_len * sizeof(unsigned char));
3825
3826                 memcpy(peer->widi_ies, ie, ie_len);
3827                 peer->widi_ies_length = ie_len;
3828                 data->services_changed = true;
3829         }
3830 }
3831
3832 static void signal_peer_found(const char *path, DBusMessageIter *iter)
3833 {
3834         struct peer_property_data *property_data;
3835         GSupplicantInterface *interface;
3836         const char *obj_path = NULL;
3837         GSupplicantPeer *peer;
3838
3839         SUPPLICANT_DBG("");
3840
3841         interface = g_hash_table_lookup(interface_table, path);
3842         if (!interface)
3843                 return;
3844
3845         dbus_message_iter_get_basic(iter, &obj_path);
3846         if (!obj_path || g_strcmp0(obj_path, "/") == 0)
3847                 return;
3848
3849         peer = g_hash_table_lookup(interface->peer_table, obj_path);
3850         if (peer)
3851                 return;
3852
3853         peer = g_try_new0(GSupplicantPeer, 1);
3854         if (!peer)
3855                 return;
3856
3857         peer->interface = interface;
3858         peer->path = g_strdup(obj_path);
3859         g_hash_table_insert(interface->peer_table, peer->path, peer);
3860         g_hash_table_replace(peer_mapping, peer->path, interface);
3861
3862         property_data = dbus_malloc0(sizeof(struct peer_property_data));
3863         property_data->peer = peer;
3864
3865         dbus_message_iter_next(iter);
3866         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
3867                 supplicant_dbus_property_foreach(iter, peer_property,
3868                                                         property_data);
3869                 peer_property(NULL, NULL, property_data);
3870                 return;
3871         }
3872
3873         supplicant_dbus_property_get_all(obj_path,
3874                                         SUPPLICANT_INTERFACE ".Peer",
3875                                         peer_property, property_data, NULL);
3876 }
3877
3878 static void signal_peer_lost(const char *path, DBusMessageIter *iter)
3879 {
3880         GSupplicantInterface *interface;
3881         const char *obj_path = NULL;
3882         GSupplicantPeer *peer;
3883
3884         SUPPLICANT_DBG("");
3885
3886         interface = g_hash_table_lookup(interface_table, path);
3887         if (!interface)
3888                 return;
3889
3890         dbus_message_iter_get_basic(iter, &obj_path);
3891         if (!obj_path || g_strcmp0(obj_path, "/") == 0)
3892                 return;
3893
3894         peer = g_hash_table_lookup(interface->peer_table, obj_path);
3895         if (!peer)
3896                 return;
3897
3898         g_hash_table_remove(interface->peer_table, obj_path);
3899 }
3900
3901 static void signal_peer_changed(const char *path, DBusMessageIter *iter)
3902 {
3903         struct peer_property_data *property_data;
3904         GSupplicantInterface *interface;
3905         GSupplicantPeer *peer;
3906
3907         SUPPLICANT_DBG("");
3908
3909         interface = g_hash_table_lookup(peer_mapping, path);
3910         if (!interface)
3911                 return;
3912
3913         peer = g_hash_table_lookup(interface->peer_table, path);
3914         if (!peer) {
3915                 g_hash_table_remove(peer_mapping, path);
3916                 return;
3917         }
3918
3919         property_data = dbus_malloc0(sizeof(struct peer_property_data));
3920         property_data->peer = peer;
3921
3922         supplicant_dbus_property_foreach(iter, peer_property, property_data);
3923         if (property_data->services_changed)
3924                 callback_peer_changed(peer,
3925                                         G_SUPPLICANT_PEER_SERVICES_CHANGED);
3926
3927         if (property_data->groups_changed)
3928                 callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_CHANGED);
3929
3930         dbus_free(property_data);
3931
3932         if (!g_supplicant_peer_is_in_a_group(peer))
3933                 peer->connection_requested = false;
3934 }
3935
3936 struct group_sig_data {
3937         const char *peer_obj_path;
3938         unsigned char iface_address[ETH_ALEN];
3939         const char *interface_obj_path;
3940         const char *group_obj_path;
3941         int role;
3942 };
3943
3944 static void group_sig_property(const char *key, DBusMessageIter *iter,
3945                                                         void *user_data)
3946 {
3947         struct group_sig_data *data = user_data;
3948
3949         if (!key)
3950                 return;
3951
3952         if (g_strcmp0(key, "peer_interface_addr") == 0) {
3953                 unsigned char *dev_addr;
3954                 DBusMessageIter array;
3955                 int len;
3956
3957                 dbus_message_iter_recurse(iter, &array);
3958                 dbus_message_iter_get_fixed_array(&array, &dev_addr, &len);
3959
3960                 if (len == ETH_ALEN)
3961                         memcpy(data->iface_address, dev_addr, len);
3962         } else if (g_strcmp0(key, "role") == 0) {
3963                 const char *str = NULL;
3964
3965                 dbus_message_iter_get_basic(iter, &str);
3966                 if (g_strcmp0(str, "GO") == 0)
3967                         data->role = G_SUPPLICANT_GROUP_ROLE_GO;
3968                 else
3969                         data->role = G_SUPPLICANT_GROUP_ROLE_CLIENT;
3970         } else if (g_strcmp0(key, "peer_object") == 0)
3971                 dbus_message_iter_get_basic(iter, &data->peer_obj_path);
3972         else if (g_strcmp0(key, "interface_object") == 0)
3973                 dbus_message_iter_get_basic(iter, &data->interface_obj_path);
3974         else if (g_strcmp0(key, "group_object") == 0)
3975                 dbus_message_iter_get_basic(iter, &data->group_obj_path);
3976
3977 }
3978
3979 static void signal_group_success(const char *path, DBusMessageIter *iter)
3980 {
3981         GSupplicantInterface *interface;
3982         struct group_sig_data data = {};
3983         GSupplicantPeer *peer;
3984
3985         SUPPLICANT_DBG("");
3986
3987         interface = g_hash_table_lookup(interface_table, path);
3988         if (!interface)
3989                 return;
3990
3991         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3992         if (!data.peer_obj_path)
3993                 return;
3994
3995         peer = g_hash_table_lookup(interface->peer_table, data.peer_obj_path);
3996         if (!peer)
3997                 return;
3998
3999         memcpy(peer->iface_address, data.iface_address, ETH_ALEN);
4000         interface->pending_peer_path = peer->path;
4001 }
4002
4003 static void signal_group_failure(const char *path, DBusMessageIter *iter)
4004 {
4005         GSupplicantInterface *interface;
4006         struct group_sig_data data = {};
4007         GSupplicantPeer *peer;
4008
4009         SUPPLICANT_DBG("");
4010
4011         interface = g_hash_table_lookup(interface_table, path);
4012         if (!interface)
4013                 return;
4014
4015         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
4016         if (!data.peer_obj_path)
4017                 return;
4018
4019         peer = g_hash_table_lookup(interface->peer_table, data.peer_obj_path);
4020         if (!peer)
4021                 return;
4022
4023         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_FAILED);
4024         peer->connection_requested = false;
4025 }
4026
4027 static void signal_group_started(const char *path, DBusMessageIter *iter)
4028 {
4029         GSupplicantInterface *interface, *g_interface;
4030         struct group_sig_data data = {};
4031         GSupplicantGroup *group;
4032         GSupplicantPeer *peer;
4033
4034         SUPPLICANT_DBG("");
4035
4036         interface = g_hash_table_lookup(interface_table, path);
4037         if (!interface)
4038                 return;
4039
4040         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
4041         if (!data.interface_obj_path || !data.group_obj_path)
4042                 return;
4043
4044         peer = g_hash_table_lookup(interface->peer_table,
4045                                                 interface->pending_peer_path);
4046         interface->pending_peer_path = NULL;
4047         if (!peer)
4048                 return;
4049
4050         g_interface = g_hash_table_lookup(interface_table,
4051                                                 data.interface_obj_path);
4052         if (!g_interface)
4053                 return;
4054
4055         group = g_hash_table_lookup(interface->group_table,
4056                                                 data.group_obj_path);
4057         if (group)
4058                 return;
4059
4060         group = g_try_new0(GSupplicantGroup, 1);
4061         if (!group)
4062                 return;
4063
4064         group->interface = g_interface;
4065         group->orig_interface = interface;
4066         group->path = g_strdup(data.group_obj_path);
4067         group->role = data.role;
4068
4069         g_hash_table_insert(interface->group_table, group->path, group);
4070         g_hash_table_replace(group_mapping, group->path, group);
4071
4072         peer->current_group_iface = g_interface;
4073         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_STARTED);
4074 }
4075
4076 static void remove_peer_group_interface(GHashTable *group_table,
4077                                 const char* path)
4078 {
4079         GSupplicantGroup *group;
4080         GHashTableIter iter;
4081         gpointer value, key;
4082
4083         if (!group_table)
4084                 return;
4085
4086         group = g_hash_table_lookup(group_table, path);
4087
4088         if (!group || !group->orig_interface)
4089                 return;
4090
4091         g_hash_table_iter_init(&iter, group->orig_interface->peer_table);
4092
4093         while (g_hash_table_iter_next(&iter, &key, &value)) {
4094                 GSupplicantPeer *peer = value;
4095
4096                 if (peer->current_group_iface == group->interface)
4097                         peer->current_group_iface = NULL;
4098         }
4099 }
4100
4101 static void signal_group_finished(const char *path, DBusMessageIter *iter)
4102 {
4103         GSupplicantInterface *interface;
4104         struct group_sig_data data = {};
4105
4106         SUPPLICANT_DBG("");
4107
4108         interface = g_hash_table_lookup(interface_table, path);
4109         if (!interface)
4110                 return;
4111
4112         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
4113         if (!data.interface_obj_path || !data.group_obj_path)
4114                 return;
4115
4116         remove_peer_group_interface(interface->group_table, data.group_obj_path);
4117
4118         g_hash_table_remove(group_mapping, data.group_obj_path);
4119
4120         g_hash_table_remove(interface->group_table, data.group_obj_path);
4121 }
4122
4123 static void signal_group_request(const char *path, DBusMessageIter *iter)
4124 {
4125         GSupplicantInterface *interface;
4126         GSupplicantPeer *peer;
4127         const char *obj_path;
4128
4129         SUPPLICANT_DBG("");
4130
4131         interface = g_hash_table_lookup(interface_table, path);
4132         if (!interface)
4133                 return;
4134
4135         dbus_message_iter_get_basic(iter, &obj_path);
4136         if (!obj_path || !g_strcmp0(obj_path, "/"))
4137                 return;
4138
4139         peer = g_hash_table_lookup(interface->peer_table, obj_path);
4140         if (!peer)
4141                 return;
4142
4143         /*
4144          * Peer has been previously found and property set,
4145          * otherwise, defer connection to when peer property
4146          * is set.
4147          */
4148         if (peer->identifier)
4149                 callback_peer_request(peer);
4150         else
4151                 g_hash_table_replace(pending_peer_connection, peer->path, peer);
4152 }
4153
4154 static void signal_group_peer_joined(const char *path, DBusMessageIter *iter)
4155 {
4156         const char *peer_path = NULL;
4157         GSupplicantInterface *interface;
4158         GSupplicantGroup *group;
4159         GSupplicantPeer *peer;
4160
4161         SUPPLICANT_DBG("");
4162
4163         group = g_hash_table_lookup(group_mapping, path);
4164         if (!group)
4165                 return;
4166
4167         dbus_message_iter_get_basic(iter, &peer_path);
4168         if (!peer_path)
4169                 return;
4170
4171         interface = g_hash_table_lookup(peer_mapping, peer_path);
4172         if (!interface)
4173                 return;
4174
4175         peer = g_hash_table_lookup(interface->peer_table, peer_path);
4176         if (!peer)
4177                 return;
4178
4179         group->members = g_slist_prepend(group->members, g_strdup(peer_path));
4180
4181         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_JOINED);
4182 }
4183
4184 static void signal_group_peer_disconnected(const char *path, DBusMessageIter *iter)
4185 {
4186         const char *peer_path = NULL;
4187         GSupplicantInterface *interface;
4188         GSupplicantGroup *group;
4189         GSupplicantPeer *peer;
4190         GSList *elem;
4191
4192         SUPPLICANT_DBG("");
4193
4194         group = g_hash_table_lookup(group_mapping, path);
4195         if (!group)
4196                 return;
4197
4198         dbus_message_iter_get_basic(iter, &peer_path);
4199         if (!peer_path)
4200                 return;
4201
4202         for (elem = group->members; elem; elem = elem->next) {
4203                 if (!g_strcmp0(elem->data, peer_path))
4204                         break;
4205         }
4206
4207         if (!elem)
4208                 return;
4209
4210         g_free(elem->data);
4211         group->members = g_slist_delete_link(group->members, elem);
4212
4213         interface = g_hash_table_lookup(peer_mapping, peer_path);
4214         if (!interface)
4215                 return;
4216
4217         peer = g_hash_table_lookup(interface->peer_table, peer_path);
4218         if (!peer)
4219                 return;
4220
4221         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_DISCONNECTED);
4222         peer->connection_requested = false;
4223 }
4224
4225 #if defined TIZEN_EXT_WIFI_MESH
4226 const void *g_supplicant_interface_get_mesh_group_ssid(
4227                                                         GSupplicantInterface *interface,
4228                                                         unsigned int *ssid_len)
4229 {
4230         if (!ssid_len)
4231                 return NULL;
4232
4233         if (!interface || interface->group_info.ssid_len == 0) {
4234                 *ssid_len = 0;
4235                 return NULL;
4236         }
4237
4238         *ssid_len = interface->group_info.ssid_len;
4239         return interface->group_info.ssid;
4240 }
4241
4242 int g_supplicant_mesh_get_disconnect_reason(GSupplicantInterface *interface)
4243 {
4244         if (!interface)
4245                 return -EINVAL;
4246
4247         return interface->group_info.disconnect_reason;
4248 }
4249
4250 const char *g_supplicant_mesh_peer_get_address(GSupplicantMeshPeer *mesh_peer)
4251 {
4252         if (!mesh_peer || !mesh_peer->peer_address)
4253                 return NULL;
4254
4255         return mesh_peer->peer_address;
4256 }
4257
4258 int g_supplicant_mesh_peer_get_disconnect_reason(GSupplicantMeshPeer *mesh_peer)
4259 {
4260         if (!mesh_peer)
4261                 return -EINVAL;
4262
4263         return mesh_peer->disconnect_reason;
4264 }
4265
4266 static void callback_mesh_group_started(GSupplicantInterface *interface)
4267 {
4268         if (!callbacks_pointer)
4269                 return;
4270
4271         if (!callbacks_pointer->mesh_group_started)
4272                 return;
4273
4274         callbacks_pointer->mesh_group_started(interface);
4275 }
4276
4277 static void callback_mesh_group_removed(GSupplicantInterface *interface)
4278 {
4279         if (!callbacks_pointer)
4280                 return;
4281
4282         if (!callbacks_pointer->mesh_group_removed)
4283                 return;
4284
4285         callbacks_pointer->mesh_group_removed(interface);
4286 }
4287
4288 static void mesh_group_info(const char *key, DBusMessageIter *iter,
4289                                                         void *user_data)
4290 {
4291         GSupplicantInterface *interface = user_data;
4292         if (!key)
4293                 return;
4294
4295         if (g_strcmp0(key, "SSID") == 0) {
4296                 DBusMessageIter array;
4297                 unsigned char *ssid;
4298                 int ssid_len;
4299
4300                 dbus_message_iter_recurse(iter, &array);
4301                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
4302
4303                 if (ssid_len > 0 && ssid_len < 33) {
4304                         memcpy(interface->group_info.ssid, ssid, ssid_len);
4305                         interface->group_info.ssid_len = ssid_len;
4306                 } else {
4307                         memset(interface->group_info.ssid, 0, 32);
4308                         interface->group_info.ssid_len = 0;
4309                 }
4310         } else if (g_strcmp0(key, "DisconnectReason") == 0) {
4311                 int disconnect_reason = 0;
4312                 dbus_message_iter_get_basic(iter, &disconnect_reason);
4313                 interface->group_info.disconnect_reason = disconnect_reason;
4314         }
4315 }
4316
4317 static void signal_mesh_group_started(const char *path, DBusMessageIter *iter)
4318 {
4319         GSupplicantInterface *interface;
4320
4321         interface = g_hash_table_lookup(interface_table, path);
4322         if (!interface)
4323                 return;
4324
4325         supplicant_dbus_property_foreach(iter, mesh_group_info, interface);
4326
4327         callback_mesh_group_started(interface);
4328 }
4329
4330 static void signal_mesh_group_removed(const char *path, DBusMessageIter *iter)
4331 {
4332         GSupplicantInterface *interface;
4333
4334         interface = g_hash_table_lookup(interface_table, path);
4335         if (!interface)
4336                 return;
4337
4338         supplicant_dbus_property_foreach(iter, mesh_group_info, interface);
4339
4340         callback_mesh_group_removed(interface);
4341 }
4342
4343 static void callback_mesh_peer_connected(GSupplicantMeshPeer *mesh_peer)
4344 {
4345         if (!callbacks_pointer)
4346                 return;
4347
4348         if (!callbacks_pointer->mesh_peer_connected)
4349                 return;
4350
4351         callbacks_pointer->mesh_peer_connected(mesh_peer);
4352 }
4353
4354 static void callback_mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer)
4355 {
4356         if (!callbacks_pointer)
4357                 return;
4358
4359         if (!callbacks_pointer->mesh_peer_disconnected)
4360                 return;
4361
4362         callbacks_pointer->mesh_peer_disconnected(mesh_peer);
4363 }
4364
4365 static void mesh_peer_info(const char *key, DBusMessageIter *iter,
4366                                                         void *user_data)
4367 {
4368         GSupplicantMeshPeer *mesh_peer = user_data;
4369         if (!key)
4370                 return;
4371
4372         if (g_strcmp0(key, "PeerAddress") == 0) {
4373                 DBusMessageIter array;
4374                 unsigned char *addr;
4375                 int addr_len;
4376
4377                 dbus_message_iter_recurse(iter, &array);
4378                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
4379
4380                 if (addr_len == 6) {
4381                         mesh_peer->peer_address = g_malloc0(19);
4382                         snprintf(mesh_peer->peer_address, 19,
4383                                          "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1],
4384                                          addr[2], addr[3], addr[4], addr[5]);
4385                 }
4386         } else if (g_strcmp0(key, "DisconnectReason") == 0) {
4387                 int disconnect_reason = 0;
4388                 dbus_message_iter_get_basic(iter, &disconnect_reason);
4389                 mesh_peer->disconnect_reason = disconnect_reason;
4390         }
4391 }
4392
4393 static void signal_mesh_peer_connected(const char *path, DBusMessageIter *iter)
4394 {
4395         GSupplicantInterface *interface;
4396         GSupplicantMeshPeer *mesh_peer;
4397
4398         interface = g_hash_table_lookup(interface_table, path);
4399         if (!interface)
4400                 return;
4401
4402         mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer));
4403         mesh_peer->interface = interface;
4404
4405         supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer);
4406
4407         callback_mesh_peer_connected(mesh_peer);
4408         g_free(mesh_peer->peer_address);
4409         g_free(mesh_peer);
4410 }
4411
4412 static void signal_mesh_peer_disconnected(const char *path,
4413                                                                 DBusMessageIter *iter)
4414 {
4415         GSupplicantInterface *interface;
4416         GSupplicantMeshPeer *mesh_peer;
4417
4418         interface = g_hash_table_lookup(interface_table, path);
4419         if (!interface)
4420                 return;
4421
4422         mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer));
4423         mesh_peer->interface = interface;
4424
4425         supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer);
4426
4427         callback_mesh_peer_disconnected(mesh_peer);
4428         g_free(mesh_peer->peer_address);
4429         g_free(mesh_peer);
4430 }
4431 #endif
4432
4433 static struct {
4434         const char *interface;
4435         const char *member;
4436         void (*function) (const char *path, DBusMessageIter *iter);
4437 } signal_map[] = {
4438         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
4439
4440         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
4441         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
4442         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
4443         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
4444
4445         { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
4446         { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done         },
4447         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added         },
4448         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed       },
4449         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
4450         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
4451
4452         { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed   },
4453
4454         { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
4455         { SUPPLICANT_INTERFACE ".Interface.WPS", "Event",       signal_wps_event       },
4456 #if defined TIZEN_EXT
4457         { "org.tizen.system.deviced.PowerOff", "ChangeState", signal_power_off },
4458 #endif
4459
4460         { SUPPLICANT_INTERFACE".Interface", "StaAuthorized", signal_station_connected      },
4461         { SUPPLICANT_INTERFACE".Interface", "StaDeauthorized", signal_station_disconnected },
4462
4463         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceFound", signal_peer_found },
4464         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceLost",  signal_peer_lost  },
4465
4466         { SUPPLICANT_INTERFACE ".Peer", "PropertiesChanged", signal_peer_changed },
4467
4468         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationSuccess", signal_group_success },
4469         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationFailure", signal_group_failure },
4470         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupStarted", signal_group_started },
4471         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupFinished", signal_group_finished },
4472         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationRequest", signal_group_request },
4473
4474         { SUPPLICANT_INTERFACE ".Group", "PeerJoined", signal_group_peer_joined },
4475         { SUPPLICANT_INTERFACE ".Group", "PeerDisconnected", signal_group_peer_disconnected },
4476 #if defined TIZEN_EXT_WIFI_MESH
4477         { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshGroupStarted",
4478                 signal_mesh_group_started },
4479         { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshGroupRemoved",
4480                 signal_mesh_group_removed },
4481         { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshPeerConnected",
4482                 signal_mesh_peer_connected },
4483         { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshPeerDisconnected",
4484                 signal_mesh_peer_disconnected },
4485 #endif
4486
4487         { }
4488 };
4489
4490 static DBusHandlerResult g_supplicant_filter(DBusConnection *conn,
4491                                         DBusMessage *message, void *data)
4492 {
4493         DBusMessageIter iter;
4494         const char *path;
4495         int i;
4496
4497         path = dbus_message_get_path(message);
4498         if (!path)
4499                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
4500
4501         if (!dbus_message_iter_init(message, &iter))
4502                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
4503
4504         for (i = 0; signal_map[i].interface; i++) {
4505                 if (!dbus_message_has_interface(message, signal_map[i].interface))
4506                         continue;
4507
4508                 if (!dbus_message_has_member(message, signal_map[i].member))
4509                         continue;
4510
4511                 signal_map[i].function(path, &iter);
4512                 break;
4513         }
4514
4515         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
4516 }
4517
4518 void g_supplicant_interface_cancel(GSupplicantInterface *interface)
4519 {
4520         SUPPLICANT_DBG("Cancelling any pending DBus calls");
4521         supplicant_dbus_method_call_cancel_all(interface);
4522         supplicant_dbus_property_call_cancel_all(interface);
4523 }
4524
4525 struct supplicant_regdom {
4526         GSupplicantCountryCallback callback;
4527         const char *alpha2;
4528         const void *user_data;
4529 };
4530
4531 static void country_result(const char *error,
4532                                 DBusMessageIter *iter, void *user_data)
4533 {
4534         struct supplicant_regdom *regdom = user_data;
4535         int result = 0;
4536
4537         SUPPLICANT_DBG("Country setting result");
4538
4539         if (!user_data)
4540                 return;
4541
4542         if (error) {
4543                 SUPPLICANT_DBG("Country setting failure %s", error);
4544                 result = -EINVAL;
4545         }
4546
4547         if (regdom->callback)
4548                 regdom->callback(result, regdom->alpha2,
4549                                         (void *) regdom->user_data);
4550
4551         g_free(regdom);
4552 }
4553
4554 static void country_params(DBusMessageIter *iter, void *user_data)
4555 {
4556         struct supplicant_regdom *regdom = user_data;
4557
4558         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
4559                                                         &regdom->alpha2);
4560 }
4561
4562 int g_supplicant_set_country(const char *alpha2,
4563                                 GSupplicantCountryCallback callback,
4564                                         const void *user_data)
4565 {
4566         struct supplicant_regdom *regdom;
4567         int ret;
4568
4569         SUPPLICANT_DBG("Country setting %s", alpha2);
4570
4571         if (!system_available)
4572                 return -EFAULT;
4573
4574         regdom = dbus_malloc0(sizeof(*regdom));
4575         if (!regdom)
4576                 return -ENOMEM;
4577
4578         regdom->callback = callback;
4579         regdom->alpha2 = alpha2;
4580         regdom->user_data = user_data;
4581
4582         ret =  supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
4583                                         "Country", DBUS_TYPE_STRING_AS_STRING,
4584                                         country_params, country_result,
4585                                         regdom, NULL);
4586         if (ret < 0) {
4587                 dbus_free(regdom);
4588                 SUPPLICANT_DBG("Unable to set Country configuration");
4589         }
4590         return ret;
4591 }
4592
4593 int g_supplicant_interface_set_country(GSupplicantInterface *interface,
4594                                         GSupplicantCountryCallback callback,
4595                                                         const char *alpha2,
4596                                                         void *user_data)
4597 {
4598         struct supplicant_regdom *regdom;
4599         int ret;
4600
4601         regdom = dbus_malloc0(sizeof(*regdom));
4602         if (!regdom)
4603                 return -ENOMEM;
4604
4605         regdom->callback = callback;
4606         regdom->alpha2 = alpha2;
4607         regdom->user_data = user_data;
4608
4609         ret =  supplicant_dbus_property_set(interface->path,
4610                                 SUPPLICANT_INTERFACE ".Interface",
4611                                 "Country", DBUS_TYPE_STRING_AS_STRING,
4612                                 country_params, country_result,
4613                                         regdom, NULL);
4614         if (ret < 0) {
4615                 dbus_free(regdom);
4616                 SUPPLICANT_DBG("Unable to set Country configuration");
4617         }
4618
4619         return ret;
4620 }
4621
4622 bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface)
4623 {
4624         if (!interface)
4625                 return false;
4626
4627         return interface->p2p_support;
4628 }
4629
4630 struct supplicant_p2p_dev_config {
4631         char *device_name;
4632         char *dev_type;
4633 };
4634
4635 static void p2p_device_config_result(const char *error,
4636                                         DBusMessageIter *iter, void *user_data)
4637 {
4638         struct supplicant_p2p_dev_config *config = user_data;
4639
4640         if (error)
4641                 SUPPLICANT_DBG("Unable to set P2P Device configuration: %s",
4642                                                                         error);
4643
4644         g_free(config->device_name);
4645         g_free(config->dev_type);
4646         dbus_free(config);
4647 }
4648
4649 static int dev_type_str2bin(const char *type, unsigned char dev_type[8])
4650 {
4651         int length, pos, end;
4652         char b[3] = {};
4653         char *e = NULL;
4654
4655         end = strlen(type);
4656         for (length = pos = 0; type[pos] != '\0' && length < 8; length++) {
4657                 if (pos+2 > end)
4658                         return 0;
4659
4660                 b[0] = type[pos];
4661                 b[1] = type[pos+1];
4662
4663                 dev_type[length] = strtol(b, &e, 16);
4664                 if (e && *e != '\0')
4665                         return 0;
4666
4667                 pos += 2;
4668         }
4669
4670         return 8;
4671 }
4672
4673 static void p2p_device_config_params(DBusMessageIter *iter, void *user_data)
4674 {
4675         struct supplicant_p2p_dev_config *config = user_data;
4676         DBusMessageIter dict;
4677
4678         supplicant_dbus_dict_open(iter, &dict);
4679
4680         supplicant_dbus_dict_append_basic(&dict, "DeviceName",
4681                                 DBUS_TYPE_STRING, &config->device_name);
4682
4683         if (config->dev_type) {
4684                 unsigned char dev_type[8] = {}, *type;
4685                 int len;
4686
4687                 len = dev_type_str2bin(config->dev_type, dev_type);
4688                 if (len) {
4689                         type = dev_type;
4690                         supplicant_dbus_dict_append_fixed_array(&dict,
4691                                         "PrimaryDeviceType",
4692                                         DBUS_TYPE_BYTE, &type, len);
4693                 }
4694         }
4695
4696         supplicant_dbus_dict_close(iter, &dict);
4697 }
4698
4699 int g_supplicant_interface_set_p2p_device_config(GSupplicantInterface *interface,
4700                                         const char *device_name,
4701                                         const char *primary_dev_type)
4702 {
4703         struct supplicant_p2p_dev_config *config;
4704         int ret;
4705
4706         SUPPLICANT_DBG("P2P Device settings %s/%s",
4707                                         device_name, primary_dev_type);
4708
4709         config = dbus_malloc0(sizeof(*config));
4710         if (!config)
4711                 return -ENOMEM;
4712
4713         config->device_name = g_strdup(device_name);
4714         config->dev_type = g_strdup(primary_dev_type);
4715
4716         ret = supplicant_dbus_property_set(interface->path,
4717                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
4718                                 "P2PDeviceConfig",
4719                                 DBUS_TYPE_ARRAY_AS_STRING
4720                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
4721                                 DBUS_TYPE_STRING_AS_STRING
4722                                 DBUS_TYPE_VARIANT_AS_STRING
4723                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
4724                                 p2p_device_config_params,
4725                                 p2p_device_config_result, config, NULL);
4726         if (ret < 0) {
4727                 g_free(config->device_name);
4728                 g_free(config->dev_type);
4729                 dbus_free(config);
4730                 SUPPLICANT_DBG("Unable to set P2P Device configuration");
4731         }
4732
4733         return ret;
4734 }
4735
4736 static gboolean peer_lookup_by_identifier(gpointer key, gpointer value,
4737                                                         gpointer user_data)
4738 {
4739         const GSupplicantPeer *peer = value;
4740         const char *identifier = user_data;
4741
4742         if (!g_strcmp0(identifier, peer->identifier))
4743                 return TRUE;
4744
4745         return FALSE;
4746 }
4747
4748 GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interface,
4749                                                         const char *identifier)
4750 {
4751         GSupplicantPeer *peer;
4752
4753         peer = g_hash_table_find(interface->peer_table,
4754                                         peer_lookup_by_identifier,
4755                                         (void *) identifier);
4756         return peer;
4757 }
4758
4759 static void interface_create_data_free(struct interface_create_data *data)
4760 {
4761         g_free(data->ifname);
4762         g_free(data->driver);
4763         g_free(data->bridge);
4764 #if defined TIZEN_EXT_WIFI_MESH
4765         g_free(data->parent_ifname);
4766 #endif
4767         dbus_free(data);
4768 }
4769
4770 static bool interface_exists(GSupplicantInterface *interface,
4771                                 const char *path)
4772 {
4773         GSupplicantInterface *tmp;
4774
4775         tmp = g_hash_table_lookup(interface_table, path);
4776         if (tmp && tmp == interface)
4777                 return true;
4778
4779         return false;
4780 }
4781
4782 static void interface_create_property(const char *key, DBusMessageIter *iter,
4783                                                         void *user_data)
4784 {
4785         struct interface_create_data *data = user_data;
4786         GSupplicantInterface *interface = data->interface;
4787
4788         if (!key) {
4789                 if (data->callback) {
4790                         data->callback(0, data->interface, data->user_data);
4791 #if !defined TIZEN_EXT
4792                         callback_p2p_support(interface);
4793 #endif
4794 #if defined TIZEN_EXT_WIFI_MESH
4795                         callback_mesh_support(interface);
4796 #endif
4797                 }
4798
4799                 interface_create_data_free(data);
4800         }
4801
4802         interface_property(key, iter, interface);
4803 }
4804
4805 static void interface_create_result(const char *error,
4806                                 DBusMessageIter *iter, void *user_data)
4807 {
4808         struct interface_create_data *data = user_data;
4809         const char *path = NULL;
4810         int err;
4811
4812         SUPPLICANT_DBG("");
4813
4814         if (error) {
4815                 g_warning("error %s", error);
4816                 err = -EIO;
4817                 goto done;
4818         }
4819
4820         dbus_message_iter_get_basic(iter, &path);
4821         if (!path) {
4822                 err = -EINVAL;
4823                 goto done;
4824         }
4825
4826         if (!system_available) {
4827                 err = -EFAULT;
4828                 goto done;
4829         }
4830
4831         data->interface = g_hash_table_lookup(interface_table, path);
4832         if (!data->interface) {
4833                 data->interface = interface_alloc(path);
4834                 if (!data->interface) {
4835                         err = -ENOMEM;
4836                         goto done;
4837                 }
4838         }
4839
4840         err = supplicant_dbus_property_get_all(path,
4841                                         SUPPLICANT_INTERFACE ".Interface",
4842                                         interface_create_property, data,
4843                                         NULL);
4844         if (err == 0)
4845                 return;
4846
4847 done:
4848         if (data->callback)
4849                 data->callback(err, NULL, data->user_data);
4850
4851         interface_create_data_free(data);
4852 }
4853
4854 static void interface_create_params(DBusMessageIter *iter, void *user_data)
4855 {
4856         struct interface_create_data *data = user_data;
4857         DBusMessageIter dict;
4858         char *config_file = NULL;
4859
4860         SUPPLICANT_DBG("");
4861
4862         supplicant_dbus_dict_open(iter, &dict);
4863
4864         supplicant_dbus_dict_append_basic(&dict, "Ifname",
4865                                         DBUS_TYPE_STRING, &data->ifname);
4866
4867         if (data->driver)
4868                 supplicant_dbus_dict_append_basic(&dict, "Driver",
4869                                         DBUS_TYPE_STRING, &data->driver);
4870
4871         if (data->bridge)
4872                 supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
4873                                         DBUS_TYPE_STRING, &data->bridge);
4874
4875         config_file = g_hash_table_lookup(config_file_table, data->ifname);
4876         if (config_file) {
4877                 SUPPLICANT_DBG("[%s] ConfigFile %s", data->ifname, config_file);
4878
4879                 supplicant_dbus_dict_append_basic(&dict, "ConfigFile",
4880                                         DBUS_TYPE_STRING, &config_file);
4881         }
4882
4883 #if defined TIZEN_EXT_WIFI_MESH
4884         if (data->is_mesh_interface) {
4885                 if (data->parent_ifname)
4886                         supplicant_dbus_dict_append_basic(&dict, "ParentIfname",
4887                                         DBUS_TYPE_STRING, &data->parent_ifname);
4888
4889                 supplicant_dbus_dict_append_basic(&dict, "IsMeshInterface",
4890                                         DBUS_TYPE_BOOLEAN, &data->is_mesh_interface);
4891         }
4892 #endif
4893
4894         supplicant_dbus_dict_close(iter, &dict);
4895 }
4896
4897 static void interface_get_result(const char *error,
4898                                 DBusMessageIter *iter, void *user_data)
4899 {
4900         struct interface_create_data *data = user_data;
4901         GSupplicantInterface *interface;
4902         const char *path = NULL;
4903         int err;
4904
4905         SUPPLICANT_DBG("");
4906
4907         if (error) {
4908                 SUPPLICANT_DBG("Interface not created yet");
4909                 goto create;
4910         }
4911
4912         dbus_message_iter_get_basic(iter, &path);
4913         if (!path) {
4914                 err = -EINVAL;
4915                 goto done;
4916         }
4917
4918         interface = g_hash_table_lookup(interface_table, path);
4919         if (!interface) {
4920                 err = -ENOENT;
4921                 goto done;
4922         }
4923
4924         if (data->callback) {
4925                 data->callback(0, interface, data->user_data);
4926 #if !defined TIZEN_EXT
4927                 callback_p2p_support(interface);
4928 #endif
4929 #if defined TIZEN_EXT_WIFI_MESH
4930                 callback_mesh_support(interface);
4931 #endif
4932         }
4933
4934         interface_create_data_free(data);
4935
4936         return;
4937
4938 create:
4939         if (!system_available) {
4940                 err = -EFAULT;
4941                 goto done;
4942         }
4943
4944         SUPPLICANT_DBG("Creating interface");
4945
4946         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
4947                                                 SUPPLICANT_INTERFACE,
4948                                                 "CreateInterface",
4949                                                 interface_create_params,
4950                                                 interface_create_result, data,
4951                                                 NULL);
4952         if (err == 0)
4953                 return;
4954
4955 done:
4956         if (data->callback)
4957                 data->callback(err, NULL, data->user_data);
4958
4959         interface_create_data_free(data);
4960 }
4961
4962 static void interface_get_params(DBusMessageIter *iter, void *user_data)
4963 {
4964         struct interface_create_data *data = user_data;
4965
4966         SUPPLICANT_DBG("");
4967
4968         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
4969 }
4970
4971 #if defined TIZEN_EXT_WIFI_MESH
4972 int g_supplicant_mesh_interface_create(const char *ifname, const char *driver,
4973                                                 const char *bridge, const char *parent_ifname,
4974                                                 GSupplicantInterfaceCallback callback, void *user_data)
4975 {
4976         struct interface_create_data *data;
4977         int ret;
4978
4979         SUPPLICANT_DBG("ifname %s", ifname);
4980
4981         if (!ifname || !parent_ifname)
4982                 return -EINVAL;
4983
4984         if (!system_available)
4985                 return -EFAULT;
4986
4987         data = dbus_malloc0(sizeof(*data));
4988         if (!data)
4989                 return -ENOMEM;
4990
4991         data->ifname = g_strdup(ifname);
4992         data->driver = g_strdup(driver);
4993         data->bridge = g_strdup(bridge);
4994         data->is_mesh_interface = true;
4995         data->parent_ifname = g_strdup(parent_ifname);
4996         data->callback = callback;
4997         data->user_data = user_data;
4998
4999         ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
5000                                                 SUPPLICANT_INTERFACE,
5001                                                 "CreateInterface",
5002                                                 interface_create_params,
5003                                                 interface_create_result, data,
5004                                                 NULL);
5005         return ret;
5006 }
5007
5008 struct interface_mesh_peer_data {
5009         char *peer_address;
5010         char *method;
5011         GSupplicantInterface *interface;
5012         GSupplicantInterfaceCallback callback;
5013         void *user_data;
5014 };
5015
5016 static void interface_mesh_change_peer_params(DBusMessageIter *iter,
5017                                                                                    void *user_data)
5018 {
5019         struct interface_mesh_peer_data *data = user_data;
5020
5021         SUPPLICANT_DBG("");
5022
5023         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->peer_address);
5024 }
5025
5026 static void interface_mesh_change_peer_result(const char *error,
5027                                 DBusMessageIter *iter, void *user_data)
5028 {
5029         struct interface_mesh_peer_data *data = user_data;
5030         int err = 0;
5031
5032         SUPPLICANT_DBG("%s", data->method);
5033
5034         if (error) {
5035                 err = -EIO;
5036                 SUPPLICANT_DBG("error %s", error);
5037         }
5038
5039         if (data->callback)
5040                 data->callback(err, data->interface, data->user_data);
5041
5042         g_free(data->peer_address);
5043         g_free(data->method);
5044         dbus_free(data);
5045 }
5046
5047 int g_supplicant_interface_mesh_peer_change_status(
5048                                 GSupplicantInterface *interface,
5049                                 GSupplicantInterfaceCallback callback, const char *peer_address,
5050                                 const char *method, void *user_data)
5051 {
5052         struct interface_mesh_peer_data *data;
5053         int ret;
5054
5055         if (!peer_address)
5056                 return -EINVAL;
5057
5058         data = dbus_malloc0(sizeof(*data));
5059         if (!data)
5060                 return -ENOMEM;
5061
5062         data->peer_address = g_strdup(peer_address);
5063         data->method = g_strdup(method);
5064         data->interface = interface;
5065         data->callback = callback;
5066         data->user_data = user_data;
5067
5068         ret = supplicant_dbus_method_call(interface->path,
5069                                                 SUPPLICANT_INTERFACE ".Interface.Mesh",
5070                                                 method, interface_mesh_change_peer_params,
5071                                                 interface_mesh_change_peer_result, data, NULL);
5072         if (ret < 0) {
5073                 g_free(data->peer_address);
5074                 g_free(data->method);
5075                 dbus_free(data);
5076         }
5077
5078         return ret;
5079 }
5080 #endif
5081
5082 int g_supplicant_interface_create(const char *ifname, const char *driver,
5083                                         const char *bridge,
5084                                         GSupplicantInterfaceCallback callback,
5085                                                         void *user_data)
5086 {
5087         struct interface_create_data *data;
5088         int ret;
5089
5090         SUPPLICANT_DBG("ifname %s", ifname);
5091
5092         if (!ifname)
5093                 return -EINVAL;
5094
5095         if (!system_available)
5096                 return -EFAULT;
5097
5098         data = dbus_malloc0(sizeof(*data));
5099         if (!data)
5100                 return -ENOMEM;
5101
5102         data->ifname = g_strdup(ifname);
5103         data->driver = g_strdup(driver);
5104         data->bridge = g_strdup(bridge);
5105         data->callback = callback;
5106         data->user_data = user_data;
5107
5108         ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
5109                                                 SUPPLICANT_INTERFACE,
5110                                                 "GetInterface",
5111                                                 interface_get_params,
5112                                                 interface_get_result, data,
5113                                                 NULL);
5114         if (ret < 0)
5115                 interface_create_data_free(data);
5116
5117         return ret;
5118 }
5119
5120 static void interface_remove_result(const char *error,
5121                                 DBusMessageIter *iter, void *user_data)
5122 {
5123         struct interface_data *data = user_data;
5124         int err;
5125
5126         if (error) {
5127                 err = -EIO;
5128                 SUPPLICANT_DBG("error: %s", error);
5129                 goto done;
5130         }
5131
5132         if (!system_available) {
5133                 err = -EFAULT;
5134                 goto done;
5135         }
5136
5137         /*
5138          * The gsupplicant interface is already freed by the InterfaceRemoved
5139          * signal callback. Simply invoke the interface_data callback.
5140          */
5141         err = 0;
5142
5143 done:
5144         g_free(data->path);
5145
5146         if (data->callback)
5147                 data->callback(err, NULL, data->user_data);
5148
5149         dbus_free(data);
5150 }
5151
5152
5153 static void interface_remove_params(DBusMessageIter *iter, void *user_data)
5154 {
5155         struct interface_data *data = user_data;
5156
5157         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
5158                                                         &data->interface->path);
5159 }
5160
5161
5162 int g_supplicant_interface_remove(GSupplicantInterface *interface,
5163                         GSupplicantInterfaceCallback callback,
5164                                                         void *user_data)
5165 {
5166         struct interface_data *data;
5167         int ret;
5168
5169         if (!interface)
5170                 return -EINVAL;
5171
5172         if (!system_available)
5173                 return -EFAULT;
5174
5175         g_supplicant_interface_cancel(interface);
5176
5177         data = dbus_malloc0(sizeof(*data));
5178         if (!data)
5179                 return -ENOMEM;
5180
5181         data->interface = interface;
5182         data->path = g_strdup(interface->path);
5183         data->callback = callback;
5184         data->user_data = user_data;
5185
5186         ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
5187                                                 SUPPLICANT_INTERFACE,
5188                                                 "RemoveInterface",
5189                                                 interface_remove_params,
5190                                                 interface_remove_result, data,
5191                                                 NULL);
5192         if (ret < 0) {
5193                 g_free(data->path);
5194                 dbus_free(data);
5195         }
5196         return ret;
5197 }
5198
5199 static void interface_scan_result(const char *error,
5200                                 DBusMessageIter *iter, void *user_data)
5201 {
5202         struct interface_scan_data *data = user_data;
5203         int err = 0;
5204
5205         if (error) {
5206                 SUPPLICANT_DBG("error %s", error);
5207                 err = -EIO;
5208         }
5209
5210         /* A non ready interface cannot send/receive anything */
5211         if (interface_exists(data->interface, data->path)) {
5212                 if (!data->interface->ready)
5213                         err = -ENOLINK;
5214         }
5215
5216         g_free(data->path);
5217
5218         if (err != 0) {
5219                 if (data->callback)
5220                         data->callback(err, data->interface, data->user_data);
5221         } else {
5222                 data->interface->scan_callback = data->callback;
5223                 data->interface->scan_data = data->user_data;
5224         }
5225
5226         if (data->scan_params)
5227                 g_supplicant_free_scan_params(data->scan_params);
5228
5229         dbus_free(data);
5230 }
5231
5232 static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq)
5233 {
5234         DBusMessageIter data;
5235         unsigned int width = 0; /* Not used by wpa_supplicant atm */
5236
5237         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data);
5238
5239         dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq);
5240         dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width);
5241
5242         dbus_message_iter_close_container(iter, &data);
5243 }
5244
5245 static void add_scan_frequencies(DBusMessageIter *iter,
5246                                                 void *user_data)
5247 {
5248         GSupplicantScanParams *scan_data = user_data;
5249         unsigned int freq;
5250         int i;
5251
5252         for (i = 0; i < scan_data->num_freqs; i++) {
5253                 freq = scan_data->freqs[i];
5254                 if (!freq)
5255                         break;
5256
5257                 add_scan_frequency(iter, freq);
5258         }
5259 }
5260
5261 static void append_ssid(DBusMessageIter *iter,
5262                         const void *ssid, unsigned int len)
5263 {
5264         DBusMessageIter array;
5265
5266         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
5267         DBUS_TYPE_BYTE_AS_STRING, &array);
5268
5269         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
5270                                                                 &ssid, len);
5271         dbus_message_iter_close_container(iter, &array);
5272 }
5273
5274 static void append_ssids(DBusMessageIter *iter, void *user_data)
5275 {
5276         GSupplicantScanParams *scan_data = user_data;
5277         GSList *list;
5278
5279         for (list = scan_data->ssids; list; list = list->next) {
5280                 struct scan_ssid *scan_ssid = list->data;
5281
5282                 append_ssid(iter, scan_ssid->ssid, scan_ssid->ssid_len);
5283         }
5284 }
5285
5286 static void supplicant_add_scan_frequency(DBusMessageIter *dict,
5287                 supplicant_dbus_array_function function,
5288                                         void *user_data)
5289 {
5290         GSupplicantScanParams *scan_params = user_data;
5291         DBusMessageIter entry, value, array;
5292         const char *key = "Channels";
5293
5294         if (scan_params->freqs && scan_params->freqs[0] != 0) {
5295                 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
5296                                                 NULL, &entry);
5297
5298                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
5299
5300                 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
5301                                         DBUS_TYPE_ARRAY_AS_STRING
5302                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
5303                                         DBUS_TYPE_UINT32_AS_STRING
5304                                         DBUS_TYPE_UINT32_AS_STRING
5305                                         DBUS_STRUCT_END_CHAR_AS_STRING,
5306                                         &value);
5307
5308                 dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
5309                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
5310                                         DBUS_TYPE_UINT32_AS_STRING
5311                                         DBUS_TYPE_UINT32_AS_STRING
5312                                         DBUS_STRUCT_END_CHAR_AS_STRING,
5313                                         &array);
5314
5315                 if (function)
5316                         function(&array, user_data);
5317
5318                 dbus_message_iter_close_container(&value, &array);
5319                 dbus_message_iter_close_container(&entry, &value);
5320                 dbus_message_iter_close_container(dict, &entry);
5321         }
5322 }
5323
5324 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
5325 {
5326         DBusMessageIter dict;
5327         const char *type = "passive";
5328         struct interface_scan_data *data = user_data;
5329
5330         supplicant_dbus_dict_open(iter, &dict);
5331
5332         if (data && data->scan_params) {
5333                 type = "active";
5334
5335                 supplicant_dbus_dict_append_basic(&dict, "Type",
5336                                         DBUS_TYPE_STRING, &type);
5337
5338 #if defined TIZEN_EXT
5339                 SUPPLICANT_DBG("[specific_scan] num_ssids %d", data->scan_params->num_ssids);
5340                 if (data->scan_params->num_ssids != 0)
5341 #endif
5342                         supplicant_dbus_dict_append_array(&dict, "SSIDs",
5343                                                 DBUS_TYPE_STRING,
5344                                                 append_ssids,
5345                                                 data->scan_params);
5346
5347                 supplicant_add_scan_frequency(&dict, add_scan_frequencies,
5348                                                 data->scan_params);
5349         } else
5350                 supplicant_dbus_dict_append_basic(&dict, "Type",
5351                                         DBUS_TYPE_STRING, &type);
5352
5353         supplicant_dbus_dict_close(iter, &dict);
5354 }
5355
5356 static int interface_ready_to_scan(GSupplicantInterface *interface)
5357 {
5358         if (!interface)
5359                 return -EINVAL;
5360
5361         if (!system_available)
5362                 return -EFAULT;
5363
5364         if (interface->scanning)
5365                 return -EALREADY;
5366
5367         switch (interface->state) {
5368         case G_SUPPLICANT_STATE_AUTHENTICATING:
5369         case G_SUPPLICANT_STATE_ASSOCIATING:
5370         case G_SUPPLICANT_STATE_ASSOCIATED:
5371         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
5372         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
5373                 return -EBUSY;
5374 #if defined TIZEN_EXT
5375         case G_SUPPLICANT_STATE_DISABLED:
5376                 return -ENOLINK;
5377         case G_SUPPLICANT_STATE_UNKNOWN:
5378 #else
5379         case G_SUPPLICANT_STATE_UNKNOWN:
5380         case G_SUPPLICANT_STATE_DISABLED:
5381 #endif
5382         case G_SUPPLICANT_STATE_DISCONNECTED:
5383         case G_SUPPLICANT_STATE_INACTIVE:
5384         case G_SUPPLICANT_STATE_SCANNING:
5385         case G_SUPPLICANT_STATE_COMPLETED:
5386                 break;
5387         }
5388
5389         return 0;
5390 }
5391
5392 #if defined TIZEN_EXT_WIFI_MESH
5393 static void interface_abort_scan_result(const char *error,
5394                                 DBusMessageIter *iter, void *user_data)
5395 {
5396         struct interface_scan_data *data = user_data;
5397         int err = 0;
5398
5399         if (error) {
5400                 SUPPLICANT_DBG("error %s", error);
5401                 err = -EIO;
5402         }
5403
5404         g_free(data->path);
5405
5406                 if (data->callback)
5407                         data->callback(err, data->interface, data->user_data);
5408
5409         dbus_free(data);
5410 }
5411
5412 int g_supplicant_interface_abort_scan(GSupplicantInterface *interface,
5413                                 GSupplicantInterfaceCallback callback, void *user_data)
5414 {
5415         struct interface_scan_data *data;
5416         int ret;
5417
5418         if (!interface->scanning)
5419                 return -EEXIST;
5420
5421         data = dbus_malloc0(sizeof(*data));
5422         if (!data)
5423                 return -ENOMEM;
5424
5425         data->interface = interface;
5426         data->path = g_strdup(interface->path);
5427         data->callback = callback;
5428         data->user_data = user_data;
5429
5430         ret = supplicant_dbus_method_call(interface->path,
5431                         SUPPLICANT_INTERFACE ".Interface", "AbortScan", NULL,
5432                         interface_abort_scan_result, data, interface);
5433
5434         if (ret < 0) {
5435                 g_free(data->path);
5436                 dbus_free(data);
5437         }
5438
5439         return ret;
5440 }
5441 #endif
5442
5443 int g_supplicant_interface_scan(GSupplicantInterface *interface,
5444                                 GSupplicantScanParams *scan_data,
5445                                 GSupplicantInterfaceCallback callback,
5446                                                         void *user_data)
5447 {
5448         struct interface_scan_data *data;
5449         int ret;
5450
5451         ret = interface_ready_to_scan(interface);
5452         if (ret)
5453                 return ret;
5454
5455         data = dbus_malloc0(sizeof(*data));
5456         if (!data)
5457                 return -ENOMEM;
5458
5459         data->interface = interface;
5460         data->path = g_strdup(interface->path);
5461 #if defined TIZEN_EXT
5462         data->interface->scan_callback = data->callback = callback;
5463         data->interface->scan_data = data->user_data = user_data;
5464 #else
5465         data->callback = callback;
5466         data->user_data = user_data;
5467 #endif
5468         data->scan_params = scan_data;
5469
5470         interface->scan_callback = callback;
5471         interface->scan_data = user_data;
5472
5473         ret = supplicant_dbus_method_call(interface->path,
5474                         SUPPLICANT_INTERFACE ".Interface", "Scan",
5475                         interface_scan_params, interface_scan_result, data,
5476                         interface);
5477
5478         if (ret < 0) {
5479                 g_free(data->path);
5480                 dbus_free(data);
5481         }
5482
5483         return ret;
5484 }
5485
5486 #if defined TIZEN_EXT
5487 static void interface_signalpoll_result(const char *error,
5488                                 DBusMessageIter *iter, void *user_data)
5489 {
5490         struct interface_signalpoll_data *data = user_data;
5491         int err = 0;
5492         dbus_int32_t maxspeed = 0;
5493         DBusMessageIter sub_iter, dict;
5494
5495         if (error) {
5496                 err = -EIO;
5497                 SUPPLICANT_DBG("error: %s", error);
5498                 goto out;
5499         }
5500
5501         dbus_message_iter_get_arg_type(iter);
5502         dbus_message_iter_recurse(iter, &sub_iter);
5503         dbus_message_iter_recurse(&sub_iter, &dict);
5504
5505         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
5506                 DBusMessageIter entry, value;
5507                 const char *key;
5508
5509                 dbus_message_iter_recurse(&dict, &entry);
5510                 dbus_message_iter_get_basic(&entry, &key);
5511                 dbus_message_iter_next(&entry);
5512                 dbus_message_iter_recurse(&entry, &value);
5513
5514                 switch (dbus_message_iter_get_arg_type(&value)) {
5515                 case DBUS_TYPE_INT32:
5516                         if (g_strcmp0(key, "linkspeed") == 0) {
5517                                 dbus_message_iter_get_basic(&value, &maxspeed);
5518                                 SUPPLICANT_DBG("linkspeed = %d", maxspeed);
5519                                 break;
5520                         }
5521                 }
5522                 dbus_message_iter_next(&dict);
5523         }
5524
5525 out:
5526         if(data->callback)
5527                 data->callback(err, maxspeed, data->user_data);
5528
5529         g_free(data->path);
5530         dbus_free(data);
5531 }
5532
5533 int g_supplicant_interface_signalpoll(GSupplicantInterface *interface,
5534                                 GSupplicantMaxSpeedCallback callback,
5535                                 void *user_data)
5536 {
5537         struct interface_signalpoll_data *data;
5538         int ret;
5539
5540         if (!interface)
5541                 return -EINVAL;
5542
5543         if (!system_available)
5544                 return -EFAULT;
5545
5546         data = dbus_malloc0(sizeof(*data));
5547         if (!data)
5548                 return -ENOMEM;
5549
5550         data->interface = interface;
5551         data->path = g_strdup(interface->path);
5552         data->callback = callback;
5553         data->user_data = user_data;
5554
5555         ret = supplicant_dbus_method_call(interface->path,
5556                         SUPPLICANT_INTERFACE ".Interface", "SignalPoll",
5557                         NULL, interface_signalpoll_result, data,
5558                         interface);
5559
5560         if (ret < 0) {
5561                 g_free(data->path);
5562                 dbus_free(data);
5563         }
5564
5565         return ret;
5566 }
5567 #endif
5568
5569 static int parse_supplicant_error(DBusMessageIter *iter)
5570 {
5571         int err = -ECONNABORTED;
5572         char *key;
5573
5574         if (!iter)
5575                 return err;
5576
5577         /* If the given passphrase is malformed wpa_s returns
5578          * "invalid message format" but this error should be interpreted as
5579          * invalid-key.
5580          */
5581         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
5582                 dbus_message_iter_get_basic(iter, &key);
5583                 if (strncmp(key, "psk", 3) == 0 ||
5584                                 strncmp(key, "wep_key", 7) == 0 ||
5585                                 strcmp(key, "invalid message format") == 0) {
5586                         err = -ENOKEY;
5587                         break;
5588                 }
5589                 dbus_message_iter_next(iter);
5590         }
5591
5592         return err;
5593 }
5594
5595 static void interface_select_network_result(const char *error,
5596                                 DBusMessageIter *iter, void *user_data)
5597 {
5598         struct interface_connect_data *data = user_data;
5599         int err;
5600
5601         SUPPLICANT_DBG("");
5602
5603         err = 0;
5604         if (error) {
5605 #if defined TIZEN_EXT
5606                 SUPPLICANT_DBG("SelectNetwork errorFreq %s", error);
5607 #else
5608                 SUPPLICANT_DBG("SelectNetwork error %s", error);
5609 #endif
5610                 err = parse_supplicant_error(iter);
5611         }
5612
5613         g_free(data->path);
5614
5615         if (data->callback)
5616                 data->callback(err, data->interface, data->user_data);
5617
5618 #if defined TIZEN_EXT
5619         g_free(data->ssid->ssid);
5620         g_free((char *)data->ssid->passphrase);
5621 #endif
5622         g_free(data->ssid);
5623         dbus_free(data);
5624 }
5625
5626 static void interface_select_network_params(DBusMessageIter *iter,
5627                                                         void *user_data)
5628 {
5629         struct interface_connect_data *data = user_data;
5630         GSupplicantInterface *interface = data->interface;
5631 #if defined TIZEN_EXT
5632         GSupplicantSSID *ssid = data->ssid;
5633 #endif
5634
5635         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
5636                                         &interface->network_path);
5637 #if defined TIZEN_EXT
5638         if (!ssid->bssid_for_connect_len)
5639                 dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &ssid->freq);
5640 #endif
5641 }
5642
5643 static void interface_add_network_result(const char *error,
5644                                 DBusMessageIter *iter, void *user_data)
5645 {
5646         struct interface_connect_data *data = user_data;
5647         GSupplicantInterface *interface = data->interface;
5648         const char *path;
5649         int err;
5650
5651         if (error)
5652                 goto error;
5653
5654         dbus_message_iter_get_basic(iter, &path);
5655         if (!path)
5656                 goto error;
5657
5658         SUPPLICANT_DBG("PATH: %s", path);
5659
5660 #if defined TIZEN_EXT
5661         if (interface->network_path)
5662                 g_free(interface->network_path);
5663 #endif
5664         interface->network_path = g_strdup(path);
5665
5666         store_network_information(interface, data->ssid);
5667
5668 #if defined TIZEN_EXT
5669         SUPPLICANT_DBG(".Interface.SelectNetworkFreq");
5670         GSupplicantSSID *ssid = data->ssid;
5671
5672         if (!ssid->bssid_for_connect_len)
5673                 supplicant_dbus_method_call(data->interface->path,
5674                                 SUPPLICANT_INTERFACE ".Interface", "SelectNetworkFreq",
5675                                 interface_select_network_params,
5676                                 interface_select_network_result, data,
5677                                 interface);
5678         else
5679                 supplicant_dbus_method_call(data->interface->path,
5680                                 SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
5681                                 interface_select_network_params,
5682                                 interface_select_network_result, data,
5683                                 interface);
5684 #else
5685         supplicant_dbus_method_call(data->interface->path,
5686                         SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
5687                         interface_select_network_params,
5688                         interface_select_network_result, data,
5689                         interface);
5690 #endif
5691
5692         return;
5693
5694 error:
5695         SUPPLICANT_DBG("AddNetwork error %s", error);
5696
5697         if (interface_exists(data->interface, data->interface->path)) {
5698                 err = parse_supplicant_error(iter);
5699                 if (data->callback)
5700                         data->callback(err, data->interface, data->user_data);
5701
5702                 g_free(interface->network_path);
5703                 interface->network_path = NULL;
5704         }
5705
5706         g_free(data->path);
5707 #if defined TIZEN_EXT
5708         g_free(data->ssid->ssid);
5709         g_free((char *)data->ssid->passphrase);
5710 #endif
5711         g_free(data->ssid);
5712         g_free(data);
5713 }
5714
5715 static void add_network_security_none(DBusMessageIter *dict)
5716 {
5717         const char *auth_alg = "OPEN";
5718
5719         supplicant_dbus_dict_append_basic(dict, "auth_alg",
5720                                         DBUS_TYPE_STRING, &auth_alg);
5721 }
5722
5723 static void add_network_security_wep(DBusMessageIter *dict,
5724                                         GSupplicantSSID *ssid)
5725 {
5726         const char *auth_alg = "OPEN SHARED";
5727         dbus_uint32_t key_index = 0;
5728
5729         supplicant_dbus_dict_append_basic(dict, "auth_alg",
5730                                         DBUS_TYPE_STRING, &auth_alg);
5731
5732         if (ssid->passphrase) {
5733                 int size = strlen(ssid->passphrase);
5734                 if (size == 10 || size == 26) {
5735                         unsigned char *key = g_try_malloc(13);
5736                         char tmp[3];
5737                         int i;
5738
5739                         memset(tmp, 0, sizeof(tmp));
5740                         if (!key)
5741                                 size = 0;
5742
5743                         for (i = 0; i < size / 2; i++) {
5744                                 memcpy(tmp, ssid->passphrase + (i * 2), 2);
5745                                 key[i] = (unsigned char) strtol(tmp, NULL, 16);
5746                         }
5747
5748                         supplicant_dbus_dict_append_fixed_array(dict,
5749                                                         "wep_key0",
5750                                                         DBUS_TYPE_BYTE,
5751                                                         &key, size / 2);
5752                         g_free(key);
5753                 } else if (size == 5 || size == 13) {
5754                         unsigned char *key = g_try_malloc(13);
5755                         int i;
5756
5757                         if (!key)
5758                                 size = 0;
5759
5760                         for (i = 0; i < size; i++)
5761                                 key[i] = (unsigned char) ssid->passphrase[i];
5762
5763                         supplicant_dbus_dict_append_fixed_array(dict,
5764                                                                 "wep_key0",
5765                                                                 DBUS_TYPE_BYTE,
5766                                                                 &key, size);
5767                         g_free(key);
5768                 } else
5769                         supplicant_dbus_dict_append_basic(dict,
5770                                                         "wep_key0",
5771                                                         DBUS_TYPE_STRING,
5772                                                         &ssid->passphrase);
5773
5774                 supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx",
5775                                         DBUS_TYPE_UINT32, &key_index);
5776         }
5777 }
5778
5779 static dbus_bool_t is_psk_raw_key(const char *psk)
5780 {
5781         int i;
5782
5783         /* A raw key is always 64 bytes length... */
5784         if (strlen(psk) != 64)
5785                 return FALSE;
5786
5787         /* ... and its content is in hex representation */
5788         for (i = 0; i < 64; i++)
5789                 if (!isxdigit((unsigned char) psk[i]))
5790                         return FALSE;
5791
5792         return TRUE;
5793 }
5794
5795 static unsigned char hexchar2bin(char c)
5796 {
5797         if ((c >= '0') && (c <= '9'))
5798                 return c - '0';
5799         else if ((c >= 'A') && (c <= 'F'))
5800                 return c - 'A' + 10;
5801         else if ((c >= 'a') && (c <= 'f'))
5802                 return c - 'a' + 10;
5803         else
5804                 return c;
5805 }
5806
5807 static void hexstring2bin(const char *string, unsigned char *data,
5808                                 size_t data_len)
5809 {
5810         size_t i;
5811
5812         for (i = 0; i < data_len; i++)
5813                 data[i] = (hexchar2bin(string[i * 2 + 0]) << 4 |
5814                            hexchar2bin(string[i * 2 + 1]) << 0);
5815 }
5816
5817 static void add_network_security_psk(DBusMessageIter *dict,
5818                                         GSupplicantSSID *ssid)
5819 {
5820         if (ssid->passphrase && strlen(ssid->passphrase) > 0) {
5821                 const char *key = "psk";
5822
5823                 if (is_psk_raw_key(ssid->passphrase)) {
5824                         unsigned char data[32];
5825                         unsigned char *datap = data;
5826
5827                         /* The above pointer alias is required by D-Bus because
5828                          * with D-Bus and GCC, non-heap-allocated arrays cannot
5829                          * be passed directly by their base pointer. */
5830
5831                         hexstring2bin(ssid->passphrase, datap, sizeof(data));
5832
5833                         supplicant_dbus_dict_append_fixed_array(dict,
5834                                                         key, DBUS_TYPE_BYTE,
5835                                                         &datap, sizeof(data));
5836                 } else
5837                         supplicant_dbus_dict_append_basic(dict,
5838                                                         key, DBUS_TYPE_STRING,
5839                                                         &ssid->passphrase);
5840         }
5841 }
5842
5843 static void add_network_security_tls(DBusMessageIter *dict,
5844                                         GSupplicantSSID *ssid)
5845 {
5846         /*
5847          * For TLS, we at least need:
5848          *              The client certificate
5849          *              The client private key file
5850          *              The client private key file password
5851          *
5852          * The Authority certificate is optional.
5853          */
5854         if (!ssid->client_cert_path)
5855                 return;
5856
5857         if (!ssid->private_key_path)
5858                 return;
5859
5860 #if !defined TIZEN_EXT
5861         if (!ssid->private_key_passphrase)
5862                 return;
5863 #endif
5864
5865         if (ssid->ca_cert_path)
5866                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
5867                                         DBUS_TYPE_STRING, &ssid->ca_cert_path);
5868
5869         supplicant_dbus_dict_append_basic(dict, "private_key",
5870                                                 DBUS_TYPE_STRING,
5871                                                 &ssid->private_key_path);
5872 #if !defined TIZEN_EXT
5873         supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
5874                                                 DBUS_TYPE_STRING,
5875                                                 &ssid->private_key_passphrase);
5876 #endif
5877         supplicant_dbus_dict_append_basic(dict, "client_cert",
5878                                                 DBUS_TYPE_STRING,
5879                                                 &ssid->client_cert_path);
5880 }
5881
5882 static void add_network_security_peap(DBusMessageIter *dict,
5883                                         GSupplicantSSID *ssid)
5884 {
5885         char *phase2_auth;
5886
5887         /*
5888          * For PEAP/TTLS, we at least need
5889          *              The authority certificate
5890          *              The 2nd phase authentication method
5891          *              The 2nd phase passphrase
5892          *
5893          * The Client certificate is optional although strongly recommended
5894          * When setting it, we need in addition
5895          *              The Client private key file
5896          *              The Client private key file password
5897          */
5898         if (!ssid->passphrase)
5899                 return;
5900
5901         if (!ssid->phase2_auth)
5902                 return;
5903
5904         if (ssid->client_cert_path) {
5905                 if (!ssid->private_key_path)
5906                         return;
5907
5908 #if !defined TIZEN_EXT
5909                 if (!ssid->private_key_passphrase)
5910                         return;
5911 #endif
5912
5913                 supplicant_dbus_dict_append_basic(dict, "client_cert",
5914                                                 DBUS_TYPE_STRING,
5915                                                 &ssid->client_cert_path);
5916
5917                 supplicant_dbus_dict_append_basic(dict, "private_key",
5918                                                 DBUS_TYPE_STRING,
5919                                                 &ssid->private_key_path);
5920
5921 #if !defined TIZEN_EXT
5922                 supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
5923                                                 DBUS_TYPE_STRING,
5924                                                 &ssid->private_key_passphrase);
5925 #endif
5926
5927         }
5928
5929         if (g_str_has_prefix(ssid->phase2_auth, "EAP-")) {
5930                 phase2_auth = g_strdup_printf("autheap=%s",
5931                                         ssid->phase2_auth + strlen("EAP-"));
5932         } else
5933                 phase2_auth = g_strdup_printf("auth=%s", ssid->phase2_auth);
5934
5935         supplicant_dbus_dict_append_basic(dict, "password",
5936                                                 DBUS_TYPE_STRING,
5937                                                 &ssid->passphrase);
5938
5939         if (ssid->ca_cert_path)
5940                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
5941                                                 DBUS_TYPE_STRING,
5942                                                 &ssid->ca_cert_path);
5943
5944         supplicant_dbus_dict_append_basic(dict, "phase2",
5945                                                 DBUS_TYPE_STRING,
5946                                                 &phase2_auth);
5947
5948         g_free(phase2_auth);
5949 }
5950
5951 #if defined TIZEN_EXT
5952 static void add_network_security_aka_sim(DBusMessageIter *dict,
5953                                         GSupplicantSSID *ssid)
5954 {
5955         if (!ssid->passphrase)
5956                 return;
5957
5958         supplicant_dbus_dict_append_basic(dict, "password",
5959                         DBUS_TYPE_STRING,
5960                         &ssid->passphrase);
5961 }
5962
5963 static void add_network_security_fast(DBusMessageIter *dict,
5964                 GSupplicantSSID *ssid)
5965 {
5966         /*
5967          * For FAST, we at least need:
5968          *              id / password
5969          *              phase1 (provisiong information)
5970          *              pac_file
5971          */
5972
5973         /* Allow provisioing both authenticated and unauthenticated */
5974         const char *phase1 = "fast_provisioning=2";
5975         supplicant_dbus_dict_append_basic(dict, "phase1",
5976                         DBUS_TYPE_STRING,
5977                         &phase1);
5978
5979         SUPPLICANT_DBG("pac_file [%s]", ssid->pac_file);
5980         if(ssid->pac_file)
5981                 supplicant_dbus_dict_append_basic(dict, "pac_file",
5982                                 DBUS_TYPE_STRING,
5983                                 &ssid->pac_file);
5984
5985         supplicant_dbus_dict_append_basic(dict, "password",
5986                         DBUS_TYPE_STRING,
5987                         &ssid->passphrase);
5988 }
5989 #endif
5990
5991 static void add_network_security_eap(DBusMessageIter *dict,
5992                                         GSupplicantSSID *ssid)
5993 {
5994         char *eap_value;
5995
5996 #if defined TIZEN_EXT
5997         if (!ssid->eap)
5998 #else
5999         if (!ssid->eap || !ssid->identity)
6000 #endif
6001                 return;
6002
6003         if (g_strcmp0(ssid->eap, "tls") == 0) {
6004                 add_network_security_tls(dict, ssid);
6005         } else if (g_strcmp0(ssid->eap, "peap") == 0 ||
6006                                 g_strcmp0(ssid->eap, "ttls") == 0) {
6007 #if defined TIZEN_EXT
6008                 if (!ssid->identity)
6009                         return;
6010 #endif
6011                 add_network_security_peap(dict, ssid);
6012
6013 #if defined TIZEN_EXT
6014         } else if (g_strcmp0(ssid->eap, "sim") == 0 ||
6015                         g_strcmp0(ssid->eap, "aka") == 0 ||
6016                         g_strcmp0(ssid->eap, "aka'") == 0) {
6017                 add_network_security_aka_sim(dict, ssid);
6018         } else if (g_strcmp0(ssid->eap, "pwd") == 0) {
6019                 if(!ssid->passphrase)
6020                         return;
6021                 supplicant_dbus_dict_append_basic(dict, "password",
6022                                 DBUS_TYPE_STRING,
6023                                 &ssid->passphrase);
6024         } else if (g_strcmp0(ssid->eap, "fast") == 0){
6025                 if (!ssid->identity || !ssid->passphrase)
6026                         return;
6027
6028                 add_network_security_fast(dict, ssid);
6029 #endif
6030         } else
6031                 return;
6032
6033         eap_value = g_ascii_strup(ssid->eap, -1);
6034
6035         supplicant_dbus_dict_append_basic(dict, "eap",
6036                                                 DBUS_TYPE_STRING,
6037                                                 &eap_value);
6038 #if defined TIZEN_EXT
6039         if (ssid->identity != NULL)
6040                 supplicant_dbus_dict_append_basic(dict, "identity",
6041                                                         DBUS_TYPE_STRING,
6042                                                         &ssid->identity);
6043 #else
6044         supplicant_dbus_dict_append_basic(dict, "identity",
6045                                                 DBUS_TYPE_STRING,
6046                                                 &ssid->identity);
6047 #endif
6048         if(ssid->anonymous_identity)
6049                 supplicant_dbus_dict_append_basic(dict, "anonymous_identity",
6050                                                      DBUS_TYPE_STRING,
6051                                                      &ssid->anonymous_identity);
6052
6053         if(ssid->subject_match)
6054                 supplicant_dbus_dict_append_basic(dict, "subject_match",
6055                                                      DBUS_TYPE_STRING,
6056                                                      &ssid->subject_match);
6057
6058         if(ssid->altsubject_match)
6059                 supplicant_dbus_dict_append_basic(dict, "altsubject_match",
6060                                                      DBUS_TYPE_STRING,
6061                                                      &ssid->altsubject_match);
6062
6063         if(ssid->domain_suffix_match)
6064                 supplicant_dbus_dict_append_basic(dict, "domain_suffix_match",
6065                                                      DBUS_TYPE_STRING,
6066                                                      &ssid->domain_suffix_match);
6067
6068         if(ssid->domain_match)
6069                 supplicant_dbus_dict_append_basic(dict, "domain_match",
6070                                                      DBUS_TYPE_STRING,
6071                                                      &ssid->domain_match);
6072
6073         g_free(eap_value);
6074 }
6075
6076 static void add_network_security_ciphers(DBusMessageIter *dict,
6077                                                 GSupplicantSSID *ssid)
6078 {
6079         unsigned int p_cipher, g_cipher, i;
6080         char *pairwise, *group;
6081         char *pair_ciphers[4];
6082         char *group_ciphers[5];
6083
6084         p_cipher = ssid->pairwise_cipher;
6085         g_cipher = ssid->group_cipher;
6086
6087         if (p_cipher == 0 && g_cipher == 0)
6088                 return;
6089
6090         i = 0;
6091
6092         if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP)
6093                 pair_ciphers[i++] = "CCMP";
6094
6095         if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP)
6096                 pair_ciphers[i++] = "TKIP";
6097
6098         if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE)
6099                 pair_ciphers[i++] = "NONE";
6100
6101         pair_ciphers[i] = NULL;
6102
6103         i = 0;
6104
6105         if (g_cipher & G_SUPPLICANT_GROUP_CCMP)
6106                 group_ciphers[i++] = "CCMP";
6107
6108         if (g_cipher & G_SUPPLICANT_GROUP_TKIP)
6109                 group_ciphers[i++] = "TKIP";
6110
6111         if (g_cipher & G_SUPPLICANT_GROUP_WEP104)
6112                 group_ciphers[i++] = "WEP104";
6113
6114         if (g_cipher & G_SUPPLICANT_GROUP_WEP40)
6115                 group_ciphers[i++] = "WEP40";
6116
6117         group_ciphers[i] = NULL;
6118
6119         pairwise = g_strjoinv(" ", pair_ciphers);
6120         group = g_strjoinv(" ", group_ciphers);
6121
6122         SUPPLICANT_DBG("cipher %s %s", pairwise, group);
6123
6124         supplicant_dbus_dict_append_basic(dict, "pairwise",
6125                                                 DBUS_TYPE_STRING,
6126                                                 &pairwise);
6127         supplicant_dbus_dict_append_basic(dict, "group",
6128                                                 DBUS_TYPE_STRING,
6129                                                 &group);
6130
6131         g_free(pairwise);
6132         g_free(group);
6133 }
6134
6135 static void add_network_security_proto(DBusMessageIter *dict,
6136                                                 GSupplicantSSID *ssid)
6137 {
6138         unsigned int protocol, i;
6139         char *proto;
6140         char *protos[3];
6141
6142         protocol = ssid->protocol;
6143
6144         if (protocol == 0)
6145                 return;
6146
6147         i = 0;
6148
6149         if (protocol & G_SUPPLICANT_PROTO_RSN)
6150                 protos[i++] = "RSN";
6151
6152         if (protocol & G_SUPPLICANT_PROTO_WPA)
6153                 protos[i++] = "WPA";
6154
6155         protos[i] = NULL;
6156
6157         proto = g_strjoinv(" ", protos);
6158
6159         SUPPLICANT_DBG("proto %s", proto);
6160
6161         supplicant_dbus_dict_append_basic(dict, "proto",
6162                                                 DBUS_TYPE_STRING,
6163                                                 &proto);
6164
6165         g_free(proto);
6166 }
6167
6168 #if defined TIZEN_EXT_WIFI_MESH
6169 static void add_network_ieee80211w(DBusMessageIter *dict, GSupplicantSSID *ssid)
6170 {
6171         if (ssid->security != G_SUPPLICANT_SECURITY_SAE)
6172                 return;
6173
6174         supplicant_dbus_dict_append_basic(dict, "ieee80211w", DBUS_TYPE_UINT32,
6175                                           &ssid->ieee80211w);
6176 }
6177 #endif
6178
6179 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
6180 {
6181         char *key_mgmt;
6182
6183         switch (ssid->security) {
6184         case G_SUPPLICANT_SECURITY_NONE:
6185                 key_mgmt = "NONE";
6186                 add_network_security_none(dict);
6187                 add_network_security_ciphers(dict, ssid);
6188                 break;
6189         case G_SUPPLICANT_SECURITY_UNKNOWN:
6190         case G_SUPPLICANT_SECURITY_WEP:
6191                 key_mgmt = "NONE";
6192                 add_network_security_wep(dict, ssid);
6193                 add_network_security_ciphers(dict, ssid);
6194                 break;
6195         case G_SUPPLICANT_SECURITY_PSK:
6196                 key_mgmt = "WPA-PSK";
6197                 add_network_security_psk(dict, ssid);
6198                 add_network_security_ciphers(dict, ssid);
6199                 add_network_security_proto(dict, ssid);
6200                 break;
6201         case G_SUPPLICANT_SECURITY_IEEE8021X:
6202                 key_mgmt = "WPA-EAP";
6203                 add_network_security_eap(dict, ssid);
6204                 add_network_security_ciphers(dict, ssid);
6205                 add_network_security_proto(dict, ssid);
6206                 break;
6207 #if defined TIZEN_EXT
6208         case G_SUPPLICANT_SECURITY_FT_PSK:
6209                 key_mgmt = "FT-PSK";
6210                 add_network_security_psk(dict, ssid);
6211                 add_network_security_ciphers(dict, ssid);
6212                 add_network_security_proto(dict, ssid);
6213                 break;
6214         case G_SUPPLICANT_SECURITY_FT_IEEE8021X:
6215                 key_mgmt = "FT-EAP";
6216                 add_network_security_eap(dict, ssid);
6217                 add_network_security_ciphers(dict, ssid);
6218                 add_network_security_proto(dict, ssid);
6219                 break;
6220 #endif
6221 #if defined TIZEN_EXT_WIFI_MESH
6222         case G_SUPPLICANT_SECURITY_SAE:
6223                 key_mgmt = "SAE";
6224                 add_network_security_psk(dict, ssid);
6225                 break;
6226 #endif
6227         }
6228
6229         supplicant_dbus_dict_append_basic(dict, "key_mgmt",
6230                                 DBUS_TYPE_STRING, &key_mgmt);
6231 }
6232
6233 static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid)
6234 {
6235         dbus_uint32_t mode;
6236
6237         switch (ssid->mode) {
6238         case G_SUPPLICANT_MODE_UNKNOWN:
6239         case G_SUPPLICANT_MODE_INFRA:
6240                 mode = 0;
6241                 break;
6242         case G_SUPPLICANT_MODE_IBSS:
6243                 mode = 1;
6244                 break;
6245         case G_SUPPLICANT_MODE_MASTER:
6246                 mode = 2;
6247                 break;
6248 #if defined TIZEN_EXT_WIFI_MESH
6249         case G_SUPPLICANT_MODE_MESH:
6250                 mode = 5;
6251                 break;
6252 #endif
6253         }
6254
6255         supplicant_dbus_dict_append_basic(dict, "mode",
6256                                 DBUS_TYPE_UINT32, &mode);
6257 }
6258
6259 static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
6260 {
6261         DBusMessageIter dict;
6262         struct interface_connect_data *data = user_data;
6263         GSupplicantSSID *ssid = data->ssid;
6264
6265         supplicant_dbus_dict_open(iter, &dict);
6266
6267         if (ssid->scan_ssid)
6268                 supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
6269                                          DBUS_TYPE_UINT32, &ssid->scan_ssid);
6270
6271         if (ssid->freq)
6272                 supplicant_dbus_dict_append_basic(&dict, "frequency",
6273                                          DBUS_TYPE_UINT32, &ssid->freq);
6274
6275         if (ssid->bgscan)
6276                 supplicant_dbus_dict_append_basic(&dict, "bgscan",
6277                                         DBUS_TYPE_STRING, &ssid->bgscan);
6278
6279         add_network_mode(&dict, ssid);
6280
6281         add_network_security(&dict, ssid);
6282
6283 #if defined TIZEN_EXT_WIFI_MESH
6284         add_network_ieee80211w(&dict, ssid);
6285 #endif
6286
6287         supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
6288                                         DBUS_TYPE_BYTE, &ssid->ssid,
6289                                                 ssid->ssid_len);
6290
6291         supplicant_dbus_dict_append_basic(&dict, "ignore_broadcast_ssid",
6292                                         DBUS_TYPE_INT32,
6293                                         &ssid->ignore_broadcast_ssid);
6294
6295 #if defined TIZEN_EXT
6296         if (ssid->bssid) {
6297                 char *bssid = NULL;
6298                 bssid = g_try_malloc0(18);
6299                 if (bssid == NULL) {
6300                         SUPPLICANT_DBG("memory allocation error");
6301                         supplicant_dbus_dict_close(iter, &dict);
6302                         return;
6303                 }
6304
6305                 if (ssid->bssid_for_connect_len)
6306                         snprintf(bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
6307                                         ssid->bssid_for_connect[0], ssid->bssid_for_connect[1], ssid->bssid_for_connect[2],
6308                                         ssid->bssid_for_connect[3], ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
6309                 else
6310                         snprintf(bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
6311                                         ssid->bssid[0], ssid->bssid[1], ssid->bssid[2],
6312                                         ssid->bssid[3], ssid->bssid[4], ssid->bssid[5]);
6313
6314                 supplicant_dbus_dict_append_basic(&dict, "bssid",
6315                                         DBUS_TYPE_STRING, &bssid);
6316                 g_free(bssid);
6317         }
6318 #endif
6319
6320         supplicant_dbus_dict_close(iter, &dict);
6321 }
6322
6323 static void interface_wps_start_result(const char *error,
6324                                 DBusMessageIter *iter, void *user_data)
6325 {
6326         struct interface_connect_data *data = user_data;
6327         int err;
6328
6329         SUPPLICANT_DBG("");
6330
6331         err = 0;
6332         if (error) {
6333                 SUPPLICANT_DBG("error: %s", error);
6334                 err = parse_supplicant_error(iter);
6335         }
6336
6337         if(data->callback)
6338                 data->callback(err, data->interface, data->user_data);
6339
6340         g_free(data->path);
6341         g_free(data->ssid);
6342         dbus_free(data);
6343 }
6344
6345 static void interface_add_wps_params(DBusMessageIter *iter, void *user_data)
6346 {
6347         struct interface_connect_data *data = user_data;
6348         GSupplicantSSID *ssid = data->ssid;
6349         const char *role = "enrollee", *type;
6350         DBusMessageIter dict;
6351
6352         SUPPLICANT_DBG("");
6353
6354         supplicant_dbus_dict_open(iter, &dict);
6355
6356         supplicant_dbus_dict_append_basic(&dict, "Role",
6357                                                 DBUS_TYPE_STRING, &role);
6358
6359         type = "pbc";
6360         if (ssid->pin_wps) {
6361                 type = "pin";
6362                 supplicant_dbus_dict_append_basic(&dict, "Pin",
6363                                         DBUS_TYPE_STRING, &ssid->pin_wps);
6364         }
6365
6366         supplicant_dbus_dict_append_basic(&dict, "Type",
6367                                         DBUS_TYPE_STRING, &type);
6368
6369 #if defined TIZEN_EXT
6370         if (ssid->bssid)
6371                 supplicant_dbus_dict_append_fixed_array(&dict, "Bssid",
6372                                                 DBUS_TYPE_BYTE, &ssid->bssid, 6);
6373 #endif
6374
6375         supplicant_dbus_dict_close(iter, &dict);
6376 }
6377
6378 static void wps_start(const char *error, DBusMessageIter *iter, void *user_data)
6379 {
6380         struct interface_connect_data *data = user_data;
6381
6382         SUPPLICANT_DBG("");
6383
6384         if (error) {
6385                 SUPPLICANT_DBG("error: %s", error);
6386                 g_free(data->path);
6387                 g_free(data->ssid);
6388                 dbus_free(data);
6389                 return;
6390         }
6391 #if defined TIZEN_EXT
6392         GSupplicantSSID *ssid = data->ssid;
6393         if (ssid->pin_wps != NULL) {
6394                 if (!g_utf8_validate(ssid->pin_wps, 8, NULL)) {
6395                         SUPPLICANT_DBG("Invalid characters in WPS_PIN");
6396                         g_free(data->ssid);
6397                         dbus_free(data);
6398                         return;
6399                 }
6400         }
6401 #endif
6402         supplicant_dbus_method_call(data->interface->path,
6403                         SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
6404                         interface_add_wps_params,
6405                         interface_wps_start_result, data, NULL);
6406 }
6407
6408 static void wps_process_credentials(DBusMessageIter *iter, void *user_data)
6409 {
6410         dbus_bool_t credentials = TRUE;
6411
6412         SUPPLICANT_DBG("");
6413
6414         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials);
6415 }
6416
6417
6418 #if defined TIZEN_EXT
6419 #define NETCONFIG_SERVICE "net.netconfig"
6420 #define NETCONFIG_WIFI_PATH "/net/netconfig/wifi"
6421 #define NETCONFIG_WIFI_INTERFACE NETCONFIG_SERVICE ".wifi"
6422
6423 struct dec_method_call_data {
6424         struct interface_connect_data *data;
6425         DBusPendingCall *pending_call;
6426 };
6427
6428 static struct dec_method_call_data decrypt_request_data;
6429
6430 static void crypt_method_call_cancel(void)
6431 {
6432         if (decrypt_request_data.pending_call) {
6433                 dbus_pending_call_cancel(decrypt_request_data.pending_call);
6434                 dbus_pending_call_unref(decrypt_request_data.pending_call);
6435                 decrypt_request_data.pending_call = NULL;
6436         }
6437
6438         g_free(decrypt_request_data.data->path);
6439         g_free(decrypt_request_data.data->ssid);
6440         dbus_free(decrypt_request_data.data);
6441         decrypt_request_data.data = NULL;
6442 }
6443
6444 static void decryption_request_reply(DBusPendingCall *call,
6445                                                 void *user_data)
6446 {
6447         DBusMessage *reply;
6448         DBusError error;
6449         DBusMessageIter args;
6450         char *out_data;
6451         int ret;
6452         struct interface_connect_data *data = user_data;
6453
6454         SUPPLICANT_DBG("");
6455
6456         reply = dbus_pending_call_steal_reply(call);
6457
6458         dbus_error_init(&error);
6459         if (dbus_set_error_from_message(&error, reply)) {
6460                 SUPPLICANT_DBG("decryption_request_reply() %s %s", error.name, error.message);
6461                 dbus_error_free(&error);
6462                 ret = -EINVAL;
6463                 goto done;
6464         }
6465
6466         if (dbus_message_iter_init(reply, &args) == FALSE) {
6467                 SUPPLICANT_DBG("dbus_message_iter_init() failed");
6468                 ret = -EINVAL;
6469                 goto done;
6470         }
6471
6472         dbus_message_iter_get_basic(&args, &out_data);
6473         data->ssid->passphrase = g_strdup((const gchar *)out_data);
6474
6475         ret = supplicant_dbus_method_call(data->interface->path,
6476                 SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
6477                 interface_add_network_params,
6478                 interface_add_network_result, data,
6479                 data->interface);
6480
6481 done:
6482         if (ret < 0) {
6483                 SUPPLICANT_DBG("AddNetwork failed %d", ret);
6484                 callback_assoc_failed(decrypt_request_data.data->user_data);
6485                 g_free(data->path);
6486                 g_free(data->ssid->ssid);
6487                 g_free((char *)data->ssid->passphrase);
6488                 g_free(data->ssid);
6489                 dbus_free(data);
6490         }
6491
6492         dbus_message_unref(reply);
6493         dbus_pending_call_unref(call);
6494
6495         decrypt_request_data.pending_call = NULL;
6496         decrypt_request_data.data = NULL;
6497 }
6498
6499 static int send_decryption_request(const char *passphrase,
6500                         struct interface_connect_data *data)
6501 {
6502         DBusMessage *msg = NULL;
6503         DBusPendingCall *call;
6504
6505         SUPPLICANT_DBG("Decryption request");
6506
6507         if (!passphrase) {
6508                 SUPPLICANT_DBG("Invalid parameter");
6509                 return -EINVAL;
6510         }
6511
6512         if (!connection)
6513                 return -EINVAL;
6514
6515         msg = dbus_message_new_method_call(NETCONFIG_SERVICE, NETCONFIG_WIFI_PATH,
6516                         NETCONFIG_WIFI_INTERFACE, "DecryptPassphrase");
6517         if (!msg)
6518                 return -EINVAL;
6519
6520         dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase,
6521                                                         DBUS_TYPE_INVALID);
6522
6523         if (!dbus_connection_send_with_reply(connection, msg,
6524                                 &call, DBUS_TIMEOUT_USE_DEFAULT)) {
6525                 dbus_message_unref(msg);
6526                 return -EIO;
6527         }
6528
6529         if (!call) {
6530                 dbus_message_unref(msg);
6531                 return -EIO;
6532         }
6533
6534         decrypt_request_data.pending_call = call;
6535         decrypt_request_data.data = data;
6536
6537         dbus_pending_call_set_notify(call, decryption_request_reply, data, NULL);
6538         dbus_message_unref(msg);
6539
6540         SUPPLICANT_DBG("Decryption request succeeded");
6541
6542         return 0;
6543 }
6544 #endif
6545
6546 int g_supplicant_interface_connect(GSupplicantInterface *interface,
6547                                 GSupplicantSSID *ssid,
6548                                 GSupplicantInterfaceCallback callback,
6549                                                         void *user_data)
6550 {
6551         struct interface_connect_data *data;
6552         struct interface_data *intf_data;
6553         int ret = 0;
6554
6555         SUPPLICANT_DBG("");
6556
6557         if (!interface)
6558                 return -EINVAL;
6559
6560         if (!system_available)
6561                 return -EFAULT;
6562
6563         /* TODO: Check if we're already connected and switch */
6564
6565         data = dbus_malloc0(sizeof(*data));
6566         if (!data)
6567                 return -ENOMEM;
6568
6569         data->interface = interface;
6570         data->path = g_strdup(interface->path);
6571         data->callback = callback;
6572         data->ssid = ssid;
6573         data->user_data = user_data;
6574
6575         if (ssid->use_wps) {
6576                 g_free(interface->wps_cred.key);
6577                 memset(&interface->wps_cred, 0,
6578                                 sizeof(struct _GSupplicantWpsCredentials));
6579
6580                 ret = supplicant_dbus_property_set(interface->path,
6581                         SUPPLICANT_INTERFACE ".Interface.WPS",
6582                         "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
6583                         wps_process_credentials, wps_start, data, interface);
6584         } else {
6585                 /* By the time there is a request for connect and the network
6586                  * path is not NULL it means that connman has not removed the
6587                  * previous network pointer. This can happen in the case AP
6588                  * deauthenticated client and connman does not remove the
6589                  * previously connected network pointer. This causes supplicant
6590                  * to reallocate the memory for struct wpa_ssid again even if it
6591                  * is the same SSID. This causes memory usage of wpa_supplicnat
6592                  * to go high. The idea here is that if the previously connected
6593                  * network is not removed at the time of next connection attempt
6594                  * check if the network path is not NULL. In case it is non-NULL
6595                  * first remove the network and then once removal is successful, add
6596                  * the network.
6597                  */
6598
6599                 if (interface->network_path != NULL) {
6600                         g_free(data->path);
6601                         dbus_free(data);
6602
6603                         /*
6604                          * If this add network is for the same network for
6605                          * which wpa_supplicant already has a profile then do
6606                          * not need to add another profile. Only if the
6607                          * profile that needs to get added is different from
6608                          * what is there in wpa_s delete the current one. A
6609                          * network is identified by its SSID, security_type
6610                          * and passphrase (private passphrase in case security
6611                          * type is 802.11x).
6612                          */
6613                         if (compare_network_parameters(interface, ssid)) {
6614                                 return -EALREADY;
6615                         }
6616
6617                         intf_data = dbus_malloc0(sizeof(*intf_data));
6618                         if (!intf_data)
6619                                 return -ENOMEM;
6620
6621                         intf_data->interface = interface;
6622                         intf_data->path = g_strdup(interface->path);
6623                         intf_data->callback = callback;
6624                         intf_data->ssid = ssid;
6625                         intf_data->user_data = user_data;
6626                         intf_data->network_remove_in_progress = TRUE;
6627                         network_remove(intf_data);
6628                 } else
6629 #if defined TIZEN_EXT
6630                         if (ssid->passphrase &&
6631                             g_strcmp0(ssid->passphrase, "") != 0 &&
6632 #if defined TIZEN_EXT_WIFI_MESH
6633                             ssid->mode != G_SUPPLICANT_MODE_MESH &&
6634 #endif
6635                             !ssid->eap) {
6636                                 ret = send_decryption_request(ssid->passphrase, data);
6637                                 if (ret < 0)
6638                                         SUPPLICANT_DBG("Decryption request failed %d", ret);
6639                         } else
6640 #endif
6641                                 ret = supplicant_dbus_method_call(interface->path,
6642                                                 SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
6643                                                 interface_add_network_params,
6644                                                 interface_add_network_result, data,
6645                                                 interface);
6646         }
6647
6648         if (ret < 0) {
6649                 g_free(data->path);
6650                 dbus_free(data);
6651                 return ret;
6652         }
6653
6654         return -EINPROGRESS;
6655 }
6656
6657 static void network_remove_result(const char *error,
6658                                 DBusMessageIter *iter, void *user_data)
6659 {
6660         struct interface_data *data = user_data;
6661         struct interface_connect_data *connect_data;
6662         int result = 0;
6663
6664         SUPPLICANT_DBG("");
6665
6666         if (error) {
6667                 result = -EIO;
6668                 SUPPLICANT_DBG("error: %s", error);
6669
6670                 if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
6671                                                 error) == 0)
6672                         result = -ECONNABORTED;
6673         }
6674
6675         g_free(data->interface->network_path);
6676         data->interface->network_path = NULL;
6677
6678         remove_network_information(data->interface);
6679
6680         if (data->network_remove_in_progress == TRUE) {
6681                 data->network_remove_in_progress = FALSE;
6682                 connect_data = dbus_malloc0(sizeof(*connect_data));
6683                 if (!connect_data)
6684                         return;
6685
6686                 connect_data->interface = data->interface;
6687                 connect_data->path = g_strdup(data->path);
6688                 connect_data->callback = data->callback;
6689                 connect_data->ssid = data->ssid;
6690                 connect_data->user_data = data->user_data;
6691
6692 #if defined TIZEN_EXT
6693                 int ret;
6694                 if (data->ssid->passphrase && g_strcmp0(data->ssid->passphrase, "") != 0
6695                         && !data->ssid->eap) {
6696                         ret = send_decryption_request(data->ssid->passphrase, connect_data);
6697                         if (ret < 0) {
6698                                 SUPPLICANT_DBG("Decryption request failed %d", ret);
6699                                 g_free(connect_data->ssid);
6700                                 g_free(connect_data->path);
6701                                 dbus_free(connect_data);
6702                         }
6703                 } else
6704 #endif
6705                 supplicant_dbus_method_call(data->interface->path,
6706                         SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
6707                         interface_add_network_params,
6708                         interface_add_network_result, connect_data,
6709                         connect_data->interface);
6710         } else {
6711                 if (data->callback)
6712                         data->callback(result, data->interface, data->user_data);
6713         }
6714         g_free(data->path);
6715         dbus_free(data);
6716 }
6717
6718 static void network_remove_params(DBusMessageIter *iter, void *user_data)
6719 {
6720         struct interface_data *data = user_data;
6721         const char *path = data->interface->network_path;
6722
6723         SUPPLICANT_DBG("path %s", path);
6724
6725         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
6726 }
6727
6728 static int network_remove(struct interface_data *data)
6729 {
6730         GSupplicantInterface *interface = data->interface;
6731
6732         SUPPLICANT_DBG("");
6733
6734 #if defined TIZEN_EXT
6735         GSupplicantInterface *intf = NULL;
6736         /*
6737          * Check if 'interface' is valid
6738          */
6739         intf = g_hash_table_lookup(interface_table, interface->path);
6740         if (intf == NULL)
6741                 return -EINVAL;
6742 #endif
6743
6744         return supplicant_dbus_method_call(interface->path,
6745                         SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
6746                         network_remove_params, network_remove_result, data,
6747                         interface);
6748 }
6749
6750 static void interface_disconnect_result(const char *error,
6751                                 DBusMessageIter *iter, void *user_data)
6752 {
6753         struct interface_data *data = user_data;
6754         int result = 0;
6755
6756         SUPPLICANT_DBG("");
6757
6758         if (error) {
6759                 result = -EIO;
6760                 SUPPLICANT_DBG("error: %s", error);
6761
6762                 if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
6763                                                 error) == 0)
6764                         result = -ECONNABORTED;
6765         }
6766
6767         /* If we are disconnecting from previous WPS successful
6768          * association. i.e.: it did not went through AddNetwork,
6769          * and interface->network_path was never set. */
6770         if (!data->interface->network_path) {
6771                 if (data->callback)
6772                         data->callback(result, data->interface,
6773                                                         data->user_data);
6774
6775                 g_free(data->path);
6776                 dbus_free(data);
6777                 return;
6778         }
6779
6780         if (result < 0 && data->callback) {
6781                 data->callback(result, data->interface, data->user_data);
6782                 data->callback = NULL;
6783         }
6784
6785         if (result != -ECONNABORTED) {
6786                 if (network_remove(data) < 0) {
6787                         g_free(data->path);
6788                         dbus_free(data);
6789                 }
6790         } else {
6791                 g_free(data->path);
6792                 dbus_free(data);
6793         }
6794 }
6795
6796 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
6797                                         GSupplicantInterfaceCallback callback,
6798                                                         void *user_data)
6799 {
6800         struct interface_data *data;
6801         int ret;
6802
6803         SUPPLICANT_DBG("");
6804
6805         if (!interface)
6806                 return -EINVAL;
6807
6808         if (!system_available)
6809                 return -EFAULT;
6810 #if defined TIZEN_EXT
6811         if (decrypt_request_data.pending_call &&
6812                         decrypt_request_data.data &&
6813                         decrypt_request_data.data->user_data == user_data) {
6814
6815                 callback_assoc_failed(decrypt_request_data.data->user_data);
6816                 crypt_method_call_cancel();
6817
6818                 return 0;
6819         }
6820 #endif
6821         data = dbus_malloc0(sizeof(*data));
6822         if (!data)
6823                 return -ENOMEM;
6824
6825         data->interface = interface;
6826         data->path = g_strdup(interface->path);
6827         data->callback = callback;
6828         data->user_data = user_data;
6829
6830         ret = supplicant_dbus_method_call(interface->path,
6831                         SUPPLICANT_INTERFACE ".Interface", "Disconnect",
6832                         NULL, interface_disconnect_result, data,
6833                         interface);
6834
6835         if (ret < 0) {
6836                 g_free(data->path);
6837                 dbus_free(data);
6838         }
6839
6840         return ret;
6841 }
6842
6843 static void interface_p2p_find_result(const char *error,
6844                                         DBusMessageIter *iter, void *user_data)
6845 {
6846         struct interface_scan_data *data = user_data;
6847         int err = 0;
6848
6849         SUPPLICANT_DBG("error %s", error);
6850
6851         if (error)
6852                 err = -EIO;
6853
6854         if (interface_exists(data->interface, data->path)) {
6855                 if (!data->interface->ready)
6856                         err = -ENOLINK;
6857                 if (!err)
6858                         data->interface->p2p_finding = true;
6859         }
6860
6861         if (data->callback)
6862                 data->callback(err, data->interface, data->user_data);
6863
6864         g_free(data->path);
6865         dbus_free(data);
6866 }
6867
6868 static void interface_p2p_find_params(DBusMessageIter *iter, void *user_data)
6869 {
6870         DBusMessageIter dict;
6871
6872         supplicant_dbus_dict_open(iter, &dict);
6873         supplicant_dbus_dict_close(iter, &dict);
6874 }
6875
6876 int g_supplicant_interface_p2p_find(GSupplicantInterface *interface,
6877                                         GSupplicantInterfaceCallback callback,
6878                                                         void *user_data)
6879 {
6880         struct interface_scan_data *data;
6881         int ret;
6882
6883         if (!interface->p2p_support)
6884                 return -ENOTSUP;
6885
6886         ret = interface_ready_to_scan(interface);
6887         if (ret && ret != -EALREADY)
6888                 return ret;
6889
6890         data = dbus_malloc0(sizeof(*data));
6891         if (!data)
6892                 return -ENOMEM;
6893
6894         data->interface = interface;
6895         data->path = g_strdup(interface->path);
6896         data->callback = callback;
6897         data->user_data = user_data;
6898
6899         ret = supplicant_dbus_method_call(interface->path,
6900                         SUPPLICANT_INTERFACE ".Interface.P2PDevice", "Find",
6901                         interface_p2p_find_params, interface_p2p_find_result,
6902                         data, interface);
6903         if (ret < 0) {
6904                 g_free(data->path);
6905                 dbus_free(data);
6906         }
6907
6908         return ret;
6909 }
6910
6911 bool g_supplicant_interface_is_p2p_finding(GSupplicantInterface *interface)
6912 {
6913         if (!interface)
6914                 return false;
6915
6916         return interface->p2p_finding;
6917 }
6918
6919 int g_supplicant_interface_p2p_stop_find(GSupplicantInterface *interface)
6920 {
6921         if (!interface->p2p_finding)
6922                 return 0;
6923
6924         SUPPLICANT_DBG("");
6925
6926         interface->p2p_finding = false;
6927
6928         return supplicant_dbus_method_call(interface->path,
6929                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "StopFind",
6930                 NULL, NULL, NULL, NULL);
6931 }
6932
6933 static void interface_p2p_connect_result(const char *error,
6934                                         DBusMessageIter *iter, void *user_data)
6935 {
6936         struct interface_connect_data *data = user_data;
6937         int err = 0;
6938
6939         SUPPLICANT_DBG("");
6940
6941         if (error) {
6942                 SUPPLICANT_DBG("error: %s", error);
6943                 err = parse_supplicant_error(iter);
6944         }
6945
6946         if (data->callback)
6947                 data->callback(err, data->interface, data->user_data);
6948
6949         g_free(data->path);
6950         g_free(data->peer->wps_pin);
6951         g_free(data->peer->path);
6952         g_free(data->peer);
6953         g_free(data);
6954 }
6955
6956 static void interface_p2p_connect_params(DBusMessageIter *iter, void *user_data)
6957 {
6958         struct interface_connect_data *data = user_data;
6959         const char *wps = "pbc";
6960         DBusMessageIter dict;
6961         int go_intent = 7;
6962
6963         SUPPLICANT_DBG("");
6964
6965         supplicant_dbus_dict_open(iter, &dict);
6966
6967         if (data->peer->master)
6968                 go_intent = 15;
6969
6970         if (data->peer->wps_pin)
6971                 wps = "pin";
6972
6973         supplicant_dbus_dict_append_basic(&dict, "peer",
6974                                 DBUS_TYPE_OBJECT_PATH, &data->peer->path);
6975         supplicant_dbus_dict_append_basic(&dict, "wps_method",
6976                                 DBUS_TYPE_STRING, &wps);
6977         if (data->peer->wps_pin) {
6978                 supplicant_dbus_dict_append_basic(&dict, "pin",
6979                                 DBUS_TYPE_STRING, &data->peer->wps_pin);
6980         }
6981
6982         supplicant_dbus_dict_append_basic(&dict, "go_intent",
6983                                         DBUS_TYPE_INT32, &go_intent);
6984
6985         supplicant_dbus_dict_close(iter, &dict);
6986 }
6987
6988 int g_supplicant_interface_p2p_connect(GSupplicantInterface *interface,
6989                                         GSupplicantPeerParams *peer_params,
6990                                         GSupplicantInterfaceCallback callback,
6991                                         void *user_data)
6992 {
6993         struct interface_connect_data *data;
6994         int ret;
6995
6996         SUPPLICANT_DBG("");
6997
6998         if (!interface->p2p_support)
6999                 return -ENOTSUP;
7000
7001         data = dbus_malloc0(sizeof(*data));
7002         if (!data)
7003                 return -ENOMEM;
7004
7005         data->interface = interface;
7006         data->path = g_strdup(interface->path);
7007         data->peer = peer_params;
7008         data->callback = callback;
7009         data->user_data = user_data;
7010
7011         ret = supplicant_dbus_method_call(interface->path,
7012                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "Connect",
7013                 interface_p2p_connect_params, interface_p2p_connect_result,
7014                 data, interface);
7015         if (ret < 0) {
7016                 g_free(data->path);
7017                 dbus_free(data);
7018                 return ret;
7019         }
7020
7021         return -EINPROGRESS;
7022 }
7023
7024 int g_supplicant_interface_p2p_disconnect(GSupplicantInterface *interface,
7025                                         GSupplicantPeerParams *peer_params)
7026 {
7027         GSupplicantPeer *peer;
7028         int count = 0;
7029         GSList *list;
7030
7031         SUPPLICANT_DBG("");
7032
7033         if (!interface->p2p_support)
7034                 return -ENOTSUP;
7035
7036         peer = g_hash_table_lookup(interface->peer_table, peer_params->path);
7037         if (!peer)
7038                 return -ENODEV;
7039
7040         for (list = peer->groups; list; list = list->next, count++) {
7041                 const char *group_obj_path = list->data;
7042                 GSupplicantInterface *g_interface;
7043                 GSupplicantGroup *group;
7044
7045                 group = g_hash_table_lookup(group_mapping, group_obj_path);
7046                 if (!group || !group->interface)
7047                         continue;
7048
7049                 g_interface = group->interface;
7050                 supplicant_dbus_method_call(g_interface->path,
7051                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
7052                                 "Disconnect", NULL, NULL, NULL, g_interface);
7053         }
7054
7055         if (count == 0 && peer->current_group_iface) {
7056                 supplicant_dbus_method_call(peer->current_group_iface->path,
7057                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
7058                                 "Disconnect", NULL, NULL, NULL,
7059                                 peer->current_group_iface->path);
7060         }
7061
7062         peer->current_group_iface = NULL;
7063
7064         return -EINPROGRESS;
7065 }
7066
7067 struct p2p_service_data {
7068         bool registration;
7069         GSupplicantInterface *interface;
7070         GSupplicantP2PServiceParams *service;
7071         GSupplicantInterfaceCallback callback;
7072         void *user_data;
7073 };
7074
7075 static void interface_p2p_service_result(const char *error,
7076                                         DBusMessageIter *iter, void *user_data)
7077 {
7078         struct p2p_service_data *data = user_data;
7079         int result = 0;
7080
7081         SUPPLICANT_DBG("%s result - %s", data->registration ?
7082                                 "Registration" : "Deletion",
7083                                 error ? error : "Success");
7084         if (error)
7085                 result = -EINVAL;
7086
7087         if (data->callback)
7088                 data->callback(result, data->interface, data->user_data);
7089
7090         g_free(data->service->query);
7091         g_free(data->service->response);
7092         g_free(data->service->service);
7093         g_free(data->service->wfd_ies);
7094         g_free(data->service);
7095         dbus_free(data);
7096 }
7097
7098 static void interface_p2p_service_params(DBusMessageIter *iter,
7099                                                         void *user_data)
7100 {
7101         struct p2p_service_data *data = user_data;
7102         GSupplicantP2PServiceParams *service;
7103         DBusMessageIter dict;
7104         const char *type;
7105
7106         SUPPLICANT_DBG("");
7107
7108         service = data->service;
7109
7110         supplicant_dbus_dict_open(iter, &dict);
7111
7112         if (service->query && service->response) {
7113                 type = "bonjour";
7114                 supplicant_dbus_dict_append_basic(&dict, "service_type",
7115                                                 DBUS_TYPE_STRING, &type);
7116                 supplicant_dbus_dict_append_fixed_array(&dict, "query",
7117                                         DBUS_TYPE_BYTE, &service->query,
7118                                         service->query_length);
7119                 supplicant_dbus_dict_append_fixed_array(&dict, "response",
7120                                         DBUS_TYPE_BYTE, &service->response,
7121                                         service->response_length);
7122         } else if (service->version && service->service) {
7123                 type = "upnp";
7124                 supplicant_dbus_dict_append_basic(&dict, "service_type",
7125                                                 DBUS_TYPE_STRING, &type);
7126                 supplicant_dbus_dict_append_basic(&dict, "version",
7127                                         DBUS_TYPE_INT32, &service->version);
7128                 supplicant_dbus_dict_append_basic(&dict, "service",
7129                                         DBUS_TYPE_STRING, &service->service);
7130         }
7131
7132         supplicant_dbus_dict_close(iter, &dict);
7133 }
7134
7135 int g_supplicant_interface_p2p_add_service(GSupplicantInterface *interface,
7136                                 GSupplicantInterfaceCallback callback,
7137                                 GSupplicantP2PServiceParams *p2p_service_params,
7138                                 void *user_data)
7139 {
7140         struct p2p_service_data *data;
7141         int ret;
7142
7143         SUPPLICANT_DBG("");
7144
7145         if (!interface->p2p_support)
7146                 return -ENOTSUP;
7147
7148         data = dbus_malloc0(sizeof(*data));
7149         if (!data)
7150                 return -ENOMEM;
7151
7152         data->registration = true;
7153         data->interface = interface;
7154         data->service = p2p_service_params;
7155         data->callback = callback;
7156         data->user_data = user_data;
7157
7158         ret = supplicant_dbus_method_call(interface->path,
7159                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "AddService",
7160                 interface_p2p_service_params, interface_p2p_service_result,
7161                 data, interface);
7162         if (ret < 0) {
7163                 dbus_free(data);
7164                 return ret;
7165         }
7166
7167         return -EINPROGRESS;
7168 }
7169
7170 int g_supplicant_interface_p2p_del_service(GSupplicantInterface *interface,
7171                                 GSupplicantP2PServiceParams *p2p_service_params)
7172 {
7173         struct p2p_service_data *data;
7174         int ret;
7175
7176         SUPPLICANT_DBG("");
7177
7178         if (!interface->p2p_support)
7179                 return -ENOTSUP;
7180
7181         data = dbus_malloc0(sizeof(*data));
7182         if (!data)
7183                 return -ENOMEM;
7184
7185         data->interface = interface;
7186         data->service = p2p_service_params;
7187
7188         ret = supplicant_dbus_method_call(interface->path,
7189                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeleteService",
7190                 interface_p2p_service_params, interface_p2p_service_result,
7191                 data, interface);
7192         if (ret < 0) {
7193                 dbus_free(data);
7194                 return ret;
7195         }
7196
7197         return -EINPROGRESS;
7198 }
7199
7200 struct p2p_listen_data {
7201         int period;
7202         int interval;
7203 };
7204
7205 static void interface_p2p_listen_params(DBusMessageIter *iter, void *user_data)
7206 {
7207         struct p2p_listen_data *params = user_data;
7208         DBusMessageIter dict;
7209
7210         supplicant_dbus_dict_open(iter, &dict);
7211
7212         supplicant_dbus_dict_append_basic(&dict, "period",
7213                                         DBUS_TYPE_INT32, &params->period);
7214         supplicant_dbus_dict_append_basic(&dict, "interval",
7215                                         DBUS_TYPE_INT32, &params->interval);
7216         supplicant_dbus_dict_close(iter, &dict);
7217 }
7218
7219 int g_supplicant_interface_p2p_listen(GSupplicantInterface *interface,
7220                                                 int period, int interval)
7221 {
7222         struct p2p_listen_data params;
7223
7224         SUPPLICANT_DBG("");
7225
7226         if (!interface->p2p_support)
7227                 return -ENOTSUP;
7228
7229         params.period = period;
7230         params.interval = interval;
7231
7232         return supplicant_dbus_method_call(interface->path,
7233                         SUPPLICANT_INTERFACE ".Interface.P2PDevice",
7234                         "ExtendedListen", interface_p2p_listen_params,
7235                         NULL, &params, NULL);
7236 }
7237
7238 static void widi_ies_params(DBusMessageIter *iter, void *user_data)
7239 {
7240         struct p2p_service_data *data = user_data;
7241         GSupplicantP2PServiceParams *service = data->service;
7242         DBusMessageIter array;
7243
7244         SUPPLICANT_DBG("%p - %d", service->wfd_ies, service->wfd_ies_length);
7245
7246         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
7247                                         DBUS_TYPE_BYTE_AS_STRING, &array);
7248
7249         if (service->wfd_ies && service->wfd_ies_length > 0) {
7250                 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
7251                                 &service->wfd_ies, service->wfd_ies_length);
7252         }
7253
7254         dbus_message_iter_close_container(iter, &array);
7255 }
7256
7257 int g_supplicant_set_widi_ies(GSupplicantP2PServiceParams *p2p_service_params,
7258                                         GSupplicantInterfaceCallback callback,
7259                                         void *user_data)
7260 {
7261         struct p2p_service_data *data;
7262         int ret;
7263
7264         SUPPLICANT_DBG("");
7265
7266         if (!system_available)
7267                 return -EFAULT;
7268
7269         data = dbus_malloc0(sizeof(*data));
7270         if (!data)
7271                 return -ENOMEM;
7272
7273         data->service = p2p_service_params;
7274         data->callback = callback;
7275         data->user_data = user_data;
7276
7277         if (p2p_service_params->wfd_ies)
7278                 data->registration = true;
7279
7280         ret = supplicant_dbus_property_set(SUPPLICANT_PATH,
7281                                         SUPPLICANT_INTERFACE, "WFDIEs",
7282                                         DBUS_TYPE_ARRAY_AS_STRING
7283                                         DBUS_TYPE_BYTE_AS_STRING,
7284                                         widi_ies_params,
7285                                         interface_p2p_service_result,
7286                                         data, NULL);
7287         if (ret < 0 && ret != -EINPROGRESS) {
7288                 dbus_free(data);
7289                 return ret;
7290         }
7291
7292         return -EINPROGRESS;
7293 }
7294
7295 static const char *g_supplicant_rule0 = "type=signal,"
7296                                         "path=" DBUS_PATH_DBUS ","
7297                                         "sender=" DBUS_SERVICE_DBUS ","
7298                                         "interface=" DBUS_INTERFACE_DBUS ","
7299                                         "member=NameOwnerChanged,"
7300                                         "arg0=" SUPPLICANT_SERVICE;
7301 static const char *g_supplicant_rule1 = "type=signal,"
7302                         "interface=" SUPPLICANT_INTERFACE;
7303 static const char *g_supplicant_rule2 = "type=signal,"
7304                         "interface=" SUPPLICANT_INTERFACE ".Interface";
7305 static const char *g_supplicant_rule3 = "type=signal,"
7306                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
7307 static const char *g_supplicant_rule4 = "type=signal,"
7308                         "interface=" SUPPLICANT_INTERFACE ".BSS";
7309 static const char *g_supplicant_rule5 = "type=signal,"
7310                         "interface=" SUPPLICANT_INTERFACE ".Network";
7311 #if !defined TIZEN_EXT
7312 static const char *g_supplicant_rule6 = "type=signal,"
7313                 "interface=" SUPPLICANT_INTERFACE ".Interface.P2PDevice";
7314 static const char *g_supplicant_rule7 = "type=signal,"
7315                 "interface=" SUPPLICANT_INTERFACE ".Peer";
7316 static const char *g_supplicant_rule8 = "type=signal,"
7317                 "interface=" SUPPLICANT_INTERFACE ".Group";
7318 #endif
7319 #if defined TIZEN_EXT_WIFI_MESH
7320 static const char *g_supplicant_rule9 = "type=signal,"
7321                 "interface=" SUPPLICANT_INTERFACE ".Interface.Mesh";
7322 #endif
7323
7324 static void invoke_introspect_method(void)
7325 {
7326         DBusMessage *message;
7327
7328         message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
7329                                         SUPPLICANT_PATH,
7330                                         DBUS_INTERFACE_INTROSPECTABLE,
7331                                         "Introspect");
7332
7333         if (!message)
7334                 return;
7335
7336         dbus_message_set_no_reply(message, TRUE);
7337         dbus_connection_send(connection, message, NULL);
7338         dbus_message_unref(message);
7339 }
7340
7341 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
7342 {
7343         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
7344         if (!connection)
7345                 return -EIO;
7346
7347         if (!dbus_connection_add_filter(connection, g_supplicant_filter,
7348                                                 NULL, NULL)) {
7349                 dbus_connection_unref(connection);
7350                 connection = NULL;
7351                 return -EIO;
7352         }
7353
7354         callbacks_pointer = callbacks;
7355         eap_methods = 0;
7356
7357         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
7358                                                 NULL, remove_interface);
7359
7360         bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
7361                                                                 NULL, NULL);
7362         peer_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
7363                                                                 NULL, NULL);
7364         group_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
7365                                                                 NULL, NULL);
7366         pending_peer_connection = g_hash_table_new_full(g_str_hash, g_str_equal,
7367                                                                 NULL, NULL);
7368         config_file_table = g_hash_table_new_full(g_str_hash, g_str_equal,
7369                                                                 g_free, g_free);
7370
7371         supplicant_dbus_setup(connection);
7372
7373         dbus_bus_add_match(connection, g_supplicant_rule0, NULL);
7374         dbus_bus_add_match(connection, g_supplicant_rule1, NULL);
7375         dbus_bus_add_match(connection, g_supplicant_rule2, NULL);
7376         dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
7377         dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
7378         dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
7379 #if defined TIZEN_EXT
7380         dbus_bus_add_match(connection,
7381                         "type=signal,interface=org.tizen.system.deviced.PowerOff,"
7382                         "member=ChangeState", NULL);
7383 #endif
7384 #if !defined TIZEN_EXT
7385         dbus_bus_add_match(connection, g_supplicant_rule6, NULL);
7386         dbus_bus_add_match(connection, g_supplicant_rule7, NULL);
7387         dbus_bus_add_match(connection, g_supplicant_rule8, NULL);
7388 #endif
7389 #if defined TIZEN_EXT_WIFI_MESH
7390         dbus_bus_add_match(connection, g_supplicant_rule9, NULL);
7391 #endif
7392         dbus_connection_flush(connection);
7393
7394         if (dbus_bus_name_has_owner(connection,
7395                                         SUPPLICANT_SERVICE, NULL)) {
7396                 system_available = TRUE;
7397                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
7398                                                 SUPPLICANT_INTERFACE,
7399                                                 service_property, NULL, NULL);
7400         } else
7401                 invoke_introspect_method();
7402
7403         return 0;
7404 }
7405
7406 static void unregister_interface_remove_params(DBusMessageIter *iter,
7407                                                 void *user_data)
7408 {
7409         const char *path = user_data;
7410
7411         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
7412                                                         &path);
7413 }
7414
7415
7416 static void unregister_remove_interface(gpointer key, gpointer value,
7417                                                 gpointer user_data)
7418 {
7419         GSupplicantInterface *interface = value;
7420
7421         supplicant_dbus_method_call(SUPPLICANT_PATH,
7422                                         SUPPLICANT_INTERFACE,
7423                                         "RemoveInterface",
7424                                         unregister_interface_remove_params,
7425                                         NULL, interface->path, NULL);
7426 }
7427
7428 void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
7429 {
7430         SUPPLICANT_DBG("");
7431
7432         if (connection) {
7433 #if defined TIZEN_EXT_WIFI_MESH
7434                 dbus_bus_remove_match(connection, g_supplicant_rule9, NULL);
7435 #endif
7436 #if !defined TIZEN_EXT
7437                 dbus_bus_remove_match(connection, g_supplicant_rule8, NULL);
7438                 dbus_bus_remove_match(connection, g_supplicant_rule7, NULL);
7439                 dbus_bus_remove_match(connection, g_supplicant_rule6, NULL);
7440 #endif
7441                 dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
7442                 dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
7443                 dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);
7444                 dbus_bus_remove_match(connection, g_supplicant_rule2, NULL);
7445                 dbus_bus_remove_match(connection, g_supplicant_rule1, NULL);
7446                 dbus_bus_remove_match(connection, g_supplicant_rule0, NULL);
7447                 dbus_connection_flush(connection);
7448
7449                 dbus_connection_remove_filter(connection,
7450                                                 g_supplicant_filter, NULL);
7451         }
7452
7453         if (config_file_table) {
7454                 g_hash_table_destroy(config_file_table);
7455                 config_file_table = NULL;
7456         }
7457
7458         if (bss_mapping) {
7459                 g_hash_table_destroy(bss_mapping);
7460                 bss_mapping = NULL;
7461         }
7462
7463         if (peer_mapping) {
7464                 g_hash_table_destroy(peer_mapping);
7465                 peer_mapping = NULL;
7466         }
7467
7468         if (group_mapping) {
7469                 g_hash_table_destroy(group_mapping);
7470                 group_mapping = NULL;
7471         }
7472
7473         if (interface_table) {
7474                 g_hash_table_foreach(interface_table,
7475                                         unregister_remove_interface, NULL);
7476                 g_hash_table_destroy(interface_table);
7477                 interface_table = NULL;
7478         }
7479
7480         if (system_available)
7481                 callback_system_killed();
7482
7483         if (connection) {
7484                 dbus_connection_unref(connection);
7485                 connection = NULL;
7486         }
7487
7488         callbacks_pointer = NULL;
7489         eap_methods = 0;
7490 }