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