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