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