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