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