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