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