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