30237a323e5087e076e074d50ea9d9e4f18c9c88
[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                 interface_network_added(iter, interface);
2258         } else if (g_strcmp0(key, "BSSs") == 0) {
2259                 supplicant_dbus_array_foreach(iter,
2260                                         interface_bss_added_without_keys,
2261                                         interface);
2262         } else if (g_strcmp0(key, "Blobs") == 0) {
2263                 /* Nothing */
2264         } else if (g_strcmp0(key, "Networks") == 0) {
2265                 supplicant_dbus_array_foreach(iter, interface_network_added,
2266                                                                 interface);
2267         } else
2268                 SUPPLICANT_DBG("key %s type %c",
2269                                 key, dbus_message_iter_get_arg_type(iter));
2270 }
2271
2272 static void scan_network_update(DBusMessageIter *iter, void *user_data)
2273 {
2274         GSupplicantInterface *interface = user_data;
2275         GSupplicantNetwork *network;
2276         char *path;
2277
2278         if (!iter)
2279                 return;
2280
2281         dbus_message_iter_get_basic(iter, &path);
2282
2283         if (!path)
2284                 return;
2285
2286         if (g_strcmp0(path, "/") == 0)
2287                 return;
2288
2289         /* Update the network details based on scan BSS data */
2290         network = g_hash_table_lookup(interface->bss_mapping, path);
2291         if (network)
2292                 callback_network_added(network);
2293 }
2294
2295 static void scan_bss_data(const char *key, DBusMessageIter *iter,
2296                                 void *user_data)
2297 {
2298         GSupplicantInterface *interface = user_data;
2299
2300         if (iter)
2301                 supplicant_dbus_array_foreach(iter, scan_network_update,
2302                                                 interface);
2303
2304         if (interface->scan_callback)
2305                 interface->scan_callback(0, interface, interface->scan_data);
2306
2307         interface->scan_callback = NULL;
2308         interface->scan_data = NULL;
2309 }
2310
2311 static GSupplicantInterface *interface_alloc(const char *path)
2312 {
2313         GSupplicantInterface *interface;
2314
2315         interface = g_try_new0(GSupplicantInterface, 1);
2316         if (!interface)
2317                 return NULL;
2318
2319         interface->path = g_strdup(path);
2320
2321         interface->network_table = g_hash_table_new_full(g_str_hash,
2322                                         g_str_equal, NULL, remove_network);
2323         interface->peer_table = g_hash_table_new_full(g_str_hash,
2324                                         g_str_equal, NULL, remove_peer);
2325         interface->group_table = g_hash_table_new_full(g_str_hash,
2326                                         g_str_equal, NULL, remove_group);
2327         interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
2328                                                                 NULL, NULL);
2329         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
2330                                                                 NULL, NULL);
2331
2332         g_hash_table_replace(interface_table, interface->path, interface);
2333
2334         return interface;
2335 }
2336
2337 static void interface_added(DBusMessageIter *iter, void *user_data)
2338 {
2339         GSupplicantInterface *interface;
2340         const char *path = NULL;
2341
2342         SUPPLICANT_DBG("");
2343
2344         dbus_message_iter_get_basic(iter, &path);
2345         if (!path)
2346                 return;
2347
2348         if (g_strcmp0(path, "/") == 0)
2349                 return;
2350
2351         interface = g_hash_table_lookup(interface_table, path);
2352         if (interface)
2353                 return;
2354
2355         interface = interface_alloc(path);
2356         if (!interface)
2357                 return;
2358
2359         dbus_message_iter_next(iter);
2360         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
2361                 supplicant_dbus_property_foreach(iter, interface_property,
2362                                                                 interface);
2363                 interface_property(NULL, NULL, interface);
2364                 return;
2365         }
2366
2367         supplicant_dbus_property_get_all(path,
2368                                         SUPPLICANT_INTERFACE ".Interface",
2369                                         interface_property, interface,
2370                                         interface);
2371 }
2372
2373 static void interface_removed(DBusMessageIter *iter, void *user_data)
2374 {
2375         const char *path = NULL;
2376         GSupplicantInterface *interface = user_data;
2377
2378         dbus_message_iter_get_basic(iter, &path);
2379         if (!path)
2380                 return;
2381
2382         interface = g_hash_table_lookup(interface_table, path);
2383         g_supplicant_interface_cancel(interface);
2384
2385         g_hash_table_remove(interface_table, path);
2386 }
2387
2388 static void eap_method(DBusMessageIter *iter, void *user_data)
2389 {
2390         const char *str = NULL;
2391         int i;
2392
2393         dbus_message_iter_get_basic(iter, &str);
2394         if (!str)
2395                 return;
2396
2397         for (i = 0; eap_method_map[i].str; i++)
2398                 if (strcmp(str, eap_method_map[i].str) == 0) {
2399                         eap_methods |= eap_method_map[i].val;
2400                         break;
2401                 }
2402 }
2403
2404 static void service_property(const char *key, DBusMessageIter *iter,
2405                                                         void *user_data)
2406 {
2407         if (!key) {
2408                 callback_system_ready();
2409                 return;
2410         }
2411
2412         if (g_strcmp0(key, "DebugLevel") == 0) {
2413                 const char *str = NULL;
2414                 int i;
2415
2416                 dbus_message_iter_get_basic(iter, &str);
2417                 for (i = 0; debug_strings[i]; i++)
2418                         if (g_strcmp0(debug_strings[i], str) == 0) {
2419                                 debug_level = i;
2420                                 break;
2421                         }
2422                 SUPPLICANT_DBG("Debug level %d", debug_level);
2423         } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
2424                 dbus_message_iter_get_basic(iter, &debug_timestamp);
2425                 SUPPLICANT_DBG("Debug timestamp %u", debug_timestamp);
2426         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
2427                 dbus_message_iter_get_basic(iter, &debug_showkeys);
2428                 SUPPLICANT_DBG("Debug show keys %u", debug_showkeys);
2429         } else if (g_strcmp0(key, "Interfaces") == 0) {
2430                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
2431         } else if (g_strcmp0(key, "EapMethods") == 0) {
2432                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
2433                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
2434         } else if (g_strcmp0(key, "Country") == 0) {
2435                 const char *country = NULL;
2436
2437                 dbus_message_iter_get_basic(iter, &country);
2438                 SUPPLICANT_DBG("Country %s", country);
2439         } else
2440                 SUPPLICANT_DBG("key %s type %c",
2441                                 key, dbus_message_iter_get_arg_type(iter));
2442 }
2443
2444 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
2445 {
2446         const char *name = NULL, *old = NULL, *new = NULL;
2447
2448         SUPPLICANT_DBG("");
2449
2450         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
2451                 return;
2452
2453         dbus_message_iter_get_basic(iter, &name);
2454         if (!name)
2455                 return;
2456
2457         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
2458                 return;
2459
2460         dbus_message_iter_next(iter);
2461         dbus_message_iter_get_basic(iter, &old);
2462         dbus_message_iter_next(iter);
2463         dbus_message_iter_get_basic(iter, &new);
2464
2465         if (!old || !new)
2466                 return;
2467
2468         if (strlen(old) > 0 && strlen(new) == 0) {
2469                 system_available = FALSE;
2470                 g_hash_table_remove_all(bss_mapping);
2471                 g_hash_table_remove_all(peer_mapping);
2472                 g_hash_table_remove_all(group_mapping);
2473                 g_hash_table_remove_all(interface_table);
2474                 callback_system_killed();
2475         }
2476
2477         if (strlen(new) > 0 && strlen(old) == 0) {
2478                 system_available = TRUE;
2479                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
2480                                                 SUPPLICANT_INTERFACE,
2481                                                 service_property, NULL, NULL);
2482         }
2483 }
2484
2485 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
2486 {
2487         SUPPLICANT_DBG("");
2488
2489         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
2490                 return;
2491
2492         supplicant_dbus_property_foreach(iter, service_property, NULL);
2493 }
2494
2495 static void signal_interface_added(const char *path, DBusMessageIter *iter)
2496 {
2497         SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
2498
2499         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
2500                 interface_added(iter, NULL);
2501 }
2502
2503 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
2504 {
2505         SUPPLICANT_DBG("");
2506
2507         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
2508                 interface_removed(iter, NULL);
2509 }
2510
2511 static void signal_interface_changed(const char *path, DBusMessageIter *iter)
2512 {
2513         GSupplicantInterface *interface;
2514
2515         SUPPLICANT_DBG("");
2516
2517         interface = g_hash_table_lookup(interface_table, path);
2518         if (!interface)
2519                 return;
2520
2521         supplicant_dbus_property_foreach(iter, interface_property, interface);
2522 }
2523
2524 static void signal_scan_done(const char *path, DBusMessageIter *iter)
2525 {
2526         GSupplicantInterface *interface;
2527         dbus_bool_t success = FALSE;
2528
2529         SUPPLICANT_DBG("");
2530
2531         interface = g_hash_table_lookup(interface_table, path);
2532         if (!interface)
2533                 return;
2534
2535         dbus_message_iter_get_basic(iter, &success);
2536
2537         if (interface->scanning) {
2538                 callback_scan_finished(interface);
2539                 interface->scanning = FALSE;
2540         }
2541
2542         /*
2543          * If scan is unsuccessful return -EIO else get the scanned BSSs
2544          * and update the network details accordingly
2545          */
2546         if (!success) {
2547                 if (interface->scan_callback)
2548                         interface->scan_callback(-EIO, interface,
2549                                                 interface->scan_data);
2550
2551                 interface->scan_callback = NULL;
2552                 interface->scan_data = NULL;
2553
2554                 return;
2555         }
2556
2557         supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface",
2558                                 "BSSs", scan_bss_data, interface, interface);
2559 }
2560
2561 static void signal_bss_added(const char *path, DBusMessageIter *iter)
2562 {
2563         GSupplicantInterface *interface;
2564
2565         SUPPLICANT_DBG("");
2566
2567         interface = g_hash_table_lookup(interface_table, path);
2568         if (!interface)
2569                 return;
2570
2571         interface_bss_added_with_keys(iter, interface);
2572 }
2573
2574 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
2575 {
2576         GSupplicantInterface *interface;
2577
2578         SUPPLICANT_DBG("");
2579
2580         interface = g_hash_table_lookup(interface_table, path);
2581         if (!interface)
2582                 return;
2583
2584         interface_bss_removed(iter, interface);
2585 }
2586
2587 static void signal_network_added(const char *path, DBusMessageIter *iter)
2588 {
2589         GSupplicantInterface *interface;
2590
2591         SUPPLICANT_DBG("");
2592
2593         interface = g_hash_table_lookup(interface_table, path);
2594         if (!interface)
2595                 return;
2596
2597         interface_network_added(iter, interface);
2598 }
2599
2600 static void signal_network_removed(const char *path, DBusMessageIter *iter)
2601 {
2602         GSupplicantInterface *interface;
2603
2604         SUPPLICANT_DBG("");
2605
2606         interface = g_hash_table_lookup(interface_table, path);
2607         if (!interface)
2608                 return;
2609
2610         interface_network_removed(iter, interface);
2611 }
2612
2613 static void signal_bss_changed(const char *path, DBusMessageIter *iter)
2614 {
2615         GSupplicantInterface *interface;
2616         GSupplicantNetwork *network;
2617         GSupplicantSecurity old_security;
2618         struct g_supplicant_bss *bss;
2619
2620         SUPPLICANT_DBG("");
2621
2622         interface = g_hash_table_lookup(bss_mapping, path);
2623         if (!interface)
2624                 return;
2625
2626         network = g_hash_table_lookup(interface->bss_mapping, path);
2627         if (!network)
2628                 return;
2629
2630         bss = g_hash_table_lookup(network->bss_table, path);
2631         if (!bss)
2632                 return;
2633
2634         supplicant_dbus_property_foreach(iter, bss_property, bss);
2635
2636         old_security = network->security;
2637         bss_compute_security(bss);
2638
2639         if (old_security != bss->security) {
2640                 struct g_supplicant_bss *new_bss;
2641
2642                 SUPPLICANT_DBG("New network security for %s", bss->ssid);
2643
2644                 /* Security change policy:
2645                  * - we first copy the current bss into a new one with
2646                  * its own pointer (path)
2647                  * - we remove the current bss related network which will
2648                  * tell the plugin about such removal. This is done due
2649                  * to the fact that a security change means a group change
2650                  * so a complete network change.
2651                  * (current bss becomes invalid as well)
2652                  * - we add the new bss: it adds new network and tell the
2653                  * plugin about it. */
2654
2655                 new_bss = g_try_new0(struct g_supplicant_bss, 1);
2656                 if (!new_bss)
2657                         return;
2658
2659                 memcpy(new_bss, bss, sizeof(struct g_supplicant_bss));
2660                 new_bss->path = g_strdup(bss->path);
2661
2662                 g_hash_table_remove(interface->network_table, network->group);
2663
2664                 add_or_replace_bss_to_network(new_bss);
2665
2666                 return;
2667         }
2668
2669 #if defined TIZEN_EXT
2670         if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) {
2671                 network->wps = TRUE;
2672                 network->wps_capabilities |= bss->wps_capabilities;
2673         } else
2674                 network->wps = FALSE;
2675 #endif
2676
2677         if (bss->signal == network->signal)
2678 #ifndef TIZEN_EXT
2679                 return;
2680 #else
2681         {
2682                 callback_network_changed(network, "");
2683                 return;
2684         }
2685 #endif
2686
2687         /*
2688          * If the new signal is lower than the SSID signal, we need
2689          * to check for the new maximum.
2690          */
2691         if (bss->signal < network->signal) {
2692                 if (bss != network->best_bss)
2693 #ifndef TIZEN_EXT
2694                         return;
2695 #else
2696                 {
2697                         callback_network_changed(network, "");
2698                         return;
2699                 }
2700 #endif
2701                 network->signal = bss->signal;
2702                 update_network_signal(network);
2703         } else {
2704                 network->signal = bss->signal;
2705                 network->best_bss = bss;
2706         }
2707
2708         SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid,
2709                         network->signal);
2710
2711         callback_network_changed(network, "Signal");
2712 }
2713
2714 static void wps_credentials(const char *key, DBusMessageIter *iter,
2715                         void *user_data)
2716 {
2717         GSupplicantInterface *interface = user_data;
2718
2719         if (!key)
2720                 return;
2721
2722         SUPPLICANT_DBG("key %s", key);
2723
2724         if (g_strcmp0(key, "Key") == 0) {
2725                 DBusMessageIter array;
2726                 unsigned char *key_val;
2727                 int key_len;
2728
2729                 dbus_message_iter_recurse(iter, &array);
2730                 dbus_message_iter_get_fixed_array(&array, &key_val, &key_len);
2731
2732                 g_free(interface->wps_cred.key);
2733                 interface->wps_cred.key = g_try_malloc0(
2734                                                 sizeof(char) * key_len + 1);
2735
2736                 if (!interface->wps_cred.key)
2737                         return;
2738
2739                 memcpy(interface->wps_cred.key, key_val,
2740                                                 sizeof(char) * key_len);
2741
2742                 SUPPLICANT_DBG("WPS key present");
2743         } else if (g_strcmp0(key, "SSID") == 0) {
2744                 DBusMessageIter array;
2745                 unsigned char *ssid;
2746                 int ssid_len;
2747
2748                 dbus_message_iter_recurse(iter, &array);
2749                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
2750
2751                 if (ssid_len > 0 && ssid_len < 33) {
2752                         memcpy(interface->wps_cred.ssid, ssid, ssid_len);
2753                         interface->wps_cred.ssid_len = ssid_len;
2754                 } else {
2755                         memset(interface->wps_cred.ssid, 0, 32);
2756                         interface->wps_cred.ssid_len = 0;
2757                 }
2758         }
2759 }
2760
2761 static void signal_wps_credentials(const char *path, DBusMessageIter *iter)
2762 {
2763         GSupplicantInterface *interface;
2764
2765         SUPPLICANT_DBG("");
2766
2767         interface = g_hash_table_lookup(interface_table, path);
2768         if (!interface)
2769                 return;
2770
2771         supplicant_dbus_property_foreach(iter, wps_credentials, interface);
2772 }
2773
2774 static void wps_event_args(const char *key, DBusMessageIter *iter,
2775                         void *user_data)
2776 {
2777         GSupplicantInterface *interface = user_data;
2778
2779         if (!key || !interface)
2780                 return;
2781
2782         SUPPLICANT_DBG("Arg Key %s", key);
2783 }
2784
2785 static void signal_wps_event(const char *path, DBusMessageIter *iter)
2786 {
2787         GSupplicantInterface *interface;
2788         const char *name = NULL;
2789
2790         SUPPLICANT_DBG("");
2791
2792         interface = g_hash_table_lookup(interface_table, path);
2793         if (!interface)
2794                 return;
2795
2796         dbus_message_iter_get_basic(iter, &name);
2797
2798         SUPPLICANT_DBG("Name: %s", name);
2799
2800         if (g_strcmp0(name, "success") == 0)
2801                 interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
2802         else if (g_strcmp0(name, "failed") == 0)
2803                 interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
2804         else
2805                 interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
2806
2807         if (!dbus_message_iter_has_next(iter))
2808                 return;
2809
2810         dbus_message_iter_next(iter);
2811
2812         supplicant_dbus_property_foreach(iter, wps_event_args, interface);
2813 }
2814
2815 #if defined TIZEN_EXT
2816 static void signal_power_off(const char *path, DBusMessageIter *iter)
2817 {
2818         int poweroff_state = 0;
2819
2820         dbus_message_iter_get_basic(iter, &poweroff_state);
2821
2822         SUPPLICANT_DBG("poweroff_state(%d)", poweroff_state);
2823
2824         /* POWER_OFF_DIRECT 2 && POWER_OFF_RESTART 3 */
2825         if (poweroff_state != 2 && poweroff_state != 3)
2826                 return;
2827
2828         if (callbacks_pointer == NULL)
2829                 return;
2830
2831         if (callbacks_pointer->system_power_off == NULL)
2832                 return;
2833
2834         callbacks_pointer->system_power_off();
2835 }
2836 #endif
2837
2838 static void signal_station_connected(const char *path, DBusMessageIter *iter)
2839 {
2840         GSupplicantInterface *interface;
2841         const char *sta_mac = NULL;
2842
2843         SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
2844
2845         if (callbacks_pointer->add_station == NULL)
2846                 return;
2847
2848         if (g_strcmp0(path, "/") == 0)
2849                 return;
2850
2851         interface = g_hash_table_lookup(interface_table, path);
2852         if (interface == NULL)
2853                 return;
2854
2855         dbus_message_iter_get_basic(iter, &sta_mac);
2856         if (sta_mac == NULL)
2857                 return;
2858
2859         SUPPLICANT_DBG("New station %s connected", sta_mac);
2860         callbacks_pointer->add_station(sta_mac);
2861 }
2862
2863 static void signal_station_disconnected(const char *path, DBusMessageIter *iter)
2864 {
2865         GSupplicantInterface *interface;
2866         const char *sta_mac = NULL;
2867
2868         SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
2869
2870         if (callbacks_pointer->remove_station == NULL)
2871                 return;
2872
2873         if (g_strcmp0(path, "/") == 0)
2874                 return;
2875
2876         interface = g_hash_table_lookup(interface_table, path);
2877         if (interface == NULL)
2878                 return;
2879
2880         dbus_message_iter_get_basic(iter, &sta_mac);
2881         if (sta_mac == NULL)
2882                 return;
2883
2884         SUPPLICANT_DBG("Station %s disconnected", sta_mac);
2885         callbacks_pointer->remove_station(sta_mac);
2886 }
2887
2888 static void create_peer_identifier(GSupplicantPeer *peer)
2889 {
2890         const unsigned char test[ETH_ALEN] = {};
2891
2892         if (!peer)
2893                 return;
2894
2895         if (!memcmp(peer->device_address, test, ETH_ALEN)) {
2896                 peer->identifier = g_strdup(peer->name);
2897                 return;
2898         }
2899
2900         peer->identifier = g_malloc0(19);
2901         snprintf(peer->identifier, 19, "%02x%02x%02x%02x%02x%02x",
2902                                                 peer->device_address[0],
2903                                                 peer->device_address[1],
2904                                                 peer->device_address[2],
2905                                                 peer->device_address[3],
2906                                                 peer->device_address[4],
2907                                                 peer->device_address[5]);
2908 }
2909
2910 struct peer_property_data {
2911         GSupplicantPeer *peer;
2912         GSList *old_groups;
2913         bool groups_changed;
2914         bool services_changed;
2915 };
2916
2917 static void peer_groups_relation(DBusMessageIter *iter, void *user_data)
2918 {
2919         struct peer_property_data *data = user_data;
2920         GSupplicantPeer *peer = data->peer;
2921         GSupplicantGroup *group;
2922         const char *str = NULL;
2923         GSList *elem;
2924
2925         dbus_message_iter_get_basic(iter, &str);
2926         if (!str)
2927                 return;
2928
2929         group = g_hash_table_lookup(group_mapping, str);
2930         if (!group)
2931                 return;
2932
2933         elem = g_slist_find_custom(data->old_groups, str, g_str_equal);
2934         if (elem) {
2935                 data->old_groups = g_slist_remove_link(data->old_groups, elem);
2936                 peer->groups = g_slist_concat(elem, peer->groups);
2937         } else {
2938                 peer->groups = g_slist_prepend(peer->groups, g_strdup(str));
2939                 data->groups_changed = true;
2940         }
2941 }
2942
2943 static void peer_property(const char *key, DBusMessageIter *iter,
2944                                                         void *user_data)
2945 {
2946         GSupplicantPeer *pending_peer;
2947         struct peer_property_data *data = user_data;
2948         GSupplicantPeer *peer = data->peer;
2949
2950         SUPPLICANT_DBG("key: %s", key);
2951
2952         if (!peer->interface)
2953                 return;
2954
2955         if (!key) {
2956                 if (peer->name) {
2957                         create_peer_identifier(peer);
2958                         callback_peer_found(peer);
2959                         pending_peer = g_hash_table_lookup(
2960                                         pending_peer_connection, peer->path);
2961
2962                         if (pending_peer && pending_peer == peer) {
2963                                 callback_peer_request(peer);
2964                                 g_hash_table_remove(pending_peer_connection,
2965                                                 peer->path);
2966                         }
2967
2968                         dbus_free(data);
2969                 }
2970
2971                 return;
2972         }
2973
2974         if (g_strcmp0(key, "DeviceAddress") == 0) {
2975                 unsigned char *dev_addr;
2976                 DBusMessageIter array;
2977                 int len;
2978
2979                 dbus_message_iter_recurse(iter, &array);
2980                 dbus_message_iter_get_fixed_array(&array, &dev_addr, &len);
2981
2982                 if (len == ETH_ALEN)
2983                         memcpy(peer->device_address, dev_addr, len);
2984         } else if (g_strcmp0(key, "DeviceName") == 0) {
2985                 const char *str = NULL;
2986
2987                 dbus_message_iter_get_basic(iter, &str);
2988                 if (str)
2989                         peer->name = g_strdup(str);
2990         } else if (g_strcmp0(key, "config_method") == 0) {
2991                 uint16_t wps_config;
2992
2993                 dbus_message_iter_get_basic(iter, &wps_config);
2994
2995                 if (wps_config & G_SUPPLICANT_WPS_CONFIG_PBC)
2996                         peer->wps_capabilities |= G_SUPPLICANT_WPS_PBC;
2997                 if (wps_config & ~G_SUPPLICANT_WPS_CONFIG_PBC)
2998                         peer->wps_capabilities |= G_SUPPLICANT_WPS_PIN;
2999         } else if (g_strcmp0(key, "Groups") == 0) {
3000                 data->old_groups = peer->groups;
3001                 peer->groups = NULL;
3002
3003                 supplicant_dbus_array_foreach(iter,
3004                                                 peer_groups_relation, data);
3005                 if (g_slist_length(data->old_groups) > 0) {
3006                         g_slist_free_full(data->old_groups, g_free);
3007                         data->groups_changed = true;
3008                 }
3009         } else if (g_strcmp0(key, "IEs") == 0) {
3010                 DBusMessageIter array;
3011                 unsigned char *ie;
3012                 int ie_len;
3013
3014                 dbus_message_iter_recurse(iter, &array);
3015                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
3016
3017                 if (!ie || ie_len < 2)
3018                         return;
3019
3020                 if (peer->widi_ies) {
3021                         if (memcmp(peer->widi_ies, ie, ie_len) == 0)
3022                                 return;
3023
3024                         g_free(peer->widi_ies);
3025                         peer->widi_ies_length = 0;
3026                 }
3027
3028                 peer->widi_ies = g_malloc0(ie_len * sizeof(unsigned char));
3029
3030                 memcpy(peer->widi_ies, ie, ie_len);
3031                 peer->widi_ies_length = ie_len;
3032                 data->services_changed = true;
3033         }
3034 }
3035
3036 static void signal_peer_found(const char *path, DBusMessageIter *iter)
3037 {
3038         struct peer_property_data *property_data;
3039         GSupplicantInterface *interface;
3040         const char *obj_path = NULL;
3041         GSupplicantPeer *peer;
3042
3043         SUPPLICANT_DBG("");
3044
3045         interface = g_hash_table_lookup(interface_table, path);
3046         if (!interface)
3047                 return;
3048
3049         dbus_message_iter_get_basic(iter, &obj_path);
3050         if (!obj_path || g_strcmp0(obj_path, "/") == 0)
3051                 return;
3052
3053         peer = g_hash_table_lookup(interface->peer_table, obj_path);
3054         if (peer)
3055                 return;
3056
3057         peer = g_try_new0(GSupplicantPeer, 1);
3058         if (!peer)
3059                 return;
3060
3061         peer->interface = interface;
3062         peer->path = g_strdup(obj_path);
3063         g_hash_table_insert(interface->peer_table, peer->path, peer);
3064         g_hash_table_replace(peer_mapping, peer->path, interface);
3065
3066         property_data = dbus_malloc0(sizeof(struct peer_property_data));
3067         property_data->peer = peer;
3068
3069         dbus_message_iter_next(iter);
3070         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
3071                 supplicant_dbus_property_foreach(iter, peer_property,
3072                                                         property_data);
3073                 peer_property(NULL, NULL, property_data);
3074                 return;
3075         }
3076
3077         supplicant_dbus_property_get_all(obj_path,
3078                                         SUPPLICANT_INTERFACE ".Peer",
3079                                         peer_property, property_data, NULL);
3080 }
3081
3082 static void signal_peer_lost(const char *path, DBusMessageIter *iter)
3083 {
3084         GSupplicantInterface *interface;
3085         const char *obj_path = NULL;
3086         GSupplicantPeer *peer;
3087
3088         SUPPLICANT_DBG("");
3089
3090         interface = g_hash_table_lookup(interface_table, path);
3091         if (!interface)
3092                 return;
3093
3094         dbus_message_iter_get_basic(iter, &obj_path);
3095         if (!obj_path || g_strcmp0(obj_path, "/") == 0)
3096                 return;
3097
3098         peer = g_hash_table_lookup(interface->peer_table, obj_path);
3099         if (!peer)
3100                 return;
3101
3102         g_hash_table_remove(interface->peer_table, obj_path);
3103 }
3104
3105 static void signal_peer_changed(const char *path, DBusMessageIter *iter)
3106 {
3107         struct peer_property_data *property_data;
3108         GSupplicantInterface *interface;
3109         GSupplicantPeer *peer;
3110
3111         SUPPLICANT_DBG("");
3112
3113         interface = g_hash_table_lookup(peer_mapping, path);
3114         if (!interface)
3115                 return;
3116
3117         peer = g_hash_table_lookup(interface->peer_table, path);
3118         if (!peer) {
3119                 g_hash_table_remove(peer_mapping, path);
3120                 return;
3121         }
3122
3123         property_data = dbus_malloc0(sizeof(struct peer_property_data));
3124         property_data->peer = peer;
3125
3126         supplicant_dbus_property_foreach(iter, peer_property, property_data);
3127         if (property_data->services_changed)
3128                 callback_peer_changed(peer,
3129                                         G_SUPPLICANT_PEER_SERVICES_CHANGED);
3130
3131         if (property_data->groups_changed)
3132                 callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_CHANGED);
3133
3134         dbus_free(property_data);
3135
3136         if (!g_supplicant_peer_is_in_a_group(peer))
3137                 peer->connection_requested = false;
3138 }
3139
3140 struct group_sig_data {
3141         const char *peer_obj_path;
3142         unsigned char iface_address[ETH_ALEN];
3143         const char *interface_obj_path;
3144         const char *group_obj_path;
3145         int role;
3146 };
3147
3148 static void group_sig_property(const char *key, DBusMessageIter *iter,
3149                                                         void *user_data)
3150 {
3151         struct group_sig_data *data = user_data;
3152
3153         if (!key)
3154                 return;
3155
3156         if (g_strcmp0(key, "peer_interface_addr") == 0) {
3157                 unsigned char *dev_addr;
3158                 DBusMessageIter array;
3159                 int len;
3160
3161                 dbus_message_iter_recurse(iter, &array);
3162                 dbus_message_iter_get_fixed_array(&array, &dev_addr, &len);
3163
3164                 if (len == ETH_ALEN)
3165                         memcpy(data->iface_address, dev_addr, len);
3166         } else if (g_strcmp0(key, "role") == 0) {
3167                 const char *str = NULL;
3168
3169                 dbus_message_iter_get_basic(iter, &str);
3170                 if (g_strcmp0(str, "GO") == 0)
3171                         data->role = G_SUPPLICANT_GROUP_ROLE_GO;
3172                 else
3173                         data->role = G_SUPPLICANT_GROUP_ROLE_CLIENT;
3174         } else if (g_strcmp0(key, "peer_object") == 0)
3175                 dbus_message_iter_get_basic(iter, &data->peer_obj_path);
3176         else if (g_strcmp0(key, "interface_object") == 0)
3177                 dbus_message_iter_get_basic(iter, &data->interface_obj_path);
3178         else if (g_strcmp0(key, "group_object") == 0)
3179                 dbus_message_iter_get_basic(iter, &data->group_obj_path);
3180
3181 }
3182
3183 static void signal_group_success(const char *path, DBusMessageIter *iter)
3184 {
3185         GSupplicantInterface *interface;
3186         struct group_sig_data data = {};
3187         GSupplicantPeer *peer;
3188
3189         SUPPLICANT_DBG("");
3190
3191         interface = g_hash_table_lookup(interface_table, path);
3192         if (!interface)
3193                 return;
3194
3195         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3196         if (!data.peer_obj_path)
3197                 return;
3198
3199         peer = g_hash_table_lookup(interface->peer_table, data.peer_obj_path);
3200         if (!peer)
3201                 return;
3202
3203         memcpy(peer->iface_address, data.iface_address, ETH_ALEN);
3204         interface->pending_peer_path = peer->path;
3205 }
3206
3207 static void signal_group_failure(const char *path, DBusMessageIter *iter)
3208 {
3209         GSupplicantInterface *interface;
3210         struct group_sig_data data = {};
3211         GSupplicantPeer *peer;
3212
3213         SUPPLICANT_DBG("");
3214
3215         interface = g_hash_table_lookup(interface_table, path);
3216         if (!interface)
3217                 return;
3218
3219         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3220         if (!data.peer_obj_path)
3221                 return;
3222
3223         peer = g_hash_table_lookup(interface->peer_table, data.peer_obj_path);
3224         if (!peer)
3225                 return;
3226
3227         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_FAILED);
3228         peer->connection_requested = false;
3229 }
3230
3231 static void signal_group_started(const char *path, DBusMessageIter *iter)
3232 {
3233         GSupplicantInterface *interface, *g_interface;
3234         struct group_sig_data data = {};
3235         GSupplicantGroup *group;
3236         GSupplicantPeer *peer;
3237
3238         SUPPLICANT_DBG("");
3239
3240         interface = g_hash_table_lookup(interface_table, path);
3241         if (!interface)
3242                 return;
3243
3244         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3245         if (!data.interface_obj_path || !data.group_obj_path)
3246                 return;
3247
3248         peer = g_hash_table_lookup(interface->peer_table,
3249                                                 interface->pending_peer_path);
3250         interface->pending_peer_path = NULL;
3251         if (!peer)
3252                 return;
3253
3254         g_interface = g_hash_table_lookup(interface_table,
3255                                                 data.interface_obj_path);
3256         if (!g_interface)
3257                 return;
3258
3259         group = g_hash_table_lookup(interface->group_table,
3260                                                 data.group_obj_path);
3261         if (group)
3262                 return;
3263
3264         group = g_try_new0(GSupplicantGroup, 1);
3265         if (!group)
3266                 return;
3267
3268         group->interface = g_interface;
3269         group->orig_interface = interface;
3270         group->path = g_strdup(data.group_obj_path);
3271         group->role = data.role;
3272
3273         g_hash_table_insert(interface->group_table, group->path, group);
3274         g_hash_table_replace(group_mapping, group->path, group);
3275
3276         peer->current_group_iface = g_interface;
3277         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_STARTED);
3278 }
3279
3280 static void remove_peer_group_interface(GHashTable *group_table,
3281                                 const char* path)
3282 {
3283         GSupplicantGroup *group;
3284         GHashTableIter iter;
3285         gpointer value, key;
3286
3287         if (!group_table)
3288                 return;
3289
3290         group = g_hash_table_lookup(group_table, path);
3291
3292         if (!group || !group->orig_interface)
3293                 return;
3294
3295         g_hash_table_iter_init(&iter, group->orig_interface->peer_table);
3296
3297         while (g_hash_table_iter_next(&iter, &key, &value)) {
3298                 GSupplicantPeer *peer = value;
3299
3300                 if (peer->current_group_iface == group->interface)
3301                         peer->current_group_iface = NULL;
3302         }
3303 }
3304
3305 static void signal_group_finished(const char *path, DBusMessageIter *iter)
3306 {
3307         GSupplicantInterface *interface;
3308         struct group_sig_data data = {};
3309
3310         SUPPLICANT_DBG("");
3311
3312         interface = g_hash_table_lookup(interface_table, path);
3313         if (!interface)
3314                 return;
3315
3316         supplicant_dbus_property_foreach(iter, group_sig_property, &data);
3317         if (!data.interface_obj_path || !data.group_obj_path)
3318                 return;
3319
3320         remove_peer_group_interface(interface->group_table, data.group_obj_path);
3321
3322         g_hash_table_remove(group_mapping, data.group_obj_path);
3323
3324         g_hash_table_remove(interface->group_table, data.group_obj_path);
3325 }
3326
3327 static void signal_group_request(const char *path, DBusMessageIter *iter)
3328 {
3329         GSupplicantInterface *interface;
3330         GSupplicantPeer *peer;
3331         const char *obj_path;
3332
3333         SUPPLICANT_DBG("");
3334
3335         interface = g_hash_table_lookup(interface_table, path);
3336         if (!interface)
3337                 return;
3338
3339         dbus_message_iter_get_basic(iter, &obj_path);
3340         if (!obj_path || !g_strcmp0(obj_path, "/"))
3341                 return;
3342
3343         peer = g_hash_table_lookup(interface->peer_table, obj_path);
3344         if (!peer)
3345                 return;
3346
3347         /*
3348          * Peer has been previously found and property set,
3349          * otherwise, defer connection to when peer property
3350          * is set.
3351          */
3352         if (peer->identifier)
3353                 callback_peer_request(peer);
3354         else
3355                 g_hash_table_replace(pending_peer_connection, peer->path, peer);
3356 }
3357
3358 static void signal_group_peer_joined(const char *path, DBusMessageIter *iter)
3359 {
3360         const char *peer_path = NULL;
3361         GSupplicantInterface *interface;
3362         GSupplicantGroup *group;
3363         GSupplicantPeer *peer;
3364
3365         SUPPLICANT_DBG("");
3366
3367         group = g_hash_table_lookup(group_mapping, path);
3368         if (!group)
3369                 return;
3370
3371         dbus_message_iter_get_basic(iter, &peer_path);
3372         if (!peer_path)
3373                 return;
3374
3375         interface = g_hash_table_lookup(peer_mapping, peer_path);
3376         if (!interface)
3377                 return;
3378
3379         peer = g_hash_table_lookup(interface->peer_table, peer_path);
3380         if (!peer)
3381                 return;
3382
3383         group->members = g_slist_prepend(group->members, g_strdup(peer_path));
3384
3385         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_JOINED);
3386 }
3387
3388 static void signal_group_peer_disconnected(const char *path, DBusMessageIter *iter)
3389 {
3390         const char *peer_path = NULL;
3391         GSupplicantInterface *interface;
3392         GSupplicantGroup *group;
3393         GSupplicantPeer *peer;
3394         GSList *elem;
3395
3396         SUPPLICANT_DBG("");
3397
3398         group = g_hash_table_lookup(group_mapping, path);
3399         if (!group)
3400                 return;
3401
3402         dbus_message_iter_get_basic(iter, &peer_path);
3403         if (!peer_path)
3404                 return;
3405
3406         for (elem = group->members; elem; elem = elem->next) {
3407                 if (!g_strcmp0(elem->data, peer_path))
3408                         break;
3409         }
3410
3411         if (!elem)
3412                 return;
3413
3414         g_free(elem->data);
3415         group->members = g_slist_delete_link(group->members, elem);
3416
3417         interface = g_hash_table_lookup(peer_mapping, peer_path);
3418         if (!interface)
3419                 return;
3420
3421         peer = g_hash_table_lookup(interface->peer_table, peer_path);
3422         if (!peer)
3423                 return;
3424
3425         callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_DISCONNECTED);
3426         peer->connection_requested = false;
3427 }
3428
3429 static struct {
3430         const char *interface;
3431         const char *member;
3432         void (*function) (const char *path, DBusMessageIter *iter);
3433 } signal_map[] = {
3434         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
3435
3436         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
3437         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
3438         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
3439         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
3440
3441         { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
3442         { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done         },
3443         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added         },
3444         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed       },
3445         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
3446         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
3447
3448         { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed   },
3449
3450         { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
3451         { SUPPLICANT_INTERFACE ".Interface.WPS", "Event",       signal_wps_event       },
3452 #if defined TIZEN_EXT
3453         { "org.tizen.system.deviced.PowerOff", "ChangeState", signal_power_off },
3454 #endif
3455
3456         { SUPPLICANT_INTERFACE".Interface", "StaAuthorized", signal_station_connected      },
3457         { SUPPLICANT_INTERFACE".Interface", "StaDeauthorized", signal_station_disconnected },
3458
3459         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceFound", signal_peer_found },
3460         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceLost",  signal_peer_lost  },
3461
3462         { SUPPLICANT_INTERFACE ".Peer", "PropertiesChanged", signal_peer_changed },
3463
3464         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationSuccess", signal_group_success },
3465         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationFailure", signal_group_failure },
3466         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupStarted", signal_group_started },
3467         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupFinished", signal_group_finished },
3468         { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationRequest", signal_group_request },
3469
3470         { SUPPLICANT_INTERFACE ".Group", "PeerJoined", signal_group_peer_joined },
3471         { SUPPLICANT_INTERFACE ".Group", "PeerDisconnected", signal_group_peer_disconnected },
3472
3473         { }
3474 };
3475
3476 static DBusHandlerResult g_supplicant_filter(DBusConnection *conn,
3477                                         DBusMessage *message, void *data)
3478 {
3479         DBusMessageIter iter;
3480         const char *path;
3481         int i;
3482
3483         path = dbus_message_get_path(message);
3484         if (!path)
3485                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3486
3487         if (!dbus_message_iter_init(message, &iter))
3488                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3489
3490         for (i = 0; signal_map[i].interface; i++) {
3491                 if (!dbus_message_has_interface(message, signal_map[i].interface))
3492                         continue;
3493
3494                 if (!dbus_message_has_member(message, signal_map[i].member))
3495                         continue;
3496
3497                 signal_map[i].function(path, &iter);
3498                 break;
3499         }
3500
3501         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3502 }
3503
3504 void g_supplicant_interface_cancel(GSupplicantInterface *interface)
3505 {
3506         SUPPLICANT_DBG("Cancelling any pending DBus calls");
3507         supplicant_dbus_method_call_cancel_all(interface);
3508         supplicant_dbus_property_call_cancel_all(interface);
3509 }
3510
3511 struct supplicant_regdom {
3512         GSupplicantCountryCallback callback;
3513         const char *alpha2;
3514         const void *user_data;
3515 };
3516
3517 static void country_result(const char *error,
3518                                 DBusMessageIter *iter, void *user_data)
3519 {
3520         struct supplicant_regdom *regdom = user_data;
3521         int result = 0;
3522
3523         SUPPLICANT_DBG("Country setting result");
3524
3525         if (!user_data)
3526                 return;
3527
3528         if (error) {
3529                 SUPPLICANT_DBG("Country setting failure %s", error);
3530                 result = -EINVAL;
3531         }
3532
3533         if (regdom->callback)
3534                 regdom->callback(result, regdom->alpha2,
3535                                         (void *) regdom->user_data);
3536
3537         g_free(regdom);
3538 }
3539
3540 static void country_params(DBusMessageIter *iter, void *user_data)
3541 {
3542         struct supplicant_regdom *regdom = user_data;
3543
3544         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
3545                                                         &regdom->alpha2);
3546 }
3547
3548 int g_supplicant_set_country(const char *alpha2,
3549                                 GSupplicantCountryCallback callback,
3550                                         const void *user_data)
3551 {
3552         struct supplicant_regdom *regdom;
3553
3554         SUPPLICANT_DBG("Country setting %s", alpha2);
3555
3556         if (!system_available)
3557                 return -EFAULT;
3558
3559         regdom = dbus_malloc0(sizeof(*regdom));
3560         if (!regdom)
3561                 return -ENOMEM;
3562
3563         regdom->callback = callback;
3564         regdom->alpha2 = alpha2;
3565         regdom->user_data = user_data;
3566
3567         return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
3568                                         "Country", DBUS_TYPE_STRING_AS_STRING,
3569                                         country_params, country_result,
3570                                         regdom, NULL);
3571 }
3572
3573 int g_supplicant_interface_set_country(GSupplicantInterface *interface,
3574                                         GSupplicantCountryCallback callback,
3575                                                         const char *alpha2,
3576                                                         void *user_data)
3577 {
3578         struct supplicant_regdom *regdom;
3579
3580         regdom = dbus_malloc0(sizeof(*regdom));
3581         if (!regdom)
3582                 return -ENOMEM;
3583
3584         regdom->callback = callback;
3585         regdom->alpha2 = alpha2;
3586         regdom->user_data = user_data;
3587
3588         return supplicant_dbus_property_set(interface->path,
3589                                 SUPPLICANT_INTERFACE ".Interface",
3590                                 "Country", DBUS_TYPE_STRING_AS_STRING,
3591                                 country_params, country_result,
3592                                         regdom, NULL);
3593 }
3594
3595 bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface)
3596 {
3597         if (!interface)
3598                 return false;
3599
3600         return interface->p2p_support;
3601 }
3602
3603 struct supplicant_p2p_dev_config {
3604         char *device_name;
3605         char *dev_type;
3606 };
3607
3608 static void p2p_device_config_result(const char *error,
3609                                         DBusMessageIter *iter, void *user_data)
3610 {
3611         struct supplicant_p2p_dev_config *config = user_data;
3612
3613         if (error)
3614                 SUPPLICANT_DBG("Unable to set P2P Device configuration: %s",
3615                                                                         error);
3616
3617         g_free(config->device_name);
3618         g_free(config->dev_type);
3619         dbus_free(config);
3620 }
3621
3622 static int dev_type_str2bin(const char *type, unsigned char dev_type[8])
3623 {
3624         int length, pos, end;
3625         char b[3] = {};
3626         char *e = NULL;
3627
3628         end = strlen(type);
3629         for (length = pos = 0; type[pos] != '\0' && length < 8; length++) {
3630                 if (pos+2 > end)
3631                         return 0;
3632
3633                 b[0] = type[pos];
3634                 b[1] = type[pos+1];
3635
3636                 dev_type[length] = strtol(b, &e, 16);
3637                 if (e && *e != '\0')
3638                         return 0;
3639
3640                 pos += 2;
3641         }
3642
3643         return 8;
3644 }
3645
3646 static void p2p_device_config_params(DBusMessageIter *iter, void *user_data)
3647 {
3648         struct supplicant_p2p_dev_config *config = user_data;
3649         DBusMessageIter dict;
3650
3651         supplicant_dbus_dict_open(iter, &dict);
3652
3653         supplicant_dbus_dict_append_basic(&dict, "DeviceName",
3654                                 DBUS_TYPE_STRING, &config->device_name);
3655
3656         if (config->dev_type) {
3657                 unsigned char dev_type[8] = {}, *type;
3658                 int len;
3659
3660                 len = dev_type_str2bin(config->dev_type, dev_type);
3661                 if (len) {
3662                         type = dev_type;
3663                         supplicant_dbus_dict_append_fixed_array(&dict,
3664                                         "PrimaryDeviceType",
3665                                         DBUS_TYPE_BYTE, &type, len);
3666                 }
3667         }
3668
3669         supplicant_dbus_dict_close(iter, &dict);
3670 }
3671
3672 int g_supplicant_interface_set_p2p_device_config(GSupplicantInterface *interface,
3673                                         const char *device_name,
3674                                         const char *primary_dev_type)
3675 {
3676         struct supplicant_p2p_dev_config *config;
3677         int ret;
3678
3679         SUPPLICANT_DBG("P2P Device settings %s/%s",
3680                                         device_name, primary_dev_type);
3681
3682         config = dbus_malloc0(sizeof(*config));
3683         if (!config)
3684                 return -ENOMEM;
3685
3686         config->device_name = g_strdup(device_name);
3687         config->dev_type = g_strdup(primary_dev_type);
3688
3689         ret = supplicant_dbus_property_set(interface->path,
3690                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
3691                                 "P2PDeviceConfig",
3692                                 DBUS_TYPE_ARRAY_AS_STRING
3693                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
3694                                 DBUS_TYPE_STRING_AS_STRING
3695                                 DBUS_TYPE_VARIANT_AS_STRING
3696                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
3697                                 p2p_device_config_params,
3698                                 p2p_device_config_result, config, NULL);
3699         if (ret < 0) {
3700                 g_free(config->device_name);
3701                 g_free(config->dev_type);
3702                 dbus_free(config);
3703                 SUPPLICANT_DBG("Unable to set P2P Device configuration");
3704         }
3705
3706         return ret;
3707 }
3708
3709 static gboolean peer_lookup_by_identifier(gpointer key, gpointer value,
3710                                                         gpointer user_data)
3711 {
3712         const GSupplicantPeer *peer = value;
3713         const char *identifier = user_data;
3714
3715         if (!g_strcmp0(identifier, peer->identifier))
3716                 return TRUE;
3717
3718         return FALSE;
3719 }
3720
3721 GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interface,
3722                                                         const char *identifier)
3723 {
3724         GSupplicantPeer *peer;
3725
3726         peer = g_hash_table_find(interface->peer_table,
3727                                         peer_lookup_by_identifier,
3728                                         (void *) identifier);
3729         return peer;
3730 }
3731
3732 struct interface_data {
3733         GSupplicantInterface *interface;
3734         char *path; /* Interface path cannot be taken from interface (above) as
3735                      * it might have been freed already.
3736                      */
3737         GSupplicantInterfaceCallback callback;
3738         void *user_data;
3739 };
3740
3741 struct interface_create_data {
3742         char *ifname;
3743         char *driver;
3744         char *bridge;
3745         GSupplicantInterface *interface;
3746         GSupplicantInterfaceCallback callback;
3747         void *user_data;
3748 };
3749
3750 struct interface_connect_data {
3751         GSupplicantInterface *interface;
3752         char *path;
3753         GSupplicantInterfaceCallback callback;
3754         union {
3755                 GSupplicantSSID *ssid;
3756                 GSupplicantPeerParams *peer;
3757         };
3758         void *user_data;
3759 };
3760
3761 struct interface_scan_data {
3762         GSupplicantInterface *interface;
3763         char *path;
3764         GSupplicantInterfaceCallback callback;
3765         GSupplicantScanParams *scan_params;
3766         void *user_data;
3767 };
3768
3769 static void interface_create_data_free(struct interface_create_data *data)
3770 {
3771         g_free(data->ifname);
3772         g_free(data->driver);
3773         g_free(data->bridge);
3774         dbus_free(data);
3775 }
3776
3777 static bool interface_exists(GSupplicantInterface *interface,
3778                                 const char *path)
3779 {
3780         GSupplicantInterface *tmp;
3781
3782         tmp = g_hash_table_lookup(interface_table, path);
3783         if (tmp && tmp == interface)
3784                 return true;
3785
3786         return false;
3787 }
3788
3789 static void interface_create_property(const char *key, DBusMessageIter *iter,
3790                                                         void *user_data)
3791 {
3792         struct interface_create_data *data = user_data;
3793         GSupplicantInterface *interface = data->interface;
3794
3795         if (!key) {
3796                 if (data->callback) {
3797                         data->callback(0, data->interface, data->user_data);
3798 #if !defined TIZEN_EXT
3799                         callback_p2p_support(interface);
3800 #endif
3801                 }
3802
3803                 interface_create_data_free(data);
3804         }
3805
3806         interface_property(key, iter, interface);
3807 }
3808
3809 static void interface_create_result(const char *error,
3810                                 DBusMessageIter *iter, void *user_data)
3811 {
3812         struct interface_create_data *data = user_data;
3813         const char *path = NULL;
3814         int err;
3815
3816         SUPPLICANT_DBG("");
3817
3818         if (error) {
3819                 g_warning("error %s", error);
3820                 err = -EIO;
3821                 goto done;
3822         }
3823
3824         dbus_message_iter_get_basic(iter, &path);
3825         if (!path) {
3826                 err = -EINVAL;
3827                 goto done;
3828         }
3829
3830         if (!system_available) {
3831                 err = -EFAULT;
3832                 goto done;
3833         }
3834
3835         data->interface = g_hash_table_lookup(interface_table, path);
3836         if (!data->interface) {
3837                 data->interface = interface_alloc(path);
3838                 if (!data->interface) {
3839                         err = -ENOMEM;
3840                         goto done;
3841                 }
3842         }
3843
3844         err = supplicant_dbus_property_get_all(path,
3845                                         SUPPLICANT_INTERFACE ".Interface",
3846                                         interface_create_property, data,
3847                                         NULL);
3848         if (err == 0)
3849                 return;
3850
3851 done:
3852         if (data->callback)
3853                 data->callback(err, NULL, data->user_data);
3854
3855         interface_create_data_free(data);
3856 }
3857
3858 static void interface_create_params(DBusMessageIter *iter, void *user_data)
3859 {
3860         struct interface_create_data *data = user_data;
3861         DBusMessageIter dict;
3862
3863         SUPPLICANT_DBG("");
3864
3865         supplicant_dbus_dict_open(iter, &dict);
3866
3867         supplicant_dbus_dict_append_basic(&dict, "Ifname",
3868                                         DBUS_TYPE_STRING, &data->ifname);
3869
3870         if (data->driver)
3871                 supplicant_dbus_dict_append_basic(&dict, "Driver",
3872                                         DBUS_TYPE_STRING, &data->driver);
3873
3874         if (data->bridge)
3875                 supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
3876                                         DBUS_TYPE_STRING, &data->bridge);
3877
3878         supplicant_dbus_dict_close(iter, &dict);
3879 }
3880
3881 static void interface_get_result(const char *error,
3882                                 DBusMessageIter *iter, void *user_data)
3883 {
3884         struct interface_create_data *data = user_data;
3885         GSupplicantInterface *interface;
3886         const char *path = NULL;
3887         int err;
3888
3889         SUPPLICANT_DBG("");
3890
3891         if (error) {
3892                 SUPPLICANT_DBG("Interface not created yet");
3893                 goto create;
3894         }
3895
3896         dbus_message_iter_get_basic(iter, &path);
3897         if (!path) {
3898                 err = -EINVAL;
3899                 goto done;
3900         }
3901
3902         interface = g_hash_table_lookup(interface_table, path);
3903         if (!interface) {
3904                 err = -ENOENT;
3905                 goto done;
3906         }
3907
3908         if (data->callback) {
3909                 data->callback(0, interface, data->user_data);
3910 #if !defined TIZEN_EXT
3911                 callback_p2p_support(interface);
3912 #endif
3913         }
3914
3915         interface_create_data_free(data);
3916
3917         return;
3918
3919 create:
3920         if (!system_available) {
3921                 err = -EFAULT;
3922                 goto done;
3923         }
3924
3925         SUPPLICANT_DBG("Creating interface");
3926
3927         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
3928                                                 SUPPLICANT_INTERFACE,
3929                                                 "CreateInterface",
3930                                                 interface_create_params,
3931                                                 interface_create_result, data,
3932                                                 NULL);
3933         if (err == 0)
3934                 return;
3935
3936 done:
3937         if (data->callback)
3938                 data->callback(err, NULL, data->user_data);
3939
3940         interface_create_data_free(data);
3941 }
3942
3943 static void interface_get_params(DBusMessageIter *iter, void *user_data)
3944 {
3945         struct interface_create_data *data = user_data;
3946
3947         SUPPLICANT_DBG("");
3948
3949         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
3950 }
3951
3952 int g_supplicant_interface_create(const char *ifname, const char *driver,
3953                                         const char *bridge,
3954                                         GSupplicantInterfaceCallback callback,
3955                                                         void *user_data)
3956 {
3957         struct interface_create_data *data;
3958         int ret;
3959
3960         SUPPLICANT_DBG("ifname %s", ifname);
3961
3962         if (!ifname)
3963                 return -EINVAL;
3964
3965         if (!system_available)
3966                 return -EFAULT;
3967
3968         data = dbus_malloc0(sizeof(*data));
3969         if (!data)
3970                 return -ENOMEM;
3971
3972         data->ifname = g_strdup(ifname);
3973         data->driver = g_strdup(driver);
3974         data->bridge = g_strdup(bridge);
3975         data->callback = callback;
3976         data->user_data = user_data;
3977
3978         ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
3979                                                 SUPPLICANT_INTERFACE,
3980                                                 "GetInterface",
3981                                                 interface_get_params,
3982                                                 interface_get_result, data,
3983                                                 NULL);
3984         if (ret < 0)
3985                 interface_create_data_free(data);
3986
3987         return ret;
3988 }
3989
3990 static void interface_remove_result(const char *error,
3991                                 DBusMessageIter *iter, void *user_data)
3992 {
3993         struct interface_data *data = user_data;
3994         int err;
3995
3996         if (error) {
3997                 err = -EIO;
3998                 goto done;
3999         }
4000
4001         if (!system_available) {
4002                 err = -EFAULT;
4003                 goto done;
4004         }
4005
4006         /*
4007          * The gsupplicant interface is already freed by the InterfaceRemoved
4008          * signal callback. Simply invoke the interface_data callback.
4009          */
4010         err = 0;
4011
4012 done:
4013         g_free(data->path);
4014
4015         if (data->callback)
4016                 data->callback(err, NULL, data->user_data);
4017
4018         dbus_free(data);
4019 }
4020
4021
4022 static void interface_remove_params(DBusMessageIter *iter, void *user_data)
4023 {
4024         struct interface_data *data = user_data;
4025
4026         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
4027                                                         &data->interface->path);
4028 }
4029
4030
4031 int g_supplicant_interface_remove(GSupplicantInterface *interface,
4032                         GSupplicantInterfaceCallback callback,
4033                                                         void *user_data)
4034 {
4035         struct interface_data *data;
4036         int ret;
4037
4038         if (!interface)
4039                 return -EINVAL;
4040
4041         if (!system_available)
4042                 return -EFAULT;
4043
4044         g_supplicant_interface_cancel(interface);
4045
4046         data = dbus_malloc0(sizeof(*data));
4047         if (!data)
4048                 return -ENOMEM;
4049
4050         data->interface = interface;
4051         data->path = g_strdup(interface->path);
4052         data->callback = callback;
4053         data->user_data = user_data;
4054
4055         ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
4056                                                 SUPPLICANT_INTERFACE,
4057                                                 "RemoveInterface",
4058                                                 interface_remove_params,
4059                                                 interface_remove_result, data,
4060                                                 NULL);
4061         if (ret < 0) {
4062                 g_free(data->path);
4063                 dbus_free(data);
4064         }
4065         return ret;
4066 }
4067
4068 static void interface_scan_result(const char *error,
4069                                 DBusMessageIter *iter, void *user_data)
4070 {
4071         struct interface_scan_data *data = user_data;
4072         int err = 0;
4073
4074         if (error) {
4075                 SUPPLICANT_DBG("error %s", error);
4076                 err = -EIO;
4077         }
4078
4079         /* A non ready interface cannot send/receive anything */
4080         if (interface_exists(data->interface, data->path)) {
4081                 if (!data->interface->ready)
4082                         err = -ENOLINK;
4083         }
4084
4085         g_free(data->path);
4086
4087         if (err != 0) {
4088                 if (data->callback)
4089                         data->callback(err, data->interface, data->user_data);
4090         } else {
4091                 data->interface->scan_callback = data->callback;
4092                 data->interface->scan_data = data->user_data;
4093         }
4094
4095         if (data->scan_params)
4096                 g_supplicant_free_scan_params(data->scan_params);
4097
4098         dbus_free(data);
4099 }
4100
4101 static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq)
4102 {
4103         DBusMessageIter data;
4104         unsigned int width = 0; /* Not used by wpa_supplicant atm */
4105
4106         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data);
4107
4108         dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq);
4109         dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width);
4110
4111         dbus_message_iter_close_container(iter, &data);
4112 }
4113
4114 static void add_scan_frequencies(DBusMessageIter *iter,
4115                                                 void *user_data)
4116 {
4117         GSupplicantScanParams *scan_data = user_data;
4118         unsigned int freq;
4119         int i;
4120
4121         for (i = 0; i < scan_data->num_freqs; i++) {
4122                 freq = scan_data->freqs[i];
4123                 if (!freq)
4124                         break;
4125
4126                 add_scan_frequency(iter, freq);
4127         }
4128 }
4129
4130 static void append_ssid(DBusMessageIter *iter,
4131                         const void *ssid, unsigned int len)
4132 {
4133         DBusMessageIter array;
4134
4135         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
4136         DBUS_TYPE_BYTE_AS_STRING, &array);
4137
4138         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
4139                                                                 &ssid, len);
4140         dbus_message_iter_close_container(iter, &array);
4141 }
4142
4143 static void append_ssids(DBusMessageIter *iter, void *user_data)
4144 {
4145         GSupplicantScanParams *scan_data = user_data;
4146         GSList *list;
4147
4148         for (list = scan_data->ssids; list; list = list->next) {
4149                 struct scan_ssid *scan_ssid = list->data;
4150
4151                 append_ssid(iter, scan_ssid->ssid, scan_ssid->ssid_len);
4152         }
4153 }
4154
4155 static void supplicant_add_scan_frequency(DBusMessageIter *dict,
4156                 supplicant_dbus_array_function function,
4157                                         void *user_data)
4158 {
4159         GSupplicantScanParams *scan_params = user_data;
4160         DBusMessageIter entry, value, array;
4161         const char *key = "Channels";
4162
4163         if (scan_params->freqs && scan_params->freqs[0] != 0) {
4164                 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
4165                                                 NULL, &entry);
4166
4167                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
4168
4169                 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
4170                                         DBUS_TYPE_ARRAY_AS_STRING
4171                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
4172                                         DBUS_TYPE_UINT32_AS_STRING
4173                                         DBUS_TYPE_UINT32_AS_STRING
4174                                         DBUS_STRUCT_END_CHAR_AS_STRING,
4175                                         &value);
4176
4177                 dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
4178                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
4179                                         DBUS_TYPE_UINT32_AS_STRING
4180                                         DBUS_TYPE_UINT32_AS_STRING
4181                                         DBUS_STRUCT_END_CHAR_AS_STRING,
4182                                         &array);
4183
4184                 if (function)
4185                         function(&array, user_data);
4186
4187                 dbus_message_iter_close_container(&value, &array);
4188                 dbus_message_iter_close_container(&entry, &value);
4189                 dbus_message_iter_close_container(dict, &entry);
4190         }
4191 }
4192
4193 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
4194 {
4195         DBusMessageIter dict;
4196         const char *type = "passive";
4197         struct interface_scan_data *data = user_data;
4198
4199         supplicant_dbus_dict_open(iter, &dict);
4200
4201         if (data && data->scan_params) {
4202                 type = "active";
4203
4204                 supplicant_dbus_dict_append_basic(&dict, "Type",
4205                                         DBUS_TYPE_STRING, &type);
4206
4207                 supplicant_dbus_dict_append_array(&dict, "SSIDs",
4208                                                 DBUS_TYPE_STRING,
4209                                                 append_ssids,
4210                                                 data->scan_params);
4211
4212                 supplicant_add_scan_frequency(&dict, add_scan_frequencies,
4213                                                 data->scan_params);
4214         } else
4215                 supplicant_dbus_dict_append_basic(&dict, "Type",
4216                                         DBUS_TYPE_STRING, &type);
4217
4218         supplicant_dbus_dict_close(iter, &dict);
4219 }
4220
4221 static int interface_ready_to_scan(GSupplicantInterface *interface)
4222 {
4223         if (!interface)
4224                 return -EINVAL;
4225
4226         if (!system_available)
4227                 return -EFAULT;
4228
4229         if (interface->scanning)
4230                 return -EALREADY;
4231
4232         switch (interface->state) {
4233         case G_SUPPLICANT_STATE_AUTHENTICATING:
4234         case G_SUPPLICANT_STATE_ASSOCIATING:
4235         case G_SUPPLICANT_STATE_ASSOCIATED:
4236         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4237         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4238                 return -EBUSY;
4239         case G_SUPPLICANT_STATE_UNKNOWN:
4240         case G_SUPPLICANT_STATE_DISABLED:
4241         case G_SUPPLICANT_STATE_DISCONNECTED:
4242         case G_SUPPLICANT_STATE_INACTIVE:
4243         case G_SUPPLICANT_STATE_SCANNING:
4244         case G_SUPPLICANT_STATE_COMPLETED:
4245                 break;
4246         }
4247
4248         return 0;
4249 }
4250
4251 int g_supplicant_interface_scan(GSupplicantInterface *interface,
4252                                 GSupplicantScanParams *scan_data,
4253                                 GSupplicantInterfaceCallback callback,
4254                                                         void *user_data)
4255 {
4256         struct interface_scan_data *data;
4257         int ret;
4258
4259         ret = interface_ready_to_scan(interface);
4260         if (ret)
4261                 return ret;
4262
4263         data = dbus_malloc0(sizeof(*data));
4264         if (!data)
4265                 return -ENOMEM;
4266
4267         data->interface = interface;
4268         data->path = g_strdup(interface->path);
4269 #if defined TIZEN_EXT
4270         data->interface->scan_callback = data->callback = callback;
4271         data->interface->scan_data = data->user_data = user_data;
4272 #else
4273         data->callback = callback;
4274         data->user_data = user_data;
4275 #endif
4276         data->scan_params = scan_data;
4277
4278         interface->scan_callback = callback;
4279         interface->scan_data = user_data;
4280
4281         ret = supplicant_dbus_method_call(interface->path,
4282                         SUPPLICANT_INTERFACE ".Interface", "Scan",
4283                         interface_scan_params, interface_scan_result, data,
4284                         interface);
4285
4286         if (ret < 0) {
4287                 g_free(data->path);
4288                 dbus_free(data);
4289         }
4290
4291         return ret;
4292 }
4293
4294 static int parse_supplicant_error(DBusMessageIter *iter)
4295 {
4296         int err = -ECANCELED;
4297         char *key;
4298
4299         if (!iter)
4300                 return err;
4301
4302         /* If the given passphrase is malformed wpa_s returns
4303          * "invalid message format" but this error should be interpreted as
4304          * invalid-key.
4305          */
4306         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
4307                 dbus_message_iter_get_basic(iter, &key);
4308                 if (strncmp(key, "psk", 3) == 0 ||
4309                                 strncmp(key, "wep_key", 7) == 0 ||
4310                                 strcmp(key, "invalid message format") == 0) {
4311                         err = -ENOKEY;
4312                         break;
4313                 }
4314                 dbus_message_iter_next(iter);
4315         }
4316
4317         return err;
4318 }
4319
4320 static void interface_select_network_result(const char *error,
4321                                 DBusMessageIter *iter, void *user_data)
4322 {
4323         struct interface_connect_data *data = user_data;
4324         int err;
4325
4326         SUPPLICANT_DBG("");
4327
4328         err = 0;
4329         if (error) {
4330                 SUPPLICANT_DBG("SelectNetwork error %s", error);
4331                 err = parse_supplicant_error(iter);
4332         }
4333
4334         g_free(data->path);
4335
4336         if (data->callback)
4337                 data->callback(err, data->interface, data->user_data);
4338
4339         g_free(data->ssid);
4340         dbus_free(data);
4341 }
4342
4343 static void interface_select_network_params(DBusMessageIter *iter,
4344                                                         void *user_data)
4345 {
4346         struct interface_connect_data *data = user_data;
4347         GSupplicantInterface *interface = data->interface;
4348
4349         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
4350                                         &interface->network_path);
4351 }
4352
4353 static void interface_add_network_result(const char *error,
4354                                 DBusMessageIter *iter, void *user_data)
4355 {
4356         struct interface_connect_data *data = user_data;
4357         GSupplicantInterface *interface = data->interface;
4358         const char *path;
4359         int err;
4360
4361         if (error)
4362                 goto error;
4363
4364         dbus_message_iter_get_basic(iter, &path);
4365         if (!path)
4366                 goto error;
4367
4368         SUPPLICANT_DBG("PATH: %s", path);
4369
4370         g_free(interface->network_path);
4371         interface->network_path = g_strdup(path);
4372
4373         supplicant_dbus_method_call(data->interface->path,
4374                         SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
4375                         interface_select_network_params,
4376                         interface_select_network_result, data,
4377                         interface);
4378
4379         return;
4380
4381 error:
4382         SUPPLICANT_DBG("AddNetwork error %s", error);
4383
4384         if (interface_exists(data->interface, data->interface->path)) {
4385                 err = parse_supplicant_error(iter);
4386                 if (data->callback)
4387                         data->callback(err, data->interface, data->user_data);
4388
4389                 g_free(interface->network_path);
4390                 interface->network_path = NULL;
4391         }
4392
4393         g_free(data->path);
4394         g_free(data->ssid);
4395         g_free(data);
4396 }
4397
4398 static void add_network_security_none(DBusMessageIter *dict)
4399 {
4400         const char *auth_alg = "OPEN";
4401
4402         supplicant_dbus_dict_append_basic(dict, "auth_alg",
4403                                         DBUS_TYPE_STRING, &auth_alg);
4404 }
4405
4406 static void add_network_security_wep(DBusMessageIter *dict,
4407                                         GSupplicantSSID *ssid)
4408 {
4409         const char *auth_alg = "OPEN SHARED";
4410         dbus_uint32_t key_index = 0;
4411
4412         supplicant_dbus_dict_append_basic(dict, "auth_alg",
4413                                         DBUS_TYPE_STRING, &auth_alg);
4414
4415         if (ssid->passphrase) {
4416                 int size = strlen(ssid->passphrase);
4417                 if (size == 10 || size == 26) {
4418                         unsigned char *key = g_try_malloc(13);
4419                         char tmp[3];
4420                         int i;
4421
4422                         memset(tmp, 0, sizeof(tmp));
4423                         if (!key)
4424                                 size = 0;
4425
4426                         for (i = 0; i < size / 2; i++) {
4427                                 memcpy(tmp, ssid->passphrase + (i * 2), 2);
4428                                 key[i] = (unsigned char) strtol(tmp, NULL, 16);
4429                         }
4430
4431                         supplicant_dbus_dict_append_fixed_array(dict,
4432                                                         "wep_key0",
4433                                                         DBUS_TYPE_BYTE,
4434                                                         &key, size / 2);
4435                         g_free(key);
4436                 } else if (size == 5 || size == 13) {
4437                         unsigned char *key = g_try_malloc(13);
4438                         int i;
4439
4440                         if (!key)
4441                                 size = 0;
4442
4443                         for (i = 0; i < size; i++)
4444                                 key[i] = (unsigned char) ssid->passphrase[i];
4445
4446                         supplicant_dbus_dict_append_fixed_array(dict,
4447                                                                 "wep_key0",
4448                                                                 DBUS_TYPE_BYTE,
4449                                                                 &key, size);
4450                         g_free(key);
4451                 } else
4452                         supplicant_dbus_dict_append_basic(dict,
4453                                                         "wep_key0",
4454                                                         DBUS_TYPE_STRING,
4455                                                         &ssid->passphrase);
4456
4457                 supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx",
4458                                         DBUS_TYPE_UINT32, &key_index);
4459         }
4460 }
4461
4462 static dbus_bool_t is_psk_raw_key(const char *psk)
4463 {
4464         int i;
4465
4466         /* A raw key is always 64 bytes length... */
4467         if (strlen(psk) != 64)
4468                 return FALSE;
4469
4470         /* ... and its content is in hex representation */
4471         for (i = 0; i < 64; i++)
4472                 if (!isxdigit((unsigned char) psk[i]))
4473                         return FALSE;
4474
4475         return TRUE;
4476 }
4477
4478 static unsigned char hexchar2bin(char c)
4479 {
4480         if ((c >= '0') && (c <= '9'))
4481                 return c - '0';
4482         else if ((c >= 'A') && (c <= 'F'))
4483                 return c - 'A' + 10;
4484         else if ((c >= 'a') && (c <= 'f'))
4485                 return c - 'a' + 10;
4486         else
4487                 return c;
4488 }
4489
4490 static void hexstring2bin(const char *string, unsigned char *data,
4491                                 size_t data_len)
4492 {
4493         size_t i;
4494
4495         for (i = 0; i < data_len; i++)
4496                 data[i] = (hexchar2bin(string[i * 2 + 0]) << 4 |
4497                            hexchar2bin(string[i * 2 + 1]) << 0);
4498 }
4499
4500 static void add_network_security_psk(DBusMessageIter *dict,
4501                                         GSupplicantSSID *ssid)
4502 {
4503         if (ssid->passphrase && strlen(ssid->passphrase) > 0) {
4504                 const char *key = "psk";
4505
4506                 if (is_psk_raw_key(ssid->passphrase)) {
4507                         unsigned char data[32];
4508                         unsigned char *datap = data;
4509
4510                         /* The above pointer alias is required by D-Bus because
4511                          * with D-Bus and GCC, non-heap-allocated arrays cannot
4512                          * be passed directly by their base pointer. */
4513
4514                         hexstring2bin(ssid->passphrase, datap, sizeof(data));
4515
4516                         supplicant_dbus_dict_append_fixed_array(dict,
4517                                                         key, DBUS_TYPE_BYTE,
4518                                                         &datap, sizeof(data));
4519                 } else
4520                         supplicant_dbus_dict_append_basic(dict,
4521                                                         key, DBUS_TYPE_STRING,
4522                                                         &ssid->passphrase);
4523         }
4524 }
4525
4526 static void add_network_security_tls(DBusMessageIter *dict,
4527                                         GSupplicantSSID *ssid)
4528 {
4529         /*
4530          * For TLS, we at least need:
4531          *              The client certificate
4532          *              The client private key file
4533          *              The client private key file password
4534          *
4535          * The Authority certificate is optional.
4536          */
4537         if (!ssid->client_cert_path)
4538                 return;
4539
4540         if (!ssid->private_key_path)
4541                 return;
4542
4543 #if !defined TIZEN_EXT
4544         if (!ssid->private_key_passphrase)
4545                 return;
4546 #endif
4547
4548         if (ssid->ca_cert_path)
4549                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
4550                                         DBUS_TYPE_STRING, &ssid->ca_cert_path);
4551
4552         supplicant_dbus_dict_append_basic(dict, "private_key",
4553                                                 DBUS_TYPE_STRING,
4554                                                 &ssid->private_key_path);
4555 #if !defined TIZEN_EXT
4556         supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
4557                                                 DBUS_TYPE_STRING,
4558                                                 &ssid->private_key_passphrase);
4559 #endif
4560         supplicant_dbus_dict_append_basic(dict, "client_cert",
4561                                                 DBUS_TYPE_STRING,
4562                                                 &ssid->client_cert_path);
4563 }
4564
4565 static void add_network_security_peap(DBusMessageIter *dict,
4566                                         GSupplicantSSID *ssid)
4567 {
4568         char *phase2_auth;
4569
4570         /*
4571          * For PEAP/TTLS, we at least need
4572          *              The authority certificate
4573          *              The 2nd phase authentication method
4574          *              The 2nd phase passphrase
4575          *
4576          * The Client certificate is optional although strongly recommended
4577          * When setting it, we need in addition
4578          *              The Client private key file
4579          *              The Client private key file password
4580          */
4581         if (!ssid->passphrase)
4582                 return;
4583
4584         if (!ssid->phase2_auth)
4585                 return;
4586
4587         if (ssid->client_cert_path) {
4588                 if (!ssid->private_key_path)
4589                         return;
4590
4591 #if !defined TIZEN_EXT
4592                 if (!ssid->private_key_passphrase)
4593                         return;
4594 #endif
4595
4596                 supplicant_dbus_dict_append_basic(dict, "client_cert",
4597                                                 DBUS_TYPE_STRING,
4598                                                 &ssid->client_cert_path);
4599
4600                 supplicant_dbus_dict_append_basic(dict, "private_key",
4601                                                 DBUS_TYPE_STRING,
4602                                                 &ssid->private_key_path);
4603
4604 #if !defined TIZEN_EXT
4605                 supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
4606                                                 DBUS_TYPE_STRING,
4607                                                 &ssid->private_key_passphrase);
4608 #endif
4609
4610         }
4611
4612         if (g_str_has_prefix(ssid->phase2_auth, "EAP-")) {
4613                 phase2_auth = g_strdup_printf("autheap=%s",
4614                                         ssid->phase2_auth + strlen("EAP-"));
4615         } else
4616                 phase2_auth = g_strdup_printf("auth=%s", ssid->phase2_auth);
4617
4618         supplicant_dbus_dict_append_basic(dict, "password",
4619                                                 DBUS_TYPE_STRING,
4620                                                 &ssid->passphrase);
4621
4622         if (ssid->ca_cert_path)
4623                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
4624                                                 DBUS_TYPE_STRING,
4625                                                 &ssid->ca_cert_path);
4626
4627         supplicant_dbus_dict_append_basic(dict, "phase2",
4628                                                 DBUS_TYPE_STRING,
4629                                                 &phase2_auth);
4630
4631         g_free(phase2_auth);
4632 }
4633
4634 static void add_network_security_eap(DBusMessageIter *dict,
4635                                         GSupplicantSSID *ssid)
4636 {
4637         char *eap_value;
4638
4639 #if defined TIZEN_EXT
4640         if (!ssid->eap)
4641 #else
4642         if (!ssid->eap || !ssid->identity)
4643 #endif
4644                 return;
4645
4646         if (g_strcmp0(ssid->eap, "tls") == 0) {
4647                 add_network_security_tls(dict, ssid);
4648         } else if (g_strcmp0(ssid->eap, "peap") == 0 ||
4649                                 g_strcmp0(ssid->eap, "ttls") == 0) {
4650 #if defined TIZEN_EXT
4651                 if (!ssid->identity)
4652                         return;
4653 #endif
4654                 add_network_security_peap(dict, ssid);
4655
4656 #if defined TIZEN_EXT
4657         } else if (g_strcmp0(ssid->eap, "sim") == 0 ||
4658                         g_strcmp0(ssid->eap, "aka") == 0) {
4659 #endif
4660         } else
4661                 return;
4662
4663         eap_value = g_ascii_strup(ssid->eap, -1);
4664
4665         supplicant_dbus_dict_append_basic(dict, "eap",
4666                                                 DBUS_TYPE_STRING,
4667                                                 &eap_value);
4668 #if defined TIZEN_EXT
4669         if (ssid->identity != NULL)
4670                 supplicant_dbus_dict_append_basic(dict, "identity",
4671                                                         DBUS_TYPE_STRING,
4672                                                         &ssid->identity);
4673 #else
4674         supplicant_dbus_dict_append_basic(dict, "identity",
4675                                                 DBUS_TYPE_STRING,
4676                                                 &ssid->identity);
4677 #endif
4678
4679         g_free(eap_value);
4680 }
4681
4682 static void add_network_security_ciphers(DBusMessageIter *dict,
4683                                                 GSupplicantSSID *ssid)
4684 {
4685         unsigned int p_cipher, g_cipher, i;
4686         char *pairwise, *group;
4687         char *pair_ciphers[4];
4688         char *group_ciphers[5];
4689
4690         p_cipher = ssid->pairwise_cipher;
4691         g_cipher = ssid->group_cipher;
4692
4693         if (p_cipher == 0 && g_cipher == 0)
4694                 return;
4695
4696         i = 0;
4697
4698         if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP)
4699                 pair_ciphers[i++] = "CCMP";
4700
4701         if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP)
4702                 pair_ciphers[i++] = "TKIP";
4703
4704         if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE)
4705                 pair_ciphers[i++] = "NONE";
4706
4707         pair_ciphers[i] = NULL;
4708
4709         i = 0;
4710
4711         if (g_cipher & G_SUPPLICANT_GROUP_CCMP)
4712                 group_ciphers[i++] = "CCMP";
4713
4714         if (g_cipher & G_SUPPLICANT_GROUP_TKIP)
4715                 group_ciphers[i++] = "TKIP";
4716
4717         if (g_cipher & G_SUPPLICANT_GROUP_WEP104)
4718                 group_ciphers[i++] = "WEP104";
4719
4720         if (g_cipher & G_SUPPLICANT_GROUP_WEP40)
4721                 group_ciphers[i++] = "WEP40";
4722
4723         group_ciphers[i] = NULL;
4724
4725         pairwise = g_strjoinv(" ", pair_ciphers);
4726         group = g_strjoinv(" ", group_ciphers);
4727
4728         SUPPLICANT_DBG("cipher %s %s", pairwise, group);
4729
4730         supplicant_dbus_dict_append_basic(dict, "pairwise",
4731                                                 DBUS_TYPE_STRING,
4732                                                 &pairwise);
4733         supplicant_dbus_dict_append_basic(dict, "group",
4734                                                 DBUS_TYPE_STRING,
4735                                                 &group);
4736
4737         g_free(pairwise);
4738         g_free(group);
4739 }
4740
4741 static void add_network_security_proto(DBusMessageIter *dict,
4742                                                 GSupplicantSSID *ssid)
4743 {
4744         unsigned int protocol, i;
4745         char *proto;
4746         char *protos[3];
4747
4748         protocol = ssid->protocol;
4749
4750         if (protocol == 0)
4751                 return;
4752
4753         i = 0;
4754
4755         if (protocol & G_SUPPLICANT_PROTO_RSN)
4756                 protos[i++] = "RSN";
4757
4758         if (protocol & G_SUPPLICANT_PROTO_WPA)
4759                 protos[i++] = "WPA";
4760
4761         protos[i] = NULL;
4762
4763         proto = g_strjoinv(" ", protos);
4764
4765         SUPPLICANT_DBG("proto %s", proto);
4766
4767         supplicant_dbus_dict_append_basic(dict, "proto",
4768                                                 DBUS_TYPE_STRING,
4769                                                 &proto);
4770
4771         g_free(proto);
4772 }
4773
4774 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
4775 {
4776         char *key_mgmt;
4777
4778         switch (ssid->security) {
4779         case G_SUPPLICANT_SECURITY_NONE:
4780                 key_mgmt = "NONE";
4781                 add_network_security_none(dict);
4782                 add_network_security_ciphers(dict, ssid);
4783                 break;
4784         case G_SUPPLICANT_SECURITY_UNKNOWN:
4785         case G_SUPPLICANT_SECURITY_WEP:
4786                 key_mgmt = "NONE";
4787                 add_network_security_wep(dict, ssid);
4788                 add_network_security_ciphers(dict, ssid);
4789                 break;
4790         case G_SUPPLICANT_SECURITY_PSK:
4791                 key_mgmt = "WPA-PSK";
4792                 add_network_security_psk(dict, ssid);
4793                 add_network_security_ciphers(dict, ssid);
4794                 add_network_security_proto(dict, ssid);
4795                 break;
4796         case G_SUPPLICANT_SECURITY_IEEE8021X:
4797                 key_mgmt = "WPA-EAP";
4798                 add_network_security_eap(dict, ssid);
4799                 add_network_security_ciphers(dict, ssid);
4800                 add_network_security_proto(dict, ssid);
4801                 break;
4802 #if defined TIZEN_EXT
4803         case G_SUPPLICANT_SECURITY_FT_PSK:
4804                 key_mgmt = "FT-PSK";
4805                 add_network_security_psk(dict, ssid);
4806                 add_network_security_ciphers(dict, ssid);
4807                 add_network_security_proto(dict, ssid);
4808                 break;
4809         case G_SUPPLICANT_SECURITY_FT_IEEE8021X:
4810                 key_mgmt = "FT-EAP";
4811                 add_network_security_eap(dict, ssid);
4812                 add_network_security_ciphers(dict, ssid);
4813                 add_network_security_proto(dict, ssid);
4814                 break;
4815 #endif
4816         }
4817
4818         supplicant_dbus_dict_append_basic(dict, "key_mgmt",
4819                                 DBUS_TYPE_STRING, &key_mgmt);
4820 }
4821
4822 static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid)
4823 {
4824         dbus_uint32_t mode;
4825
4826         switch (ssid->mode) {
4827         case G_SUPPLICANT_MODE_UNKNOWN:
4828         case G_SUPPLICANT_MODE_INFRA:
4829                 mode = 0;
4830                 break;
4831         case G_SUPPLICANT_MODE_IBSS:
4832                 mode = 1;
4833                 break;
4834         case G_SUPPLICANT_MODE_MASTER:
4835                 mode = 2;
4836                 break;
4837         }
4838
4839         supplicant_dbus_dict_append_basic(dict, "mode",
4840                                 DBUS_TYPE_UINT32, &mode);
4841 }
4842
4843 static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
4844 {
4845         DBusMessageIter dict;
4846         struct interface_connect_data *data = user_data;
4847         GSupplicantSSID *ssid = data->ssid;
4848
4849         supplicant_dbus_dict_open(iter, &dict);
4850
4851         if (ssid->scan_ssid)
4852                 supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
4853                                          DBUS_TYPE_UINT32, &ssid->scan_ssid);
4854
4855         if (ssid->freq)
4856                 supplicant_dbus_dict_append_basic(&dict, "frequency",
4857                                          DBUS_TYPE_UINT32, &ssid->freq);
4858
4859         if (ssid->bgscan)
4860                 supplicant_dbus_dict_append_basic(&dict, "bgscan",
4861                                         DBUS_TYPE_STRING, &ssid->bgscan);
4862
4863         add_network_mode(&dict, ssid);
4864
4865         add_network_security(&dict, ssid);
4866
4867         supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
4868                                         DBUS_TYPE_BYTE, &ssid->ssid,
4869                                                 ssid->ssid_len);
4870
4871         supplicant_dbus_dict_append_basic(&dict, "ignore_broadcast_ssid",
4872                                         DBUS_TYPE_INT32,
4873                                         &ssid->ignore_broadcast_ssid);
4874
4875         supplicant_dbus_dict_close(iter, &dict);
4876 }
4877
4878 static void interface_wps_start_result(const char *error,
4879                                 DBusMessageIter *iter, void *user_data)
4880 {
4881         struct interface_connect_data *data = user_data;
4882         int err;
4883
4884         SUPPLICANT_DBG("");
4885
4886         err = 0;
4887         if (error) {
4888                 SUPPLICANT_DBG("error: %s", error);
4889                 err = parse_supplicant_error(iter);
4890         }
4891
4892         if(data->callback)
4893                 data->callback(err, data->interface, data->user_data);
4894
4895         g_free(data->path);
4896         g_free(data->ssid);
4897         dbus_free(data);
4898 }
4899
4900 static void interface_add_wps_params(DBusMessageIter *iter, void *user_data)
4901 {
4902         struct interface_connect_data *data = user_data;
4903         GSupplicantSSID *ssid = data->ssid;
4904         const char *role = "enrollee", *type;
4905         DBusMessageIter dict;
4906
4907         SUPPLICANT_DBG("");
4908
4909         supplicant_dbus_dict_open(iter, &dict);
4910
4911         supplicant_dbus_dict_append_basic(&dict, "Role",
4912                                                 DBUS_TYPE_STRING, &role);
4913
4914         type = "pbc";
4915         if (ssid->pin_wps) {
4916                 type = "pin";
4917                 supplicant_dbus_dict_append_basic(&dict, "Pin",
4918                                         DBUS_TYPE_STRING, &ssid->pin_wps);
4919         }
4920
4921         supplicant_dbus_dict_append_basic(&dict, "Type",
4922                                         DBUS_TYPE_STRING, &type);
4923
4924 #if defined TIZEN_EXT
4925         if (ssid->bssid)
4926                 supplicant_dbus_dict_append_fixed_array(&dict, "Bssid",
4927                                                 DBUS_TYPE_BYTE, &ssid->bssid, 6);
4928 #endif
4929
4930         supplicant_dbus_dict_close(iter, &dict);
4931 }
4932
4933 static void wps_start(const char *error, DBusMessageIter *iter, void *user_data)
4934 {
4935         struct interface_connect_data *data = user_data;
4936
4937         SUPPLICANT_DBG("");
4938
4939         if (error) {
4940                 SUPPLICANT_DBG("error: %s", error);
4941                 g_free(data->path);
4942                 g_free(data->ssid);
4943                 dbus_free(data);
4944                 return;
4945         }
4946 #if defined TIZEN_EXT
4947         GSupplicantSSID *ssid = data->ssid;
4948         if (ssid->pin_wps != NULL) {
4949                 if (!g_utf8_validate(ssid->pin_wps, 8, NULL)) {
4950                         SUPPLICANT_DBG("Invalid characters in WPS_PIN");
4951                         g_free(data->ssid);
4952                         dbus_free(data);
4953                         return;
4954                 }
4955         }
4956 #endif
4957         supplicant_dbus_method_call(data->interface->path,
4958                         SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
4959                         interface_add_wps_params,
4960                         interface_wps_start_result, data, NULL);
4961 }
4962
4963 static void wps_process_credentials(DBusMessageIter *iter, void *user_data)
4964 {
4965         dbus_bool_t credentials = TRUE;
4966
4967         SUPPLICANT_DBG("");
4968
4969         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials);
4970 }
4971
4972
4973 int g_supplicant_interface_connect(GSupplicantInterface *interface,
4974                                 GSupplicantSSID *ssid,
4975                                 GSupplicantInterfaceCallback callback,
4976                                                         void *user_data)
4977 {
4978         struct interface_connect_data *data;
4979         int ret;
4980
4981         if (!interface)
4982                 return -EINVAL;
4983
4984         if (!system_available)
4985                 return -EFAULT;
4986
4987         /* TODO: Check if we're already connected and switch */
4988
4989         data = dbus_malloc0(sizeof(*data));
4990         if (!data)
4991                 return -ENOMEM;
4992
4993         data->interface = interface;
4994         data->path = g_strdup(interface->path);
4995         data->callback = callback;
4996         data->ssid = ssid;
4997         data->user_data = user_data;
4998
4999         if (ssid->use_wps) {
5000                 g_free(interface->wps_cred.key);
5001                 memset(&interface->wps_cred, 0,
5002                                 sizeof(struct _GSupplicantWpsCredentials));
5003
5004                 ret = supplicant_dbus_property_set(interface->path,
5005                         SUPPLICANT_INTERFACE ".Interface.WPS",
5006                         "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
5007                         wps_process_credentials, wps_start, data, interface);
5008         } else
5009                 ret = supplicant_dbus_method_call(interface->path,
5010                         SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
5011                         interface_add_network_params,
5012                         interface_add_network_result, data,
5013                         interface);
5014
5015         if (ret < 0) {
5016                 g_free(data->path);
5017                 dbus_free(data);
5018                 return ret;
5019         }
5020
5021         return -EINPROGRESS;
5022 }
5023
5024 static void network_remove_result(const char *error,
5025                                 DBusMessageIter *iter, void *user_data)
5026 {
5027         struct interface_data *data = user_data;
5028         int result = 0;
5029
5030         SUPPLICANT_DBG("");
5031
5032         if (error) {
5033                 result = -EIO;
5034                 if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
5035                                                 error) == 0)
5036                         result = -ECONNABORTED;
5037         }
5038
5039         g_free(data->path);
5040
5041         if (data->callback)
5042                 data->callback(result, data->interface, data->user_data);
5043
5044         dbus_free(data);
5045 }
5046
5047 static void network_remove_params(DBusMessageIter *iter, void *user_data)
5048 {
5049         struct interface_data *data = user_data;
5050         const char *path = data->interface->network_path;
5051
5052         SUPPLICANT_DBG("path %s", path);
5053
5054         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
5055 }
5056
5057 static int network_remove(struct interface_data *data)
5058 {
5059         GSupplicantInterface *interface = data->interface;
5060
5061         SUPPLICANT_DBG("");
5062
5063 #if defined TIZEN_EXT
5064         GSupplicantInterface *intf = NULL;
5065         /*
5066          * Check if 'interface' is valid
5067          */
5068         intf = g_hash_table_lookup(interface_table, interface->path);
5069         if (intf == NULL)
5070                 return -EINVAL;
5071 #endif
5072
5073         return supplicant_dbus_method_call(interface->path,
5074                         SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
5075                         network_remove_params, network_remove_result, data,
5076                         interface);
5077 }
5078
5079 static void interface_disconnect_result(const char *error,
5080                                 DBusMessageIter *iter, void *user_data)
5081 {
5082         struct interface_data *data = user_data;
5083         int result = 0;
5084
5085         SUPPLICANT_DBG("");
5086
5087         if (error) {
5088                 result = -EIO;
5089                 if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
5090                                                 error) == 0)
5091                         result = -ECONNABORTED;
5092         }
5093
5094         if (result < 0 && data->callback) {
5095                 data->callback(result, data->interface, data->user_data);
5096                 data->callback = NULL;
5097         }
5098
5099         /* If we are disconnecting from previous WPS successful
5100          * association. i.e.: it did not went through AddNetwork,
5101          * and interface->network_path was never set. */
5102         if (!data->interface->network_path) {
5103                 g_free(data->path);
5104                 dbus_free(data);
5105                 return;
5106         }
5107
5108         if (result != -ECONNABORTED) {
5109                 if (network_remove(data) < 0) {
5110                         g_free(data->path);
5111                         dbus_free(data);
5112                 }
5113         } else {
5114                 g_free(data->path);
5115                 dbus_free(data);
5116         }
5117 }
5118
5119 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
5120                                         GSupplicantInterfaceCallback callback,
5121                                                         void *user_data)
5122 {
5123         struct interface_data *data;
5124         int ret;
5125
5126         SUPPLICANT_DBG("");
5127
5128         if (!interface)
5129                 return -EINVAL;
5130
5131         if (!system_available)
5132                 return -EFAULT;
5133
5134         data = dbus_malloc0(sizeof(*data));
5135         if (!data)
5136                 return -ENOMEM;
5137
5138         data->interface = interface;
5139         data->path = g_strdup(interface->path);
5140         data->callback = callback;
5141         data->user_data = user_data;
5142
5143         ret = supplicant_dbus_method_call(interface->path,
5144                         SUPPLICANT_INTERFACE ".Interface", "Disconnect",
5145                         NULL, interface_disconnect_result, data,
5146                         interface);
5147
5148         if (ret < 0) {
5149                 g_free(data->path);
5150                 dbus_free(data);
5151         }
5152
5153         return ret;
5154 }
5155
5156 static void interface_p2p_find_result(const char *error,
5157                                         DBusMessageIter *iter, void *user_data)
5158 {
5159         struct interface_scan_data *data = user_data;
5160         int err = 0;
5161
5162         SUPPLICANT_DBG("error %s", error);
5163
5164         if (error)
5165                 err = -EIO;
5166
5167         if (interface_exists(data->interface, data->path)) {
5168                 if (!data->interface->ready)
5169                         err = -ENOLINK;
5170                 if (!err)
5171                         data->interface->p2p_finding = true;
5172         }
5173
5174         if (data->callback)
5175                 data->callback(err, data->interface, data->user_data);
5176
5177         g_free(data->path);
5178         dbus_free(data);
5179 }
5180
5181 static void interface_p2p_find_params(DBusMessageIter *iter, void *user_data)
5182 {
5183         DBusMessageIter dict;
5184
5185         supplicant_dbus_dict_open(iter, &dict);
5186         supplicant_dbus_dict_close(iter, &dict);
5187 }
5188
5189 int g_supplicant_interface_p2p_find(GSupplicantInterface *interface,
5190                                         GSupplicantInterfaceCallback callback,
5191                                                         void *user_data)
5192 {
5193         struct interface_scan_data *data;
5194         int ret;
5195
5196         if (!interface->p2p_support)
5197                 return -ENOTSUP;
5198
5199         ret = interface_ready_to_scan(interface);
5200         if (ret && ret != -EALREADY)
5201                 return ret;
5202
5203         data = dbus_malloc0(sizeof(*data));
5204         if (!data)
5205                 return -ENOMEM;
5206
5207         data->interface = interface;
5208         data->path = g_strdup(interface->path);
5209         data->callback = callback;
5210         data->user_data = user_data;
5211
5212         ret = supplicant_dbus_method_call(interface->path,
5213                         SUPPLICANT_INTERFACE ".Interface.P2PDevice", "Find",
5214                         interface_p2p_find_params, interface_p2p_find_result,
5215                         data, interface);
5216         if (ret < 0) {
5217                 g_free(data->path);
5218                 dbus_free(data);
5219         }
5220
5221         return ret;
5222 }
5223
5224 bool g_supplicant_interface_is_p2p_finding(GSupplicantInterface *interface)
5225 {
5226         if (!interface)
5227                 return false;
5228
5229         return interface->p2p_finding;
5230 }
5231
5232 int g_supplicant_interface_p2p_stop_find(GSupplicantInterface *interface)
5233 {
5234         if (!interface->p2p_finding)
5235                 return 0;
5236
5237         SUPPLICANT_DBG("");
5238
5239         interface->p2p_finding = false;
5240
5241         return supplicant_dbus_method_call(interface->path,
5242                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "StopFind",
5243                 NULL, NULL, NULL, NULL);
5244 }
5245
5246 static void interface_p2p_connect_result(const char *error,
5247                                         DBusMessageIter *iter, void *user_data)
5248 {
5249         struct interface_connect_data *data = user_data;
5250         int err = 0;
5251
5252         SUPPLICANT_DBG("");
5253
5254         if (error)
5255                 err = parse_supplicant_error(iter);
5256
5257         if (data->callback)
5258                 data->callback(err, data->interface, data->user_data);
5259
5260         g_free(data->path);
5261         g_free(data->peer->wps_pin);
5262         g_free(data->peer->path);
5263         g_free(data->peer);
5264         g_free(data);
5265 }
5266
5267 static void interface_p2p_connect_params(DBusMessageIter *iter, void *user_data)
5268 {
5269         struct interface_connect_data *data = user_data;
5270         const char *wps = "pbc";
5271         DBusMessageIter dict;
5272         int go_intent = 7;
5273
5274         SUPPLICANT_DBG("");
5275
5276         supplicant_dbus_dict_open(iter, &dict);
5277
5278         if (data->peer->master)
5279                 go_intent = 15;
5280
5281         if (data->peer->wps_pin)
5282                 wps = "pin";
5283
5284         supplicant_dbus_dict_append_basic(&dict, "peer",
5285                                 DBUS_TYPE_OBJECT_PATH, &data->peer->path);
5286         supplicant_dbus_dict_append_basic(&dict, "wps_method",
5287                                 DBUS_TYPE_STRING, &wps);
5288         if (data->peer->wps_pin) {
5289                 supplicant_dbus_dict_append_basic(&dict, "pin",
5290                                 DBUS_TYPE_STRING, &data->peer->wps_pin);
5291         }
5292
5293         supplicant_dbus_dict_append_basic(&dict, "go_intent",
5294                                         DBUS_TYPE_INT32, &go_intent);
5295
5296         supplicant_dbus_dict_close(iter, &dict);
5297 }
5298
5299 int g_supplicant_interface_p2p_connect(GSupplicantInterface *interface,
5300                                         GSupplicantPeerParams *peer_params,
5301                                         GSupplicantInterfaceCallback callback,
5302                                         void *user_data)
5303 {
5304         struct interface_connect_data *data;
5305         int ret;
5306
5307         SUPPLICANT_DBG("");
5308
5309         if (!interface->p2p_support)
5310                 return -ENOTSUP;
5311
5312         data = dbus_malloc0(sizeof(*data));
5313         data->interface = interface;
5314         data->path = g_strdup(interface->path);
5315         data->peer = peer_params;
5316         data->callback = callback;
5317         data->user_data = user_data;
5318
5319         ret = supplicant_dbus_method_call(interface->path,
5320                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "Connect",
5321                 interface_p2p_connect_params, interface_p2p_connect_result,
5322                 data, interface);
5323         if (ret < 0) {
5324                 g_free(data->path);
5325                 dbus_free(data);
5326                 return ret;
5327         }
5328
5329         return -EINPROGRESS;
5330 }
5331
5332 int g_supplicant_interface_p2p_disconnect(GSupplicantInterface *interface,
5333                                         GSupplicantPeerParams *peer_params)
5334 {
5335         GSupplicantPeer *peer;
5336         int count = 0;
5337         GSList *list;
5338
5339         SUPPLICANT_DBG("");
5340
5341         if (!interface->p2p_support)
5342                 return -ENOTSUP;
5343
5344         peer = g_hash_table_lookup(interface->peer_table, peer_params->path);
5345         if (!peer)
5346                 return -ENODEV;
5347
5348         for (list = peer->groups; list; list = list->next, count++) {
5349                 const char *group_obj_path = list->data;
5350                 GSupplicantInterface *g_interface;
5351                 GSupplicantGroup *group;
5352
5353                 group = g_hash_table_lookup(group_mapping, group_obj_path);
5354                 if (!group || !group->interface)
5355                         continue;
5356
5357                 g_interface = group->interface;
5358                 supplicant_dbus_method_call(g_interface->path,
5359                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
5360                                 "Disconnect", NULL, NULL, NULL, g_interface);
5361         }
5362
5363         if (count == 0 && peer->current_group_iface) {
5364                 supplicant_dbus_method_call(peer->current_group_iface->path,
5365                                 SUPPLICANT_INTERFACE ".Interface.P2PDevice",
5366                                 "Disconnect", NULL, NULL, NULL,
5367                                 peer->current_group_iface->path);
5368         }
5369
5370         peer->current_group_iface = NULL;
5371
5372         return -EINPROGRESS;
5373 }
5374
5375 struct p2p_service_data {
5376         bool registration;
5377         GSupplicantInterface *interface;
5378         GSupplicantP2PServiceParams *service;
5379         GSupplicantInterfaceCallback callback;
5380         void *user_data;
5381 };
5382
5383 static void interface_p2p_service_result(const char *error,
5384                                         DBusMessageIter *iter, void *user_data)
5385 {
5386         struct p2p_service_data *data = user_data;
5387         int result = 0;
5388
5389         SUPPLICANT_DBG("%s result - %s", data->registration ?
5390                                 "Registration" : "Deletion",
5391                                 error ? error : "Success");
5392         if (error)
5393                 result = -EINVAL;
5394
5395         if (data->callback)
5396                 data->callback(result, data->interface, data->user_data);
5397
5398         g_free(data->service->query);
5399         g_free(data->service->response);
5400         g_free(data->service->service);
5401         g_free(data->service->wfd_ies);
5402         g_free(data->service);
5403         dbus_free(data);
5404 }
5405
5406 static void interface_p2p_service_params(DBusMessageIter *iter,
5407                                                         void *user_data)
5408 {
5409         struct p2p_service_data *data = user_data;
5410         GSupplicantP2PServiceParams *service;
5411         DBusMessageIter dict;
5412         const char *type;
5413
5414         SUPPLICANT_DBG("");
5415
5416         service = data->service;
5417
5418         supplicant_dbus_dict_open(iter, &dict);
5419
5420         if (service->query && service->response) {
5421                 type = "bonjour";
5422                 supplicant_dbus_dict_append_basic(&dict, "service_type",
5423                                                 DBUS_TYPE_STRING, &type);
5424                 supplicant_dbus_dict_append_fixed_array(&dict, "query",
5425                                         DBUS_TYPE_BYTE, &service->query,
5426                                         service->query_length);
5427                 supplicant_dbus_dict_append_fixed_array(&dict, "response",
5428                                         DBUS_TYPE_BYTE, &service->response,
5429                                         service->response_length);
5430         } else if (service->version && service->service) {
5431                 type = "upnp";
5432                 supplicant_dbus_dict_append_basic(&dict, "service_type",
5433                                                 DBUS_TYPE_STRING, &type);
5434                 supplicant_dbus_dict_append_basic(&dict, "version",
5435                                         DBUS_TYPE_INT32, &service->version);
5436                 supplicant_dbus_dict_append_basic(&dict, "service",
5437                                         DBUS_TYPE_STRING, &service->service);
5438         }
5439
5440         supplicant_dbus_dict_close(iter, &dict);
5441 }
5442
5443 int g_supplicant_interface_p2p_add_service(GSupplicantInterface *interface,
5444                                 GSupplicantInterfaceCallback callback,
5445                                 GSupplicantP2PServiceParams *p2p_service_params,
5446                                 void *user_data)
5447 {
5448         struct p2p_service_data *data;
5449         int ret;
5450
5451         SUPPLICANT_DBG("");
5452
5453         if (!interface->p2p_support)
5454                 return -ENOTSUP;
5455
5456         data = dbus_malloc0(sizeof(*data));
5457         data->registration = true;
5458         data->interface = interface;
5459         data->service = p2p_service_params;
5460         data->callback = callback;
5461         data->user_data = user_data;
5462
5463         ret = supplicant_dbus_method_call(interface->path,
5464                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "AddService",
5465                 interface_p2p_service_params, interface_p2p_service_result,
5466                 data, interface);
5467         if (ret < 0) {
5468                 dbus_free(data);
5469                 return ret;
5470         }
5471
5472         return -EINPROGRESS;
5473 }
5474
5475 int g_supplicant_interface_p2p_del_service(GSupplicantInterface *interface,
5476                                 GSupplicantP2PServiceParams *p2p_service_params)
5477 {
5478         struct p2p_service_data *data;
5479         int ret;
5480
5481         SUPPLICANT_DBG("");
5482
5483         if (!interface->p2p_support)
5484                 return -ENOTSUP;
5485
5486         data = dbus_malloc0(sizeof(*data));
5487         data->interface = interface;
5488         data->service = p2p_service_params;
5489
5490         ret = supplicant_dbus_method_call(interface->path,
5491                 SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeleteService",
5492                 interface_p2p_service_params, interface_p2p_service_result,
5493                 data, interface);
5494         if (ret < 0) {
5495                 dbus_free(data);
5496                 return ret;
5497         }
5498
5499         return -EINPROGRESS;
5500 }
5501
5502 struct p2p_listen_data {
5503         int period;
5504         int interval;
5505 };
5506
5507 static void interface_p2p_listen_params(DBusMessageIter *iter, void *user_data)
5508 {
5509         struct p2p_listen_data *params = user_data;
5510         DBusMessageIter dict;
5511
5512         supplicant_dbus_dict_open(iter, &dict);
5513
5514         supplicant_dbus_dict_append_basic(&dict, "period",
5515                                         DBUS_TYPE_INT32, &params->period);
5516         supplicant_dbus_dict_append_basic(&dict, "interval",
5517                                         DBUS_TYPE_INT32, &params->interval);
5518         supplicant_dbus_dict_close(iter, &dict);
5519 }
5520
5521 int g_supplicant_interface_p2p_listen(GSupplicantInterface *interface,
5522                                                 int period, int interval)
5523 {
5524         struct p2p_listen_data params;
5525
5526         SUPPLICANT_DBG("");
5527
5528         if (!interface->p2p_support)
5529                 return -ENOTSUP;
5530
5531         params.period = period;
5532         params.interval = interval;
5533
5534         return supplicant_dbus_method_call(interface->path,
5535                         SUPPLICANT_INTERFACE ".Interface.P2PDevice",
5536                         "ExtendedListen", interface_p2p_listen_params,
5537                         NULL, &params, NULL);
5538 }
5539
5540 static void widi_ies_params(DBusMessageIter *iter, void *user_data)
5541 {
5542         struct p2p_service_data *data = user_data;
5543         GSupplicantP2PServiceParams *service = data->service;
5544         DBusMessageIter array;
5545
5546         SUPPLICANT_DBG("%p - %d", service->wfd_ies, service->wfd_ies_length);
5547
5548         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
5549                                         DBUS_TYPE_BYTE_AS_STRING, &array);
5550
5551         if (service->wfd_ies && service->wfd_ies_length > 0) {
5552                 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
5553                                 &service->wfd_ies, service->wfd_ies_length);
5554         }
5555
5556         dbus_message_iter_close_container(iter, &array);
5557 }
5558
5559 int g_supplicant_set_widi_ies(GSupplicantP2PServiceParams *p2p_service_params,
5560                                         GSupplicantInterfaceCallback callback,
5561                                         void *user_data)
5562 {
5563         struct p2p_service_data *data;
5564         int ret;
5565
5566         SUPPLICANT_DBG("");
5567
5568         if (!system_available)
5569                 return -EFAULT;
5570
5571         data = dbus_malloc0(sizeof(*data));
5572         data->service = p2p_service_params;
5573         data->callback = callback;
5574         data->user_data = user_data;
5575
5576         if (p2p_service_params->wfd_ies)
5577                 data->registration = true;
5578
5579         ret = supplicant_dbus_property_set(SUPPLICANT_PATH,
5580                                         SUPPLICANT_INTERFACE, "WFDIEs",
5581                                         DBUS_TYPE_ARRAY_AS_STRING
5582                                         DBUS_TYPE_BYTE_AS_STRING,
5583                                         widi_ies_params,
5584                                         interface_p2p_service_result,
5585                                         data, NULL);
5586         if (ret < 0 && ret != -EINPROGRESS) {
5587                 dbus_free(data);
5588                 return ret;
5589         }
5590
5591         return -EINPROGRESS;
5592 }
5593
5594
5595 static const char *g_supplicant_rule0 = "type=signal,"
5596                                         "path=" DBUS_PATH_DBUS ","
5597                                         "sender=" DBUS_SERVICE_DBUS ","
5598                                         "interface=" DBUS_INTERFACE_DBUS ","
5599                                         "member=NameOwnerChanged,"
5600                                         "arg0=" SUPPLICANT_SERVICE;
5601 static const char *g_supplicant_rule1 = "type=signal,"
5602                         "interface=" SUPPLICANT_INTERFACE;
5603 static const char *g_supplicant_rule2 = "type=signal,"
5604                         "interface=" SUPPLICANT_INTERFACE ".Interface";
5605 static const char *g_supplicant_rule3 = "type=signal,"
5606                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
5607 static const char *g_supplicant_rule4 = "type=signal,"
5608                         "interface=" SUPPLICANT_INTERFACE ".BSS";
5609 static const char *g_supplicant_rule5 = "type=signal,"
5610                         "interface=" SUPPLICANT_INTERFACE ".Network";
5611 #if !defined TIZEN_EXT
5612 static const char *g_supplicant_rule6 = "type=signal,"
5613                 "interface=" SUPPLICANT_INTERFACE ".Interface.P2PDevice";
5614 static const char *g_supplicant_rule7 = "type=signal,"
5615                 "interface=" SUPPLICANT_INTERFACE ".Peer";
5616 static const char *g_supplicant_rule8 = "type=signal,"
5617                 "interface=" SUPPLICANT_INTERFACE ".Group";
5618 #endif
5619
5620 static void invoke_introspect_method(void)
5621 {
5622         DBusMessage *message;
5623
5624         message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
5625                                         SUPPLICANT_PATH,
5626                                         DBUS_INTERFACE_INTROSPECTABLE,
5627                                         "Introspect");
5628
5629         if (!message)
5630                 return;
5631
5632         dbus_message_set_no_reply(message, TRUE);
5633         dbus_connection_send(connection, message, NULL);
5634         dbus_message_unref(message);
5635 }
5636
5637 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
5638 {
5639         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
5640         if (!connection)
5641                 return -EIO;
5642
5643         if (!dbus_connection_add_filter(connection, g_supplicant_filter,
5644                                                 NULL, NULL)) {
5645                 dbus_connection_unref(connection);
5646                 connection = NULL;
5647                 return -EIO;
5648         }
5649
5650         callbacks_pointer = callbacks;
5651         eap_methods = 0;
5652
5653         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
5654                                                 NULL, remove_interface);
5655
5656         bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
5657                                                                 NULL, NULL);
5658         peer_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
5659                                                                 NULL, NULL);
5660         group_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
5661                                                                 NULL, NULL);
5662         pending_peer_connection = g_hash_table_new_full(g_str_hash, g_str_equal,
5663                                                                 NULL, NULL);
5664
5665         supplicant_dbus_setup(connection);
5666
5667         dbus_bus_add_match(connection, g_supplicant_rule0, NULL);
5668         dbus_bus_add_match(connection, g_supplicant_rule1, NULL);
5669         dbus_bus_add_match(connection, g_supplicant_rule2, NULL);
5670         dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
5671         dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
5672         dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
5673 #if defined TIZEN_EXT
5674         dbus_bus_add_match(connection,
5675                         "type=signal,interface=org.tizen.system.deviced.PowerOff,"
5676                         "member=ChangeState", NULL);
5677 #endif
5678 #if !defined TIZEN_EXT
5679         dbus_bus_add_match(connection, g_supplicant_rule6, NULL);
5680         dbus_bus_add_match(connection, g_supplicant_rule7, NULL);
5681         dbus_bus_add_match(connection, g_supplicant_rule8, NULL);
5682 #endif
5683         dbus_connection_flush(connection);
5684
5685         if (dbus_bus_name_has_owner(connection,
5686                                         SUPPLICANT_SERVICE, NULL)) {
5687                 system_available = TRUE;
5688                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
5689                                                 SUPPLICANT_INTERFACE,
5690                                                 service_property, NULL, NULL);
5691         } else
5692                 invoke_introspect_method();
5693
5694         return 0;
5695 }
5696
5697 static void unregister_interface_remove_params(DBusMessageIter *iter,
5698                                                 void *user_data)
5699 {
5700         const char *path = user_data;
5701
5702         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
5703                                                         &path);
5704 }
5705
5706
5707 static void unregister_remove_interface(gpointer key, gpointer value,
5708                                                 gpointer user_data)
5709 {
5710         GSupplicantInterface *interface = value;
5711
5712         supplicant_dbus_method_call(SUPPLICANT_PATH,
5713                                         SUPPLICANT_INTERFACE,
5714                                         "RemoveInterface",
5715                                         unregister_interface_remove_params,
5716                                         NULL, interface->path, NULL);
5717 }
5718
5719 void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
5720 {
5721         SUPPLICANT_DBG("");
5722
5723         if (connection) {
5724 #if !defined TIZEN_EXT
5725                 dbus_bus_remove_match(connection, g_supplicant_rule8, NULL);
5726                 dbus_bus_remove_match(connection, g_supplicant_rule7, NULL);
5727                 dbus_bus_remove_match(connection, g_supplicant_rule6, NULL);
5728 #endif
5729                 dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
5730                 dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
5731                 dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);
5732                 dbus_bus_remove_match(connection, g_supplicant_rule2, NULL);
5733                 dbus_bus_remove_match(connection, g_supplicant_rule1, NULL);
5734                 dbus_bus_remove_match(connection, g_supplicant_rule0, NULL);
5735                 dbus_connection_flush(connection);
5736
5737                 dbus_connection_remove_filter(connection,
5738                                                 g_supplicant_filter, NULL);
5739         }
5740
5741         if (bss_mapping) {
5742                 g_hash_table_destroy(bss_mapping);
5743                 bss_mapping = NULL;
5744         }
5745
5746         if (peer_mapping) {
5747                 g_hash_table_destroy(peer_mapping);
5748                 peer_mapping = NULL;
5749         }
5750
5751         if (group_mapping) {
5752                 g_hash_table_destroy(group_mapping);
5753                 group_mapping = NULL;
5754         }
5755
5756         if (interface_table) {
5757                 g_hash_table_foreach(interface_table,
5758                                         unregister_remove_interface, NULL);
5759                 g_hash_table_destroy(interface_table);
5760                 interface_table = NULL;
5761         }
5762
5763         if (system_available)
5764                 callback_system_killed();
5765
5766         if (connection) {
5767                 dbus_connection_unref(connection);
5768                 connection = NULL;
5769         }
5770
5771         callbacks_pointer = NULL;
5772         eap_methods = 0;
5773 }