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