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