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