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