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