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