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