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