55e0abe1960e2a1bc15511829d9f8aecba864cb2
[platform/upstream/connman.git] / gsupplicant / supplicant.c
1 /*
2  *
3  *  WPA supplicant library with GLib integration
4  *
5  *  Copyright (C) 2010  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
34 #include <glib.h>
35 #include <gdbus.h>
36
37 #include "dbus.h"
38 #include "gsupplicant.h"
39
40 #define TIMEOUT 5000
41
42 #define IEEE80211_CAP_ESS       0x0001
43 #define IEEE80211_CAP_IBSS      0x0002
44 #define IEEE80211_CAP_PRIVACY   0x0010
45
46 static DBusConnection *connection;
47
48 static const GSupplicantCallbacks *callbacks_pointer;
49
50 static dbus_bool_t system_available = FALSE;
51 static dbus_bool_t system_ready = FALSE;
52
53 static dbus_int32_t debug_level;
54 static dbus_bool_t debug_timestamp = FALSE;
55 static dbus_bool_t debug_showkeys = FALSE;
56
57 static const char *debug_strings[] = {
58         "msgdump", "debug", "info", "warning", "error", NULL
59 };
60
61 static unsigned int eap_methods;
62
63 struct strvalmap {
64         const char *str;
65         unsigned int val;
66 };
67
68 static struct strvalmap eap_method_map[] = {
69         { "MD5",        G_SUPPLICANT_EAP_METHOD_MD5     },
70         { "TLS",        G_SUPPLICANT_EAP_METHOD_TLS     },
71         { "MSCHAPV2",   G_SUPPLICANT_EAP_METHOD_MSCHAPV2        },
72         { "PEAP",       G_SUPPLICANT_EAP_METHOD_PEAP    },
73         { "TTLS",       G_SUPPLICANT_EAP_METHOD_TTLS    },
74         { "GTC",        G_SUPPLICANT_EAP_METHOD_GTC     },
75         { "OTP",        G_SUPPLICANT_EAP_METHOD_OTP     },
76         { "LEAP",       G_SUPPLICANT_EAP_METHOD_LEAP    },
77         { "WSC",        G_SUPPLICANT_EAP_METHOD_WSC     },
78         { }
79 };
80
81 static struct strvalmap keymgmt_map[] = {
82         { "none",               G_SUPPLICANT_KEYMGMT_NONE               },
83         { "ieee8021x",          G_SUPPLICANT_KEYMGMT_IEEE8021X  },
84         { "wpa-none",           G_SUPPLICANT_KEYMGMT_WPA_NONE   },
85         { "wpa-psk",            G_SUPPLICANT_KEYMGMT_WPA_PSK    },
86         { "wpa-psk-sha256",     G_SUPPLICANT_KEYMGMT_WPA_PSK_256        },
87         { "wpa-ft-psk",         G_SUPPLICANT_KEYMGMT_WPA_FT_PSK },
88         { "wpa-ft-eap",         G_SUPPLICANT_KEYMGMT_WPA_FT_EAP },
89         { "wpa-eap",            G_SUPPLICANT_KEYMGMT_WPA_EAP    },
90         { "wpa-eap-sha256",     G_SUPPLICANT_KEYMGMT_WPA_EAP_256        },
91         { "wps",                G_SUPPLICANT_KEYMGMT_WPS                },
92         { }
93 };
94
95 static struct strvalmap authalg_capa_map[] = {
96         { "open",       G_SUPPLICANT_CAPABILITY_AUTHALG_OPEN    },
97         { "shared",     G_SUPPLICANT_CAPABILITY_AUTHALG_SHARED  },
98         { "leap",       G_SUPPLICANT_CAPABILITY_AUTHALG_LEAP    },
99         { }
100 };
101
102 static struct strvalmap proto_capa_map[] = {
103         { "wpa",        G_SUPPLICANT_CAPABILITY_PROTO_WPA               },
104         { "rsn",        G_SUPPLICANT_CAPABILITY_PROTO_RSN               },
105         { }
106 };
107
108 static struct strvalmap group_map[] = {
109         { "wep40",      G_SUPPLICANT_GROUP_WEP40        },
110         { "wep104",     G_SUPPLICANT_GROUP_WEP104       },
111         { "tkip",       G_SUPPLICANT_GROUP_TKIP },
112         { "ccmp",       G_SUPPLICANT_GROUP_CCMP },
113         { }
114 };
115
116 static struct strvalmap pairwise_map[] = {
117         { "none",       G_SUPPLICANT_PAIRWISE_NONE      },
118         { "tkip",       G_SUPPLICANT_PAIRWISE_TKIP      },
119         { "ccmp",       G_SUPPLICANT_PAIRWISE_CCMP      },
120         { }
121 };
122
123 static struct strvalmap scan_capa_map[] = {
124         { "active",     G_SUPPLICANT_CAPABILITY_SCAN_ACTIVE     },
125         { "passive",    G_SUPPLICANT_CAPABILITY_SCAN_PASSIVE    },
126         { "ssid",       G_SUPPLICANT_CAPABILITY_SCAN_SSID               },
127         { }
128 };
129
130 static struct strvalmap mode_capa_map[] = {
131         { "infrastructure",     G_SUPPLICANT_CAPABILITY_MODE_INFRA      },
132         { "ad-hoc",             G_SUPPLICANT_CAPABILITY_MODE_IBSS       },
133         { "ap",                 G_SUPPLICANT_CAPABILITY_MODE_AP         },
134         { }
135 };
136
137 static GHashTable *interface_table;
138 static GHashTable *bss_mapping;
139
140 struct _GSupplicantWpsCredentials {
141         unsigned char ssid[32];
142         unsigned int ssid_len;
143         char *key;
144 };
145
146 struct _GSupplicantInterface {
147         char *path;
148         char *network_path;
149         unsigned int keymgmt_capa;
150         unsigned int authalg_capa;
151         unsigned int proto_capa;
152         unsigned int group_capa;
153         unsigned int pairwise_capa;
154         unsigned int scan_capa;
155         unsigned int mode_capa;
156         dbus_bool_t ready;
157         GSupplicantState state;
158         dbus_bool_t scanning;
159         GSupplicantInterfaceCallback scan_callback;
160         void *scan_data;
161         int apscan;
162         char *ifname;
163         char *driver;
164         char *bridge;
165         struct _GSupplicantWpsCredentials wps_cred;
166         GSupplicantWpsState wps_state;
167         GHashTable *network_table;
168         GHashTable *net_mapping;
169         GHashTable *bss_mapping;
170         void *data;
171 };
172
173 struct g_supplicant_bss {
174         GSupplicantInterface *interface;
175         char *path;
176         unsigned char bssid[6];
177         unsigned char ssid[32];
178         unsigned int ssid_len;
179         dbus_uint16_t frequency;
180         dbus_uint32_t maxrate;
181         dbus_int16_t signal;
182         GSupplicantMode mode;
183         GSupplicantSecurity security;
184         unsigned int keymgmt;
185         unsigned int pairwise;
186         unsigned int group;
187         dbus_bool_t privacy;
188         dbus_bool_t psk;
189         dbus_bool_t ieee8021x;
190 };
191
192 struct _GSupplicantNetwork {
193         GSupplicantInterface *interface;
194         char *path;
195         char *group;
196         char *name;
197         unsigned char ssid[32];
198         unsigned int ssid_len;
199         dbus_int16_t signal;
200         struct g_supplicant_bss *best_bss;
201         GSupplicantMode mode;
202         GSupplicantSecurity security;
203         dbus_bool_t wps;
204         GHashTable *bss_table;
205         GHashTable *config_table;
206 };
207
208 static inline void debug(const char *format, ...)
209 {
210         char str[256];
211         va_list ap;
212
213         if (callbacks_pointer->debug == NULL)
214                 return;
215
216         va_start(ap, format);
217
218         if (vsnprintf(str, sizeof(str), format, ap) > 0)
219                 callbacks_pointer->debug(str);
220
221         va_end(ap);
222 }
223
224 #define SUPPLICANT_DBG(fmt, arg...) \
225         debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg);
226
227 static GSupplicantMode string2mode(const char *mode)
228 {
229         if (mode == NULL)
230                 return G_SUPPLICANT_MODE_UNKNOWN;
231
232         if (g_str_equal(mode, "infrastructure") == TRUE)
233                 return G_SUPPLICANT_MODE_INFRA;
234         else if (g_str_equal(mode, "ad-hoc") == TRUE)
235                 return G_SUPPLICANT_MODE_IBSS;
236
237         return G_SUPPLICANT_MODE_UNKNOWN;
238 }
239
240 static const char *mode2string(GSupplicantMode mode)
241 {
242         switch (mode) {
243         case G_SUPPLICANT_MODE_UNKNOWN:
244                 break;
245         case G_SUPPLICANT_MODE_INFRA:
246                 return "managed";
247         case G_SUPPLICANT_MODE_IBSS:
248                 return "adhoc";
249         case G_SUPPLICANT_MODE_MASTER:
250                 return "ap";
251         }
252
253         return NULL;
254 }
255
256 static const char *security2string(GSupplicantSecurity security)
257 {
258         switch (security) {
259         case G_SUPPLICANT_SECURITY_UNKNOWN:
260                 break;
261         case G_SUPPLICANT_SECURITY_NONE:
262                 return "none";
263         case G_SUPPLICANT_SECURITY_WEP:
264                 return "wep";
265         case G_SUPPLICANT_SECURITY_PSK:
266                 return "psk";
267         case G_SUPPLICANT_SECURITY_IEEE8021X:
268                 return "ieee8021x";
269         }
270
271         return NULL;
272 }
273
274 static GSupplicantState string2state(const char *state)
275 {
276         if (state == NULL)
277                 return G_SUPPLICANT_STATE_UNKNOWN;
278
279         if (g_str_equal(state, "unknown") == TRUE)
280                 return G_SUPPLICANT_STATE_UNKNOWN;
281         else if (g_str_equal(state, "disconnected") == TRUE)
282                 return G_SUPPLICANT_STATE_DISCONNECTED;
283         else if (g_str_equal(state, "inactive") == TRUE)
284                 return G_SUPPLICANT_STATE_INACTIVE;
285         else if (g_str_equal(state, "scanning") == TRUE)
286                 return G_SUPPLICANT_STATE_SCANNING;
287         else if (g_str_equal(state, "authenticating") == TRUE)
288                 return G_SUPPLICANT_STATE_AUTHENTICATING;
289         else if (g_str_equal(state, "associating") == TRUE)
290                 return G_SUPPLICANT_STATE_ASSOCIATING;
291         else if (g_str_equal(state, "associated") == TRUE)
292                 return G_SUPPLICANT_STATE_ASSOCIATED;
293         else if (g_str_equal(state, "group_handshake") == TRUE)
294                 return G_SUPPLICANT_STATE_GROUP_HANDSHAKE;
295         else if (g_str_equal(state, "4way_handshake") == TRUE)
296                 return G_SUPPLICANT_STATE_4WAY_HANDSHAKE;
297         else if (g_str_equal(state, "completed") == TRUE)
298                 return G_SUPPLICANT_STATE_COMPLETED;
299
300         return G_SUPPLICANT_STATE_UNKNOWN;
301 }
302
303 static void callback_system_ready(void)
304 {
305         if (system_ready == TRUE)
306                 return;
307
308         system_ready = TRUE;
309
310         if (callbacks_pointer == NULL)
311                 return;
312
313         if (callbacks_pointer->system_ready == NULL)
314                 return;
315
316         callbacks_pointer->system_ready();
317 }
318
319 static void callback_system_killed(void)
320 {
321         system_ready = FALSE;
322
323         if (callbacks_pointer == NULL)
324                 return;
325
326         if (callbacks_pointer->system_killed == NULL)
327                 return;
328
329         callbacks_pointer->system_killed();
330 }
331
332 static void callback_interface_added(GSupplicantInterface *interface)
333 {
334         SUPPLICANT_DBG("");
335
336         if (callbacks_pointer == NULL)
337                 return;
338
339         if (callbacks_pointer->interface_added == NULL)
340                 return;
341
342         callbacks_pointer->interface_added(interface);
343 }
344
345 static void callback_interface_state(GSupplicantInterface *interface)
346 {
347         if (callbacks_pointer == NULL)
348                 return;
349
350         if (callbacks_pointer->interface_state == NULL)
351                 return;
352
353         callbacks_pointer->interface_state(interface);
354 }
355
356 static void callback_interface_removed(GSupplicantInterface *interface)
357 {
358         if (callbacks_pointer == NULL)
359                 return;
360
361         if (callbacks_pointer->interface_removed == NULL)
362                 return;
363
364         callbacks_pointer->interface_removed(interface);
365 }
366
367 static void callback_scan_started(GSupplicantInterface *interface)
368 {
369         if (callbacks_pointer == NULL)
370                 return;
371
372         if (callbacks_pointer->scan_started == NULL)
373                 return;
374
375         callbacks_pointer->scan_started(interface);
376 }
377
378 static void callback_scan_finished(GSupplicantInterface *interface)
379 {
380         if (callbacks_pointer == NULL)
381                 return;
382
383         if (callbacks_pointer->scan_finished == NULL)
384                 return;
385
386         callbacks_pointer->scan_finished(interface);
387 }
388
389 static void callback_network_added(GSupplicantNetwork *network)
390 {
391         if (callbacks_pointer == NULL)
392                 return;
393
394         if (callbacks_pointer->network_added == NULL)
395                 return;
396
397         callbacks_pointer->network_added(network);
398 }
399
400 static void callback_network_removed(GSupplicantNetwork *network)
401 {
402         if (callbacks_pointer == NULL)
403                 return;
404
405         if (callbacks_pointer->network_removed == NULL)
406                 return;
407
408         callbacks_pointer->network_removed(network);
409 }
410
411 static void remove_interface(gpointer data)
412 {
413         GSupplicantInterface *interface = data;
414
415         g_hash_table_destroy(interface->bss_mapping);
416         g_hash_table_destroy(interface->net_mapping);
417         g_hash_table_destroy(interface->network_table);
418
419         callback_interface_removed(interface);
420
421         g_free(interface->wps_cred.key);
422         g_free(interface->path);
423         g_free(interface->network_path);
424         g_free(interface->ifname);
425         g_free(interface->driver);
426         g_free(interface->bridge);
427         g_free(interface);
428 }
429
430 static void remove_network(gpointer data)
431 {
432         GSupplicantNetwork *network = data;
433
434         g_hash_table_destroy(network->bss_table);
435
436         callback_network_removed(network);
437
438         g_hash_table_destroy(network->config_table);
439
440         g_free(network->path);
441         g_free(network->group);
442         g_free(network->name);
443         g_free(network);
444 }
445
446 static void remove_bss(gpointer data)
447 {
448         struct g_supplicant_bss *bss = data;
449
450         g_free(bss->path);
451         g_free(bss);
452 }
453
454 static void debug_strvalmap(const char *label, struct strvalmap *map,
455                                                         unsigned int val)
456 {
457         int i;
458
459         for (i = 0; map[i].str != NULL; i++) {
460                 if (val & map[i].val)
461                         SUPPLICANT_DBG("%s: %s", label, map[i].str);
462         }
463 }
464
465 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
466 {
467         GSupplicantInterface *interface = user_data;
468         const char *str = NULL;
469         int i;
470
471         dbus_message_iter_get_basic(iter, &str);
472         if (str == NULL)
473                 return;
474
475         for (i = 0; keymgmt_map[i].str != NULL; i++)
476                 if (strcmp(str, keymgmt_map[i].str) == 0) {
477                         interface->keymgmt_capa |= keymgmt_map[i].val;
478                         break;
479                 }
480 }
481
482 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
483 {
484         GSupplicantInterface *interface = user_data;
485         const char *str = NULL;
486         int i;
487
488         dbus_message_iter_get_basic(iter, &str);
489         if (str == NULL)
490                 return;
491
492         for (i = 0; authalg_capa_map[i].str != NULL; i++)
493                 if (strcmp(str, authalg_capa_map[i].str) == 0) {
494                         interface->authalg_capa |= authalg_capa_map[i].val;
495                         break;
496                 }
497 }
498
499 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
500 {
501         GSupplicantInterface *interface = user_data;
502         const char *str = NULL;
503         int i;
504
505         dbus_message_iter_get_basic(iter, &str);
506         if (str == NULL)
507                 return;
508
509         for (i = 0; proto_capa_map[i].str != NULL; i++)
510                 if (strcmp(str, proto_capa_map[i].str) == 0) {
511                         interface->proto_capa |= proto_capa_map[i].val;
512                         break;
513                 }
514 }
515
516 static void interface_capability_pairwise(DBusMessageIter *iter,
517                                                         void *user_data)
518 {
519         GSupplicantInterface *interface = user_data;
520         const char *str = NULL;
521         int i;
522
523         dbus_message_iter_get_basic(iter, &str);
524         if (str == NULL)
525                 return;
526
527         for (i = 0; pairwise_map[i].str != NULL; i++)
528                 if (strcmp(str, pairwise_map[i].str) == 0) {
529                         interface->pairwise_capa |= pairwise_map[i].val;
530                         break;
531                 }
532 }
533
534 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
535 {
536         GSupplicantInterface *interface = user_data;
537         const char *str = NULL;
538         int i;
539
540         dbus_message_iter_get_basic(iter, &str);
541         if (str == NULL)
542                 return;
543
544         for (i = 0; group_map[i].str != NULL; i++)
545                 if (strcmp(str, group_map[i].str) == 0) {
546                         interface->group_capa |= group_map[i].val;
547                         break;
548                 }
549 }
550
551 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
552 {
553         GSupplicantInterface *interface = user_data;
554         const char *str = NULL;
555         int i;
556
557         dbus_message_iter_get_basic(iter, &str);
558         if (str == NULL)
559                 return;
560
561         for (i = 0; scan_capa_map[i].str != NULL; i++)
562                 if (strcmp(str, scan_capa_map[i].str) == 0) {
563                         interface->scan_capa |= scan_capa_map[i].val;
564                         break;
565                 }
566 }
567
568 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
569 {
570         GSupplicantInterface *interface = user_data;
571         const char *str = NULL;
572         int i;
573
574         dbus_message_iter_get_basic(iter, &str);
575         if (str == NULL)
576                 return;
577
578         for (i = 0; mode_capa_map[i].str != NULL; i++)
579                 if (strcmp(str, mode_capa_map[i].str) == 0) {
580                         interface->mode_capa |= mode_capa_map[i].val;
581                         break;
582                 }
583 }
584
585 static void interface_capability(const char *key, DBusMessageIter *iter,
586                                                         void *user_data)
587 {
588         GSupplicantInterface *interface = user_data;
589
590         if (key == NULL)
591                 return;
592
593         if (g_strcmp0(key, "KeyMgmt") == 0)
594                 supplicant_dbus_array_foreach(iter,
595                                 interface_capability_keymgmt, interface);
596         else if (g_strcmp0(key, "AuthAlg") == 0)
597                 supplicant_dbus_array_foreach(iter,
598                                 interface_capability_authalg, interface);
599         else if (g_strcmp0(key, "Protocol") == 0)
600                 supplicant_dbus_array_foreach(iter,
601                                 interface_capability_proto, interface);
602         else if (g_strcmp0(key, "Pairwise") == 0)
603                 supplicant_dbus_array_foreach(iter,
604                                 interface_capability_pairwise, interface);
605         else if (g_strcmp0(key, "Group") == 0)
606                 supplicant_dbus_array_foreach(iter,
607                                 interface_capability_group, interface);
608         else if (g_strcmp0(key, "Scan") == 0)
609                 supplicant_dbus_array_foreach(iter,
610                                 interface_capability_scan, interface);
611         else if (g_strcmp0(key, "Modes") == 0)
612                 supplicant_dbus_array_foreach(iter,
613                                 interface_capability_mode, interface);
614         else
615                 SUPPLICANT_DBG("key %s type %c",
616                                 key, dbus_message_iter_get_arg_type(iter));
617 }
618
619 static void set_apscan(DBusMessageIter *iter, void *user_data)
620 {
621         unsigned int ap_scan = *(unsigned int *)user_data;
622
623         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ap_scan);
624 }
625
626 int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
627                                                         unsigned int ap_scan)
628 {
629         return supplicant_dbus_property_set(interface->path,
630                         SUPPLICANT_INTERFACE ".Interface",
631                                 "ApScan", DBUS_TYPE_UINT32_AS_STRING,
632                                         set_apscan, NULL, &ap_scan);
633 }
634
635 void g_supplicant_interface_set_data(GSupplicantInterface *interface,
636                                                                 void *data)
637 {
638         if (interface == NULL)
639                 return;
640
641         interface->data = data;
642 }
643
644 void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
645 {
646         if (interface == NULL)
647                 return NULL;
648
649         return interface->data;
650 }
651
652 const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface)
653 {
654         if (interface == NULL)
655                 return NULL;
656
657         return interface->ifname;
658 }
659
660 const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface)
661 {
662         if (interface == NULL)
663                 return NULL;
664
665         return interface->driver;
666 }
667
668 GSupplicantState g_supplicant_interface_get_state(
669                                         GSupplicantInterface *interface)
670 {
671         if (interface == NULL)
672                 return G_SUPPLICANT_STATE_UNKNOWN;
673
674         return interface->state;
675 }
676
677 const char *g_supplicant_interface_get_wps_key(GSupplicantInterface *interface)
678 {
679         if (interface == NULL)
680                 return NULL;
681
682         return (const char *)interface->wps_cred.key;
683 }
684
685 const void *g_supplicant_interface_get_wps_ssid(GSupplicantInterface *interface,
686                                                         unsigned int *ssid_len)
687 {
688         if (ssid_len == NULL)
689                 return NULL;
690
691         if (interface == NULL || interface->wps_cred.ssid == NULL) {
692                 *ssid_len = 0;
693                 return NULL;
694         }
695
696         *ssid_len = interface->wps_cred.ssid_len;
697         return interface->wps_cred.ssid;
698 }
699
700 GSupplicantWpsState g_supplicant_interface_get_wps_state(
701                                         GSupplicantInterface *interface)
702 {
703         if (interface == NULL)
704                 return G_SUPPLICANT_WPS_STATE_UNKNOWN;
705
706         return interface->wps_state;
707 }
708
709 unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface)
710 {
711         if (interface == NULL)
712                 return 0;
713
714         return interface->mode_capa;
715 }
716
717 GSupplicantInterface *g_supplicant_network_get_interface(
718                                         GSupplicantNetwork *network)
719 {
720         if (network == NULL)
721                 return NULL;
722
723         return network->interface;
724 }
725
726 const char *g_supplicant_network_get_name(GSupplicantNetwork *network)
727 {
728         if (network == NULL || network->name == NULL)
729                 return "";
730
731         return network->name;
732 }
733
734 const char *g_supplicant_network_get_identifier(GSupplicantNetwork *network)
735 {
736         if (network == NULL || network->group == NULL)
737                 return "";
738
739         return network->group;
740 }
741
742 const char *g_supplicant_network_get_path(GSupplicantNetwork *network)
743 {
744         if (network == NULL || network->path == NULL)
745                 return NULL;
746
747         return network->path;
748 }
749
750 const char *g_supplicant_network_get_mode(GSupplicantNetwork *network)
751 {
752         if (network == NULL)
753                 return G_SUPPLICANT_MODE_UNKNOWN;
754
755         return mode2string(network->mode);
756 }
757
758 const char *g_supplicant_network_get_security(GSupplicantNetwork *network)
759 {
760         if (network == NULL)
761                 return G_SUPPLICANT_SECURITY_UNKNOWN;
762
763         return security2string(network->security);
764 }
765
766 const void *g_supplicant_network_get_ssid(GSupplicantNetwork *network,
767                                                 unsigned int *ssid_len)
768 {
769         if (network == NULL || network->ssid == NULL) {
770                 *ssid_len = 0;
771                 return NULL;
772         }
773
774         *ssid_len = network->ssid_len;
775         return network->ssid;
776 }
777
778 dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network)
779 {
780         if (network == NULL)
781                 return 0;
782
783         return network->signal;
784 }
785
786 dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network)
787 {
788         if (network == NULL)
789                 return FALSE;
790
791         return network->wps;
792 }
793
794 static void merge_network(GSupplicantNetwork *network)
795 {
796         GString *str;
797         const char *ssid, *mode, *key_mgmt;
798         unsigned int i, ssid_len;
799         char *group;
800
801         ssid = g_hash_table_lookup(network->config_table, "ssid");
802         mode = g_hash_table_lookup(network->config_table, "mode");
803         key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
804
805         SUPPLICANT_DBG("ssid %s mode %s", ssid, mode);
806
807         if (ssid != NULL)
808                 ssid_len = strlen(ssid);
809         else
810                 ssid_len = 0;
811
812         str = g_string_sized_new((ssid_len * 2) + 24);
813         if (str == NULL)
814                 return;
815
816         for (i = 0; i < ssid_len; i++)
817                 g_string_append_printf(str, "%02x", ssid[i]);
818
819         if (g_strcmp0(mode, "0") == 0)
820                 g_string_append_printf(str, "_managed");
821         else if (g_strcmp0(mode, "1") == 0)
822                 g_string_append_printf(str, "_adhoc");
823
824         if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
825                 g_string_append_printf(str, "_psk");
826
827         group = g_string_free(str, FALSE);
828
829         SUPPLICANT_DBG("%s", group);
830
831         g_free(group);
832
833         g_hash_table_destroy(network->config_table);
834
835         g_free(network->path);
836         g_free(network);
837 }
838
839 static void network_property(const char *key, DBusMessageIter *iter,
840                                                         void *user_data)
841 {
842         GSupplicantNetwork *network = user_data;
843
844         if (network->interface == NULL)
845                 return;
846
847         if (key == NULL) {
848                 merge_network(network);
849                 return;
850         }
851
852         if (g_strcmp0(key, "Enabled") == 0) {
853                 dbus_bool_t enabled = FALSE;
854
855                 dbus_message_iter_get_basic(iter, &enabled);
856         } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
857                 const char *str = NULL;
858
859                 dbus_message_iter_get_basic(iter, &str);
860                 if (str != NULL) {
861                         g_hash_table_replace(network->config_table,
862                                                 g_strdup(key), g_strdup(str));
863                 }
864         } else
865                 SUPPLICANT_DBG("key %s type %c",
866                                 key, dbus_message_iter_get_arg_type(iter));
867 }
868
869 static void interface_network_added(DBusMessageIter *iter, void *user_data)
870 {
871         GSupplicantInterface *interface = user_data;
872         GSupplicantNetwork *network;
873         const char *path = NULL;
874
875         SUPPLICANT_DBG("");
876
877         dbus_message_iter_get_basic(iter, &path);
878         if (path == NULL)
879                 return;
880
881         if (g_strcmp0(path, "/") == 0)
882                 return;
883
884         network = g_hash_table_lookup(interface->net_mapping, path);
885         if (network != NULL)
886                 return;
887
888         network = g_try_new0(GSupplicantNetwork, 1);
889         if (network == NULL)
890                 return;
891
892         network->interface = interface;
893         network->path = g_strdup(path);
894
895         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
896                                                         g_free, g_free);
897
898         dbus_message_iter_next(iter);
899         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
900                 supplicant_dbus_property_foreach(iter, network_property,
901                                                                 network);
902                 network_property(NULL, NULL, network);
903                 return;
904         }
905
906         supplicant_dbus_property_get_all(path,
907                                 SUPPLICANT_INTERFACE ".Network",
908                                                 network_property, network);
909 }
910
911 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
912 {
913         GSupplicantInterface *interface = user_data;
914         GSupplicantNetwork *network;
915         const char *path = NULL;
916
917         dbus_message_iter_get_basic(iter, &path);
918         if (path == NULL)
919                 return;
920
921         network = g_hash_table_lookup(interface->net_mapping, path);
922         if (network == NULL)
923                 return;
924
925         g_hash_table_remove(interface->net_mapping, path);
926 }
927
928 static char *create_name(unsigned char *ssid, int ssid_len)
929 {
930         char *name;
931         int i;
932
933         if (ssid_len < 1 || ssid[0] == '\0')
934                 name = NULL;
935         else
936                 name = g_try_malloc0(ssid_len + 1);
937
938         if (name == NULL)
939                 return g_strdup("");
940
941         for (i = 0; i < ssid_len; i++) {
942                 if (g_ascii_isprint(ssid[i]))
943                         name[i] = ssid[i];
944                 else
945                         name[i] = ' ';
946         }
947
948         return name;
949 }
950
951 static char *create_group(struct g_supplicant_bss *bss)
952 {
953         GString *str;
954         unsigned int i;
955         const char *mode, *security;
956
957         str = g_string_sized_new((bss->ssid_len * 2) + 24);
958         if (str == NULL)
959                 return NULL;
960
961         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
962                 for (i = 0; i < bss->ssid_len; i++)
963                         g_string_append_printf(str, "%02x", bss->ssid[i]);
964         } else
965                 g_string_append_printf(str, "hidden");
966
967         mode = mode2string(bss->mode);
968         if (mode != NULL)
969                 g_string_append_printf(str, "_%s", mode);
970
971         security = security2string(bss->security);
972         if (security != NULL)
973                 g_string_append_printf(str, "_%s", security);
974
975         return g_string_free(str, FALSE);
976 }
977
978 static void add_bss_to_network(struct g_supplicant_bss *bss)
979 {
980         GSupplicantInterface *interface = bss->interface;
981         GSupplicantNetwork *network;
982         char *group;
983
984         group = create_group(bss);
985         if (group == NULL)
986                 return;
987
988         network = g_hash_table_lookup(interface->network_table, group);
989         if (network != NULL) {
990                 g_free(group);
991                 goto done;
992         }
993
994         network = g_try_new0(GSupplicantNetwork, 1);
995         if (network == NULL) {
996                 g_free(group);
997                 return;
998         }
999
1000         network->interface = interface;
1001         if (network->path == NULL)
1002                 network->path = g_strdup(bss->path);
1003         network->group = group;
1004         network->name = create_name(bss->ssid, bss->ssid_len);
1005         network->mode = bss->mode;
1006         network->security = bss->security;
1007         network->ssid_len = bss->ssid_len;
1008         memcpy(network->ssid, bss->ssid, bss->ssid_len);
1009         network->signal = bss->signal;
1010         network->best_bss = bss;
1011
1012         network->wps = FALSE;
1013         if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0)
1014                 network->wps = TRUE;
1015
1016         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1017                                                         NULL, remove_bss);
1018
1019         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1020                                                         g_free, g_free);
1021
1022         g_hash_table_replace(interface->network_table,
1023                                                 network->group, network);
1024
1025         callback_network_added(network);
1026
1027 done:
1028         if (bss->signal > network->signal) {
1029                 network->signal = bss->signal;
1030                 network->best_bss = bss;
1031         }
1032
1033         g_hash_table_replace(interface->bss_mapping, bss->path, network);
1034         g_hash_table_replace(network->bss_table, bss->path, bss);
1035
1036         g_hash_table_replace(bss_mapping, bss->path, interface);
1037 }
1038
1039 static void bss_rates(DBusMessageIter *iter, void *user_data)
1040 {
1041         struct g_supplicant_bss *bss = user_data;
1042         dbus_uint32_t rate = 0;
1043
1044         dbus_message_iter_get_basic(iter, &rate);
1045         if (rate == 0)
1046                 return;
1047
1048         if (rate > bss->maxrate)
1049                 bss->maxrate = rate;
1050 }
1051
1052 static void bss_keymgmt(DBusMessageIter *iter, void *user_data)
1053 {
1054         struct g_supplicant_bss *bss = user_data;
1055         const char *str = NULL;
1056         int i;
1057
1058         dbus_message_iter_get_basic(iter, &str);
1059         if (str == NULL)
1060                 return;
1061
1062         for (i = 0; keymgmt_map[i].str != NULL; i++)
1063                 if (strcmp(str, keymgmt_map[i].str) == 0) {
1064                         bss->keymgmt |= keymgmt_map[i].val;
1065                         break;
1066                 }
1067 }
1068
1069 static void bss_group(DBusMessageIter *iter, void *user_data)
1070 {
1071         struct g_supplicant_bss *bss = user_data;
1072         const char *str = NULL;
1073         int i;
1074
1075         dbus_message_iter_get_basic(iter, &str);
1076         if (str == NULL)
1077                 return;
1078
1079         for (i = 0; group_map[i].str != NULL; i++)
1080                 if (strcmp(str, group_map[i].str) == 0) {
1081                         bss->group |= group_map[i].val;
1082                         break;
1083                 }
1084 }
1085
1086 static void bss_pairwise(DBusMessageIter *iter, void *user_data)
1087 {
1088         struct g_supplicant_bss *bss = user_data;
1089         const char *str = NULL;
1090         int i;
1091
1092         dbus_message_iter_get_basic(iter, &str);
1093         if (str == NULL)
1094                 return;
1095
1096         for (i = 0; pairwise_map[i].str != NULL; i++)
1097                 if (strcmp(str, pairwise_map[i].str) == 0) {
1098                         bss->pairwise |= pairwise_map[i].val;
1099                         break;
1100                 }
1101 }
1102
1103 static void bss_wpa(const char *key, DBusMessageIter *iter,
1104                         void *user_data)
1105 {
1106         if (g_strcmp0(key, "KeyMgmt") == 0)
1107                 supplicant_dbus_array_foreach(iter, bss_keymgmt, user_data);
1108         else if (g_strcmp0(key, "Group") == 0)
1109                 supplicant_dbus_array_foreach(iter, bss_group, user_data);
1110         else if (g_strcmp0(key, "Pairwise") == 0)
1111                 supplicant_dbus_array_foreach(iter, bss_pairwise, user_data);
1112
1113 }
1114
1115 static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size,
1116                                                         unsigned int type)
1117 {
1118         unsigned int len = 0;
1119
1120         while (len + 4 < ie_size) {
1121                 unsigned int hi = ie[len];
1122                 unsigned int lo = ie[len + 1];
1123                 unsigned int tmp_type = (hi << 8) + lo;
1124                 unsigned int v_len = 0;
1125
1126                 /* hi and lo are used to recreate an unsigned int
1127                  * based on 2 8bits length unsigned int. */
1128
1129                 hi = ie[len + 2];
1130                 lo = ie[len + 3];
1131                 v_len = (hi << 8) + lo;
1132
1133                 if (tmp_type == type) {
1134                         unsigned int ret_value = 0;
1135                         unsigned char *value = (unsigned char *)&ret_value;
1136
1137                         SUPPLICANT_DBG("IE: match type 0x%x", type);
1138
1139                         /* Verifying length relevance */
1140                         if (v_len > sizeof(unsigned int) ||
1141                                 len + 4 + v_len > ie_size)
1142                                 break;
1143
1144                         memcpy(value, ie + len + 4, v_len);
1145
1146                         SUPPLICANT_DBG("returning 0x%x", ret_value);
1147                         return ret_value;
1148                 }
1149
1150                 len += v_len + 4;
1151         }
1152
1153         SUPPLICANT_DBG("returning 0");
1154         return 0;
1155 }
1156
1157 static void bss_process_ies(DBusMessageIter *iter, void *user_data)
1158 {
1159         struct g_supplicant_bss *bss = user_data;
1160         const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
1161         unsigned char *ie, *ie_end;
1162         DBusMessageIter array;
1163         int ie_len;
1164
1165 #define WMM_WPA1_WPS_INFO 221
1166 #define WPS_INFO_MIN_LEN  6
1167 #define WPS_VERSION_TLV   0x104A
1168 #define WPS_STATE_TLV     0x1044
1169 #define WPS_VERSION       0x10
1170
1171         dbus_message_iter_recurse(iter, &array);
1172         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1173
1174         if (ie == NULL || ie_len < 2)
1175                 return;
1176
1177         for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end;
1178                                                         ie += ie[1] + 2) {
1179
1180                 if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
1181                         memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
1182                         continue;
1183
1184                 SUPPLICANT_DBG("IE: match WPS_OUI");
1185
1186                 if (get_tlv(&ie[6], ie[1],
1187                                 WPS_VERSION_TLV) == WPS_VERSION &&
1188                         get_tlv(&ie[6], ie[1],
1189                                 WPS_STATE_TLV) != 0)
1190                         bss->keymgmt |= G_SUPPLICANT_KEYMGMT_WPS;
1191         }
1192 }
1193
1194 static void bss_property(const char *key, DBusMessageIter *iter,
1195                                                         void *user_data)
1196 {
1197         struct g_supplicant_bss *bss = user_data;
1198
1199         if (bss->interface == NULL)
1200                 return;
1201
1202         SUPPLICANT_DBG("key %s", key);
1203
1204         if (key == NULL) {
1205                 if (bss->ieee8021x == TRUE)
1206                         bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
1207                 else if (bss->psk == TRUE)
1208                         bss->security = G_SUPPLICANT_SECURITY_PSK;
1209                 else if (bss->privacy == TRUE)
1210                         bss->security = G_SUPPLICANT_SECURITY_WEP;
1211                 else
1212                         bss->security = G_SUPPLICANT_SECURITY_NONE;
1213
1214                 add_bss_to_network(bss);
1215                 return;
1216         }
1217
1218         if (g_strcmp0(key, "BSSID") == 0) {
1219                 DBusMessageIter array;
1220                 unsigned char *addr;
1221                 int addr_len;
1222
1223                 dbus_message_iter_recurse(iter, &array);
1224                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
1225
1226                 if (addr_len == 6)
1227                         memcpy(bss->bssid, addr, addr_len);
1228         } else if (g_strcmp0(key, "SSID") == 0) {
1229                 DBusMessageIter array;
1230                 unsigned char *ssid;
1231                 int ssid_len;
1232
1233                 dbus_message_iter_recurse(iter, &array);
1234                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
1235
1236                 if (ssid_len > 0 && ssid_len < 33) {
1237                         memcpy(bss->ssid, ssid, ssid_len);
1238                         bss->ssid_len = ssid_len;
1239                 } else {
1240                         memset(bss->ssid, 0, sizeof(bss->ssid));
1241                         bss->ssid_len = 0;
1242                 }
1243         } else if (g_strcmp0(key, "Capabilities") == 0) {
1244                 dbus_uint16_t capabilities = 0x0000;
1245
1246                 dbus_message_iter_get_basic(iter, &capabilities);
1247
1248                 if (capabilities & IEEE80211_CAP_ESS)
1249                         bss->mode = G_SUPPLICANT_MODE_INFRA;
1250                 else if (capabilities & IEEE80211_CAP_IBSS)
1251                         bss->mode = G_SUPPLICANT_MODE_IBSS;
1252
1253                 if (capabilities & IEEE80211_CAP_PRIVACY)
1254                         bss->privacy = TRUE;
1255         } else if (g_strcmp0(key, "Mode") == 0) {
1256                 const char *mode = NULL;
1257
1258                 dbus_message_iter_get_basic(iter, &mode);
1259                 bss->mode = string2mode(mode);
1260         } else if (g_strcmp0(key, "Frequency") == 0) {
1261                 dbus_uint16_t frequency = 0;
1262
1263                 dbus_message_iter_get_basic(iter, &frequency);
1264                 bss->frequency = frequency;
1265         } else if (g_strcmp0(key, "Signal") == 0) {
1266                 dbus_int16_t signal = 0;
1267
1268                 dbus_message_iter_get_basic(iter, &signal);
1269
1270                 bss->signal = signal;
1271         } else if (g_strcmp0(key, "Level") == 0) {
1272                 dbus_int32_t level = 0;
1273
1274                 dbus_message_iter_get_basic(iter, &level);
1275         } else if (g_strcmp0(key, "Rates") == 0) {
1276                 supplicant_dbus_array_foreach(iter, bss_rates, bss);
1277         } else if (g_strcmp0(key, "MaxRate") == 0) {
1278                 dbus_uint32_t maxrate = 0;
1279
1280                 dbus_message_iter_get_basic(iter, &maxrate);
1281                 if (maxrate != 0)
1282                         bss->maxrate = maxrate;
1283         } else if (g_strcmp0(key, "Privacy") == 0) {
1284                 dbus_bool_t privacy = FALSE;
1285
1286                 dbus_message_iter_get_basic(iter, &privacy);
1287                 bss->privacy = privacy;
1288         } else if ((g_strcmp0(key, "RSN") == 0) ||
1289                         (g_strcmp0(key, "WPA") == 0)) {
1290                 supplicant_dbus_property_foreach(iter, bss_wpa, bss);
1291
1292                 if (bss->keymgmt &
1293                         (G_SUPPLICANT_KEYMGMT_WPA_EAP |
1294                                 G_SUPPLICANT_KEYMGMT_WPA_FT_EAP |
1295                                 G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
1296                         bss->ieee8021x = TRUE;
1297
1298                 if (bss->keymgmt &
1299                         (G_SUPPLICANT_KEYMGMT_WPA_PSK |
1300                                 G_SUPPLICANT_KEYMGMT_WPA_FT_PSK |
1301                                 G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
1302                         bss->psk = TRUE;
1303         } else if (g_strcmp0(key, "IEs") == 0)
1304                 bss_process_ies(iter, bss);
1305         else
1306                 SUPPLICANT_DBG("key %s type %c",
1307                                 key, dbus_message_iter_get_arg_type(iter));
1308 }
1309
1310 static struct g_supplicant_bss *interface_bss_added(DBusMessageIter *iter,
1311                                                         void *user_data)
1312 {
1313         GSupplicantInterface *interface = user_data;
1314         GSupplicantNetwork *network;
1315         struct g_supplicant_bss *bss;
1316         const char *path = NULL;
1317
1318         SUPPLICANT_DBG("");
1319
1320         dbus_message_iter_get_basic(iter, &path);
1321         if (path == NULL)
1322                 return NULL;
1323
1324         if (g_strcmp0(path, "/") == 0)
1325                 return NULL;
1326
1327         SUPPLICANT_DBG("%s", path);
1328
1329         network = g_hash_table_lookup(interface->bss_mapping, path);
1330         if (network != NULL) {
1331                 bss = g_hash_table_lookup(network->bss_table, path);
1332                 if (bss != NULL)
1333                         return NULL;
1334         }
1335
1336         bss = g_try_new0(struct g_supplicant_bss, 1);
1337         if (bss == NULL)
1338                 return NULL;
1339
1340         bss->interface = interface;
1341         bss->path = g_strdup(path);
1342
1343         return bss;
1344 }
1345
1346 static void interface_bss_added_with_keys(DBusMessageIter *iter,
1347                                                 void *user_data)
1348 {
1349         struct g_supplicant_bss *bss;
1350
1351         SUPPLICANT_DBG("");
1352
1353         bss = interface_bss_added(iter, user_data);
1354         if (bss == NULL)
1355                 return;
1356
1357         dbus_message_iter_next(iter);
1358
1359         if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID)
1360                 return;
1361
1362         supplicant_dbus_property_foreach(iter, bss_property, bss);
1363         bss_property(NULL, NULL, bss);
1364 }
1365
1366 static void interface_bss_added_without_keys(DBusMessageIter *iter,
1367                                                 void *user_data)
1368 {
1369         struct g_supplicant_bss *bss;
1370
1371         SUPPLICANT_DBG("");
1372
1373         bss = interface_bss_added(iter, user_data);
1374         if (bss == NULL)
1375                 return;
1376
1377         supplicant_dbus_property_get_all(bss->path,
1378                                         SUPPLICANT_INTERFACE ".BSS",
1379                                                         bss_property, bss);
1380 }
1381
1382 static void update_signal(gpointer key, gpointer value,
1383                                                 gpointer user_data)
1384 {
1385         struct g_supplicant_bss *bss = value;
1386         GSupplicantNetwork *network = user_data;
1387
1388         if (bss->signal > network->signal) {
1389                 network->signal = bss->signal;
1390                 network->best_bss = bss;
1391         }
1392 }
1393
1394 static void update_network_signal(GSupplicantNetwork *network)
1395 {
1396         if (g_hash_table_size(network->bss_table) <= 1)
1397                 return;
1398
1399         g_hash_table_foreach(network->bss_table,
1400                                 update_signal, network);
1401
1402         SUPPLICANT_DBG("New network signal %d", network->signal);
1403 }
1404
1405 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
1406 {
1407         GSupplicantInterface *interface = user_data;
1408         GSupplicantNetwork *network;
1409         const char *path = NULL;
1410
1411         dbus_message_iter_get_basic(iter, &path);
1412         if (path == NULL)
1413                 return;
1414
1415         network = g_hash_table_lookup(interface->bss_mapping, path);
1416         if (network == NULL)
1417                 return;
1418
1419         g_hash_table_remove(bss_mapping, path);
1420
1421         g_hash_table_remove(interface->bss_mapping, path);
1422         g_hash_table_remove(network->bss_table, path);
1423
1424         update_network_signal(network);
1425
1426         if (g_hash_table_size(network->bss_table) == 0)
1427                 g_hash_table_remove(interface->network_table, network->group);
1428 }
1429
1430 static void interface_property(const char *key, DBusMessageIter *iter,
1431                                                         void *user_data)
1432 {
1433         GSupplicantInterface *interface = user_data;
1434
1435         if (interface == NULL)
1436                 return;
1437
1438         SUPPLICANT_DBG("%s", key);
1439
1440         if (key == NULL) {
1441                 debug_strvalmap("KeyMgmt capability", keymgmt_map,
1442                                                 interface->keymgmt_capa);
1443                 debug_strvalmap("AuthAlg capability", authalg_capa_map,
1444                                                 interface->authalg_capa);
1445                 debug_strvalmap("Protocol capability", proto_capa_map,
1446                                                 interface->proto_capa);
1447                 debug_strvalmap("Pairwise capability", pairwise_map,
1448                                                 interface->pairwise_capa);
1449                 debug_strvalmap("Group capability", group_map,
1450                                                 interface->group_capa);
1451                 debug_strvalmap("Scan capability", scan_capa_map,
1452                                                 interface->scan_capa);
1453                 debug_strvalmap("Mode capability", mode_capa_map,
1454                                                 interface->mode_capa);
1455
1456                 interface->ready = TRUE;
1457                 callback_interface_added(interface);
1458                 return;
1459         }
1460
1461         if (g_strcmp0(key, "Capabilities") == 0) {
1462                 supplicant_dbus_property_foreach(iter, interface_capability,
1463                                                                 interface);
1464         } else if (g_strcmp0(key, "State") == 0) {
1465                 const char *str = NULL;
1466
1467                 dbus_message_iter_get_basic(iter, &str);
1468                 if (str != NULL)
1469                         if (string2state(str) != interface->state) {
1470                                 interface->state = string2state(str);
1471                                 callback_interface_state(interface);
1472                         }
1473
1474                 SUPPLICANT_DBG("state %s (%d)", str, interface->state);
1475         } else if (g_strcmp0(key, "Scanning") == 0) {
1476                 dbus_bool_t scanning = FALSE;
1477
1478                 dbus_message_iter_get_basic(iter, &scanning);
1479                 interface->scanning = scanning;
1480
1481                 if (interface->ready == TRUE) {
1482                         if (interface->scanning == TRUE)
1483                                 callback_scan_started(interface);
1484                         else
1485                                 callback_scan_finished(interface);
1486                 }
1487         } else if (g_strcmp0(key, "ApScan") == 0) {
1488                 int apscan = 1;
1489
1490                 dbus_message_iter_get_basic(iter, &apscan);
1491                 interface->apscan = apscan;
1492         } else if (g_strcmp0(key, "Ifname") == 0) {
1493                 const char *str = NULL;
1494
1495                 dbus_message_iter_get_basic(iter, &str);
1496                 if (str != NULL) {
1497                         g_free(interface->ifname);
1498                         interface->ifname = g_strdup(str);
1499                 }
1500         } else if (g_strcmp0(key, "Driver") == 0) {
1501                 const char *str = NULL;
1502
1503                 dbus_message_iter_get_basic(iter, &str);
1504                 if (str != NULL) {
1505                         g_free(interface->driver);
1506                         interface->driver = g_strdup(str);
1507                 }
1508         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1509                 const char *str = NULL;
1510
1511                 dbus_message_iter_get_basic(iter, &str);
1512                 if (str != NULL) {
1513                         g_free(interface->bridge);
1514                         interface->bridge = g_strdup(str);
1515                 }
1516         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1517                 interface_bss_added_without_keys(iter, interface);
1518         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1519                 interface_network_added(iter, interface);
1520         } else if (g_strcmp0(key, "BSSs") == 0) {
1521                 supplicant_dbus_array_foreach(iter, interface_bss_added_without_keys,
1522                                                                 interface);
1523         } else if (g_strcmp0(key, "Blobs") == 0) {
1524                 /* Nothing */
1525         } else if (g_strcmp0(key, "Networks") == 0) {
1526                 supplicant_dbus_array_foreach(iter, interface_network_added,
1527                                                                 interface);
1528         } else
1529                 SUPPLICANT_DBG("key %s type %c",
1530                                 key, dbus_message_iter_get_arg_type(iter));
1531 }
1532
1533 static void scan_network_update(DBusMessageIter *iter, void *user_data)
1534 {
1535         GSupplicantInterface *interface = user_data;
1536         GSupplicantNetwork *network;
1537         char *path;
1538
1539         if (iter == NULL)
1540                 return;
1541
1542         dbus_message_iter_get_basic(iter, &path);
1543
1544         if (path == NULL)
1545                 return;
1546
1547         if (g_strcmp0(path, "/") == 0)
1548                 return;
1549
1550         /* Update the network details based on scan BSS data */
1551         network = g_hash_table_lookup(interface->bss_mapping, path);
1552         if (network != NULL)
1553                 callback_network_added(network);
1554 }
1555
1556 static void scan_bss_data(const char *key, DBusMessageIter *iter,
1557                                 void *user_data)
1558 {
1559         GSupplicantInterface *interface = user_data;
1560
1561         if (iter)
1562                 supplicant_dbus_array_foreach(iter, scan_network_update,
1563                                                 interface);
1564
1565         if (interface->scan_callback != NULL)
1566                 interface->scan_callback(0, interface, interface->scan_data);
1567
1568         interface->scan_callback = NULL;
1569         interface->scan_data = NULL;
1570 }
1571
1572 static GSupplicantInterface *interface_alloc(const char *path)
1573 {
1574         GSupplicantInterface *interface;
1575
1576         interface = g_try_new0(GSupplicantInterface, 1);
1577         if (interface == NULL)
1578                 return NULL;
1579
1580         interface->path = g_strdup(path);
1581
1582         interface->network_table = g_hash_table_new_full(g_str_hash,
1583                                         g_str_equal, NULL, remove_network);
1584
1585         interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1586                                                                 NULL, NULL);
1587         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1588                                                                 NULL, NULL);
1589
1590         g_hash_table_replace(interface_table, interface->path, interface);
1591
1592         return interface;
1593 }
1594
1595 static void interface_added(DBusMessageIter *iter, void *user_data)
1596 {
1597         GSupplicantInterface *interface;
1598         const char *path = NULL;
1599
1600         SUPPLICANT_DBG("");
1601
1602         dbus_message_iter_get_basic(iter, &path);
1603         if (path == NULL)
1604                 return;
1605
1606         if (g_strcmp0(path, "/") == 0)
1607                 return;
1608
1609         interface = g_hash_table_lookup(interface_table, path);
1610         if (interface != NULL)
1611                 return;
1612
1613         interface = interface_alloc(path);
1614         if (interface == NULL)
1615                 return;
1616
1617         dbus_message_iter_next(iter);
1618         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1619                 supplicant_dbus_property_foreach(iter, interface_property,
1620                                                                 interface);
1621                 interface_property(NULL, NULL, interface);
1622                 return;
1623         }
1624
1625         supplicant_dbus_property_get_all(path,
1626                                         SUPPLICANT_INTERFACE ".Interface",
1627                                                 interface_property, interface);
1628 }
1629
1630 static void interface_removed(DBusMessageIter *iter, void *user_data)
1631 {
1632         const char *path = NULL;
1633
1634         dbus_message_iter_get_basic(iter, &path);
1635         if (path == NULL)
1636                 return;
1637
1638         g_hash_table_remove(interface_table, path);
1639 }
1640
1641 static void eap_method(DBusMessageIter *iter, void *user_data)
1642 {
1643         const char *str = NULL;
1644         int i;
1645
1646         dbus_message_iter_get_basic(iter, &str);
1647         if (str == NULL)
1648                 return;
1649
1650         for (i = 0; eap_method_map[i].str != NULL; i++)
1651                 if (strcmp(str, eap_method_map[i].str) == 0) {
1652                         eap_methods |= eap_method_map[i].val;
1653                         break;
1654                 }
1655 }
1656
1657 static void service_property(const char *key, DBusMessageIter *iter,
1658                                                         void *user_data)
1659 {
1660         if (key == NULL) {
1661                 callback_system_ready();
1662                 return;
1663         }
1664
1665         if (g_strcmp0(key, "DebugLevel") == 0) {
1666                 const char *str = NULL;
1667                 int i;
1668
1669                 dbus_message_iter_get_basic(iter, &str);
1670                 for (i = 0; debug_strings[i] != NULL; i++)
1671                         if (g_strcmp0(debug_strings[i], str) == 0) {
1672                                 debug_level = i;
1673                                 break;
1674                         }
1675                 SUPPLICANT_DBG("Debug level %d", debug_level);
1676         } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
1677                 dbus_message_iter_get_basic(iter, &debug_timestamp);
1678                 SUPPLICANT_DBG("Debug timestamp %u", debug_timestamp);
1679         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1680                 dbus_message_iter_get_basic(iter, &debug_showkeys);
1681                 SUPPLICANT_DBG("Debug show keys %u", debug_showkeys);
1682         } else if (g_strcmp0(key, "Interfaces") == 0) {
1683                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1684         } else if (g_strcmp0(key, "EapMethods") == 0) {
1685                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1686                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1687         } else if (g_strcmp0(key, "Country") == 0) {
1688                 const char *country = NULL;
1689
1690                 dbus_message_iter_get_basic(iter, &country);
1691                 SUPPLICANT_DBG("Country %s", country);
1692         } else
1693                 SUPPLICANT_DBG("key %s type %c",
1694                                 key, dbus_message_iter_get_arg_type(iter));
1695 }
1696
1697 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1698 {
1699         const char *name = NULL, *old = NULL, *new = NULL;
1700
1701         SUPPLICANT_DBG("");
1702
1703         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1704                 return;
1705
1706         dbus_message_iter_get_basic(iter, &name);
1707         if (name == NULL)
1708                 return;
1709
1710         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1711                 return;
1712
1713         dbus_message_iter_next(iter);
1714         dbus_message_iter_get_basic(iter, &old);
1715         dbus_message_iter_next(iter);
1716         dbus_message_iter_get_basic(iter, &new);
1717
1718         if (old == NULL || new == NULL)
1719                 return;
1720
1721         if (strlen(old) > 0 && strlen(new) == 0) {
1722                 system_available = FALSE;
1723                 g_hash_table_remove_all(bss_mapping);
1724                 g_hash_table_remove_all(interface_table);
1725                 callback_system_killed();
1726         }
1727
1728         if (strlen(new) > 0 && strlen(old) == 0) {
1729                 system_available = TRUE;
1730                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1731                                                         SUPPLICANT_INTERFACE,
1732                                                         service_property, NULL);
1733         }
1734 }
1735
1736 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1737 {
1738         SUPPLICANT_DBG("");
1739
1740         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1741                 return;
1742
1743         supplicant_dbus_property_foreach(iter, service_property, NULL);
1744 }
1745
1746 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1747 {
1748         SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
1749
1750         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1751                 interface_added(iter, NULL);
1752 }
1753
1754 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1755 {
1756         SUPPLICANT_DBG("");
1757
1758         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1759                 interface_removed(iter, NULL);
1760 }
1761
1762 static void signal_interface_changed(const char *path, DBusMessageIter *iter)
1763 {
1764         GSupplicantInterface *interface;
1765
1766         SUPPLICANT_DBG("");
1767
1768         interface = g_hash_table_lookup(interface_table, path);
1769         if (interface == NULL)
1770                 return;
1771
1772         supplicant_dbus_property_foreach(iter, interface_property, interface);
1773 }
1774
1775 static void signal_scan_done(const char *path, DBusMessageIter *iter)
1776 {
1777         GSupplicantInterface *interface;
1778         dbus_bool_t success = FALSE;
1779
1780         SUPPLICANT_DBG("");
1781
1782         interface = g_hash_table_lookup(interface_table, path);
1783         if (interface == NULL)
1784                 return;
1785
1786         dbus_message_iter_get_basic(iter, &success);
1787
1788         /*
1789          * If scan is unsuccessful return -EIO else get the scanned BSSs
1790          * and update the network details accordingly
1791          */
1792         if (success == FALSE) {
1793                 if (interface->scan_callback != NULL)
1794                         interface->scan_callback(-EIO, interface,
1795                                                 interface->scan_data);
1796
1797                 interface->scan_callback = NULL;
1798                 interface->scan_data = NULL;
1799
1800                 return;
1801         }
1802
1803         supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface",
1804                                         "BSSs", scan_bss_data, interface);
1805 }
1806
1807 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1808 {
1809         GSupplicantInterface *interface;
1810
1811         SUPPLICANT_DBG("");
1812
1813         interface = g_hash_table_lookup(interface_table, path);
1814         if (interface == NULL)
1815                 return;
1816
1817         interface_bss_added_with_keys(iter, interface);
1818 }
1819
1820 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1821 {
1822         GSupplicantInterface *interface;
1823
1824         SUPPLICANT_DBG("");
1825
1826         interface = g_hash_table_lookup(interface_table, path);
1827         if (interface == NULL)
1828                 return;
1829
1830         interface_bss_removed(iter, interface);
1831 }
1832
1833 static void signal_network_added(const char *path, DBusMessageIter *iter)
1834 {
1835         GSupplicantInterface *interface;
1836
1837         SUPPLICANT_DBG("");
1838
1839         interface = g_hash_table_lookup(interface_table, path);
1840         if (interface == NULL)
1841                 return;
1842
1843         interface_network_added(iter, interface);
1844 }
1845
1846 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1847 {
1848         GSupplicantInterface *interface;
1849
1850         SUPPLICANT_DBG("");
1851
1852         interface = g_hash_table_lookup(interface_table, path);
1853         if (interface == NULL)
1854                 return;
1855
1856         interface_network_removed(iter, interface);
1857 }
1858
1859 static void signal_bss_changed(const char *path, DBusMessageIter *iter)
1860 {
1861         GSupplicantInterface *interface;
1862         GSupplicantNetwork *network;
1863         struct g_supplicant_bss *bss;
1864
1865         SUPPLICANT_DBG("");
1866
1867         interface = g_hash_table_lookup(bss_mapping, path);
1868         if (interface == NULL)
1869                 return;
1870
1871         network = g_hash_table_lookup(interface->bss_mapping, path);
1872         if (network == NULL)
1873                 return;
1874
1875         bss = g_hash_table_lookup(network->bss_table, path);
1876         if (bss == NULL)
1877                 return;
1878
1879         supplicant_dbus_property_foreach(iter, bss_property, bss);
1880
1881         if (bss->signal == network->signal)
1882                 return;
1883
1884         /*
1885          * If the new signal is lower than the SSID signal, we need
1886          * to check for the new maximum.
1887          */
1888         if (bss->signal < network->signal) {
1889                 if (bss != network->best_bss)
1890                         return;
1891                 network->signal = bss->signal;
1892                 update_network_signal(network);
1893         } else {
1894                 network->signal = bss->signal;
1895                 network->best_bss = bss;
1896         }
1897
1898         SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid, network->signal);
1899 }
1900
1901 static void wps_credentials(const char *key, DBusMessageIter *iter,
1902                         void *user_data)
1903 {
1904         GSupplicantInterface *interface = user_data;
1905
1906         if (key == NULL)
1907                 return;
1908
1909         SUPPLICANT_DBG("key %s", key);
1910
1911         if (g_strcmp0(key, "Key") == 0) {
1912                 DBusMessageIter array;
1913                 unsigned char *key;
1914                 int key_len;
1915
1916                 dbus_message_iter_recurse(iter, &array);
1917                 dbus_message_iter_get_fixed_array(&array, &key, &key_len);
1918
1919                 g_free(interface->wps_cred.key);
1920                 interface->wps_cred.key = g_try_malloc0(
1921                                                 sizeof(char) * key_len+1);
1922
1923                 if (interface->wps_cred.key == NULL)
1924                         return;
1925
1926                 memcpy(interface->wps_cred.key, key, sizeof(char) * key_len);
1927
1928                 SUPPLICANT_DBG("WPS key present");
1929         } else if (g_strcmp0(key, "SSID") == 0) {
1930                 DBusMessageIter array;
1931                 unsigned char *ssid;
1932                 int ssid_len;
1933
1934                 dbus_message_iter_recurse(iter, &array);
1935                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
1936
1937                 if (ssid_len > 0 && ssid_len < 33) {
1938                         memcpy(interface->wps_cred.ssid, ssid, ssid_len);
1939                         interface->wps_cred.ssid_len = ssid_len;
1940                 } else {
1941                         memset(interface->wps_cred.ssid, 0, 32);
1942                         interface->wps_cred.ssid_len = 0;
1943                 }
1944         }
1945 }
1946
1947 static void signal_wps_credentials(const char *path, DBusMessageIter *iter)
1948 {
1949         GSupplicantInterface *interface;
1950
1951         SUPPLICANT_DBG("");
1952
1953         interface = g_hash_table_lookup(interface_table, path);
1954         if (interface == NULL)
1955                 return;
1956
1957         supplicant_dbus_property_foreach(iter, wps_credentials, interface);
1958 }
1959
1960 static void wps_event_args(const char *key, DBusMessageIter *iter,
1961                         void *user_data)
1962 {
1963         GSupplicantInterface *interface = user_data;
1964
1965         if (key == NULL || interface == NULL)
1966                 return;
1967
1968         SUPPLICANT_DBG("Arg Key %s", key);
1969 }
1970
1971 static void signal_wps_event(const char *path, DBusMessageIter *iter)
1972 {
1973         GSupplicantInterface *interface;
1974         const char *name = NULL;
1975
1976         SUPPLICANT_DBG("");
1977
1978         interface = g_hash_table_lookup(interface_table, path);
1979         if (interface == NULL)
1980                 return;
1981
1982         dbus_message_iter_get_basic(iter, &name);
1983
1984         SUPPLICANT_DBG("Name: %s", name);
1985
1986         if (g_strcmp0(name, "success") == 0)
1987                 interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
1988         else if (g_strcmp0(name, "failed") == 0)
1989                 interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
1990         else
1991                 interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
1992
1993         if (!dbus_message_iter_has_next(iter))
1994                 return;
1995
1996         dbus_message_iter_next(iter);
1997
1998         supplicant_dbus_property_foreach(iter, wps_event_args, interface);
1999 }
2000
2001 static struct {
2002         const char *interface;
2003         const char *member;
2004         void (*function) (const char *path, DBusMessageIter *iter);
2005 } signal_map[] = {
2006         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
2007
2008         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
2009         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
2010         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
2011         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
2012
2013         { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
2014         { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done         },
2015         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added         },
2016         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed       },
2017         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
2018         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
2019
2020         { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed   },
2021
2022         { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
2023         { SUPPLICANT_INTERFACE ".Interface.WPS", "Event",       signal_wps_event       },
2024
2025         { }
2026 };
2027
2028 static DBusHandlerResult g_supplicant_filter(DBusConnection *conn,
2029                                         DBusMessage *message, void *data)
2030 {
2031         DBusMessageIter iter;
2032         const char *path;
2033         int i;
2034
2035         path = dbus_message_get_path(message);
2036         if (path == NULL)
2037                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2038
2039         if (dbus_message_iter_init(message, &iter) == FALSE)
2040                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2041
2042         for (i = 0; signal_map[i].interface != NULL; i++) {
2043                 if (dbus_message_has_interface(message,
2044                                         signal_map[i].interface) == FALSE)
2045                         continue;
2046
2047                 if (dbus_message_has_member(message,
2048                                         signal_map[i].member) == FALSE)
2049                         continue;
2050
2051                 signal_map[i].function(path, &iter);
2052                 break;
2053         }
2054
2055         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2056 }
2057
2058 struct supplicant_regdom {
2059         GSupplicantCountryCallback callback;
2060         const void *user_data;
2061 };
2062
2063 static void country_result(const char *error,
2064                                 DBusMessageIter *iter, void *user_data)
2065 {
2066         struct supplicant_regdom *regdom = user_data;
2067         char *alpha2;
2068
2069         SUPPLICANT_DBG("Country setting result");
2070
2071         if (user_data == NULL)
2072                 return;
2073
2074         if (error == NULL) {
2075                 alpha2 = (char *)regdom->user_data;
2076         } else {
2077                 SUPPLICANT_DBG("Country setting failure %s", error);
2078                 alpha2 = NULL;
2079         }
2080
2081         if (regdom->callback)
2082                 regdom->callback(alpha2);
2083
2084         g_free(regdom);
2085 }
2086
2087 static void country_params(DBusMessageIter *iter, void *user_data)
2088 {
2089         struct supplicant_regdom *regdom = user_data;
2090         const char *country;
2091
2092         country = regdom->user_data;
2093
2094         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &country);
2095 }
2096
2097 int g_supplicant_set_country(const char *alpha2,
2098                                 GSupplicantCountryCallback callback,
2099                                         const void *user_data)
2100 {
2101         struct supplicant_regdom *regdom;
2102
2103         SUPPLICANT_DBG("Country setting %s", alpha2);
2104
2105         if (system_available == FALSE)
2106                 return -EFAULT;
2107
2108         regdom = dbus_malloc0(sizeof(*regdom));
2109         if (regdom == NULL)
2110                 return -ENOMEM;
2111
2112         regdom->callback = callback;
2113         regdom->user_data = user_data;
2114
2115         return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
2116                                         "Country", DBUS_TYPE_STRING_AS_STRING,
2117                                         country_params, country_result,
2118                                                 regdom);
2119 }
2120
2121 struct interface_data {
2122         GSupplicantInterface *interface;
2123         GSupplicantInterfaceCallback callback;
2124         void *user_data;
2125 };
2126
2127 struct interface_create_data {
2128         const char *ifname;
2129         const char *driver;
2130         const char *bridge;
2131         GSupplicantInterface *interface;
2132         GSupplicantInterfaceCallback callback;
2133         void *user_data;
2134 };
2135
2136 struct interface_connect_data {
2137         GSupplicantInterface *interface;
2138         GSupplicantInterfaceCallback callback;
2139         GSupplicantSSID *ssid;
2140         void *user_data;
2141 };
2142
2143 static void interface_create_property(const char *key, DBusMessageIter *iter,
2144                                                         void *user_data)
2145 {
2146         struct interface_create_data *data = user_data;
2147         GSupplicantInterface *interface = data->interface;
2148
2149         if (key == NULL) {
2150                 if (data->callback != NULL)
2151                         data->callback(0, data->interface, data->user_data);
2152
2153                 dbus_free(data);
2154         }
2155
2156         interface_property(key, iter, interface);
2157 }
2158
2159 static void interface_create_result(const char *error,
2160                                 DBusMessageIter *iter, void *user_data)
2161 {
2162         struct interface_create_data *data = user_data;
2163         const char *path = NULL;
2164         int err;
2165
2166         SUPPLICANT_DBG("");
2167
2168         if (error != NULL) {
2169                 g_critical("error %s", error);
2170                 err = -EIO;
2171                 goto done;
2172         }
2173
2174         dbus_message_iter_get_basic(iter, &path);
2175         if (path == NULL) {
2176                 err = -EINVAL;
2177                 goto done;
2178         }
2179
2180         if (system_available == FALSE) {
2181                 err = -EFAULT;
2182                 goto done;
2183         }
2184
2185         data->interface = g_hash_table_lookup(interface_table, path);
2186         if (data->interface == NULL) {
2187                 data->interface = interface_alloc(path);
2188                 if (data->interface == NULL) {
2189                         err = -ENOMEM;
2190                         goto done;
2191                 }
2192         }
2193
2194         err = supplicant_dbus_property_get_all(path,
2195                                         SUPPLICANT_INTERFACE ".Interface",
2196                                         interface_create_property, data);
2197         if (err == 0)
2198                 return;
2199
2200 done:
2201         if (data->callback != NULL)
2202                 data->callback(err, NULL, data->user_data);
2203
2204         dbus_free(data);
2205 }
2206
2207 static void interface_create_params(DBusMessageIter *iter, void *user_data)
2208 {
2209         struct interface_create_data *data = user_data;
2210         DBusMessageIter dict;
2211
2212         SUPPLICANT_DBG("");
2213
2214         supplicant_dbus_dict_open(iter, &dict);
2215
2216         supplicant_dbus_dict_append_basic(&dict, "Ifname",
2217                                         DBUS_TYPE_STRING, &data->ifname);
2218
2219         if (data->driver != NULL)
2220                 supplicant_dbus_dict_append_basic(&dict, "Driver",
2221                                         DBUS_TYPE_STRING, &data->driver);
2222
2223         if (data->bridge != NULL)
2224                 supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
2225                                         DBUS_TYPE_STRING, &data->bridge);
2226
2227         supplicant_dbus_dict_close(iter, &dict);
2228 }
2229
2230 static void interface_get_result(const char *error,
2231                                 DBusMessageIter *iter, void *user_data)
2232 {
2233         struct interface_create_data *data = user_data;
2234         GSupplicantInterface *interface;
2235         const char *path = NULL;
2236         int err;
2237
2238         SUPPLICANT_DBG("");
2239
2240         if (error != NULL) {
2241                 SUPPLICANT_DBG("Interface not created yet");
2242                 err = -EIO;
2243                 goto create;
2244         }
2245
2246         dbus_message_iter_get_basic(iter, &path);
2247         if (path == NULL) {
2248                 err = -EINVAL;
2249                 goto done;
2250         }
2251
2252         interface = g_hash_table_lookup(interface_table, path);
2253         if (interface == NULL) {
2254                 err = -ENOENT;
2255                 goto done;
2256         }
2257
2258         if (data->callback != NULL)
2259                 data->callback(0, interface, data->user_data);
2260
2261         dbus_free(data);
2262
2263         return;
2264
2265 create:
2266         if (system_available == FALSE) {
2267                 err = -EFAULT;
2268                 goto done;
2269         }
2270
2271         SUPPLICANT_DBG("Creating interface");
2272
2273         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
2274                                                 SUPPLICANT_INTERFACE,
2275                                                 "CreateInterface",
2276                                                 interface_create_params,
2277                                                 interface_create_result, data);
2278         if (err == 0)
2279                 return;
2280
2281 done:
2282         if (data->callback != NULL)
2283                 data->callback(err, NULL, data->user_data);
2284
2285         dbus_free(data);
2286 }
2287
2288 static void interface_get_params(DBusMessageIter *iter, void *user_data)
2289 {
2290         struct interface_create_data *data = user_data;
2291
2292         SUPPLICANT_DBG("");
2293
2294         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
2295 }
2296
2297 int g_supplicant_interface_create(const char *ifname, const char *driver,
2298                                         const char *bridge,
2299                                         GSupplicantInterfaceCallback callback,
2300                                                         void *user_data)
2301 {
2302         struct interface_create_data *data;
2303
2304         SUPPLICANT_DBG("ifname %s", ifname);
2305
2306         if (ifname == NULL)
2307                 return -EINVAL;
2308
2309         if (system_available == FALSE)
2310                 return -EFAULT;
2311
2312         data = dbus_malloc0(sizeof(*data));
2313         if (data == NULL)
2314                 return -ENOMEM;
2315
2316         data->ifname = ifname;
2317         data->driver = driver;
2318         data->bridge = bridge;
2319         data->callback = callback;
2320         data->user_data = user_data;
2321
2322         return supplicant_dbus_method_call(SUPPLICANT_PATH,
2323                                                 SUPPLICANT_INTERFACE,
2324                                                 "GetInterface",
2325                                                 interface_get_params,
2326                                                 interface_get_result, data);
2327 }
2328
2329 static void interface_remove_result(const char *error,
2330                                 DBusMessageIter *iter, void *user_data)
2331 {
2332         struct interface_data *data = user_data;
2333         int err;
2334
2335         if (error != NULL) {
2336                 err = -EIO;
2337                 goto done;
2338         }
2339
2340         if (system_available == FALSE) {
2341                 err = -EFAULT;
2342                 goto done;
2343         }
2344
2345         /*
2346          * The gsupplicant interface is already freed by the InterfaceRemoved
2347          * signal callback. Simply invoke the interface_data callback.
2348          */
2349         err = 0;
2350
2351 done:
2352         if (data->callback != NULL)
2353                 data->callback(err, NULL, data->user_data);
2354
2355         dbus_free(data);
2356 }
2357
2358
2359 static void interface_remove_params(DBusMessageIter *iter, void *user_data)
2360 {
2361         struct interface_data *data = user_data;
2362
2363         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2364                                                         &data->interface->path);
2365 }
2366
2367
2368 int g_supplicant_interface_remove(GSupplicantInterface *interface,
2369                         GSupplicantInterfaceCallback callback,
2370                                                         void *user_data)
2371 {
2372         struct interface_data *data;
2373
2374         if (interface == NULL)
2375                 return -EINVAL;
2376
2377         if (system_available == FALSE)
2378                 return -EFAULT;
2379
2380         data = dbus_malloc0(sizeof(*data));
2381         if (data == NULL)
2382                 return -ENOMEM;
2383
2384         data->interface = interface;
2385         data->callback = callback;
2386         data->user_data = user_data;
2387
2388         return supplicant_dbus_method_call(SUPPLICANT_PATH,
2389                                                 SUPPLICANT_INTERFACE,
2390                                                 "RemoveInterface",
2391                                                 interface_remove_params,
2392                                                 interface_remove_result, data);
2393 }
2394
2395 static void interface_scan_result(const char *error,
2396                                 DBusMessageIter *iter, void *user_data)
2397 {
2398         struct interface_data *data = user_data;
2399
2400         if (error != NULL) {
2401                 if (data->callback != NULL)
2402                         data->callback(-EIO, data->interface, data->user_data);
2403         } else {
2404                 data->interface->scan_callback = data->callback;
2405                 data->interface->scan_data = data->user_data;
2406         }
2407
2408         dbus_free(data);
2409 }
2410
2411 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
2412 {
2413         DBusMessageIter dict;
2414         const char *type = "passive";
2415
2416         supplicant_dbus_dict_open(iter, &dict);
2417
2418         supplicant_dbus_dict_append_basic(&dict, "Type",
2419                                                 DBUS_TYPE_STRING, &type);
2420
2421         supplicant_dbus_dict_close(iter, &dict);
2422 }
2423
2424 int g_supplicant_interface_scan(GSupplicantInterface *interface,
2425                                 GSupplicantInterfaceCallback callback,
2426                                                         void *user_data)
2427 {
2428         struct interface_data *data;
2429
2430         if (interface == NULL)
2431                 return -EINVAL;
2432
2433         if (system_available == FALSE)
2434                 return -EFAULT;
2435
2436         if (interface->scanning == TRUE)
2437                 return -EALREADY;
2438
2439         switch (interface->state) {
2440         case G_SUPPLICANT_STATE_AUTHENTICATING:
2441         case G_SUPPLICANT_STATE_ASSOCIATING:
2442         case G_SUPPLICANT_STATE_ASSOCIATED:
2443         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2444         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2445                 return -EBUSY;
2446         case G_SUPPLICANT_STATE_UNKNOWN:
2447         case G_SUPPLICANT_STATE_DISCONNECTED:
2448         case G_SUPPLICANT_STATE_INACTIVE:
2449         case G_SUPPLICANT_STATE_SCANNING:
2450         case G_SUPPLICANT_STATE_COMPLETED:
2451                 break;
2452         }
2453
2454         data = dbus_malloc0(sizeof(*data));
2455         if (data == NULL)
2456                 return -ENOMEM;
2457
2458         data->interface = interface;
2459         data->callback = callback;
2460         data->user_data = user_data;
2461
2462         return supplicant_dbus_method_call(interface->path,
2463                         SUPPLICANT_INTERFACE ".Interface", "Scan",
2464                         interface_scan_params, interface_scan_result, data);
2465 }
2466
2467 static int parse_supplicant_error(DBusMessageIter *iter)
2468 {
2469         int err = -ECANCELED;
2470         char *key;
2471
2472         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
2473                 dbus_message_iter_get_basic(iter, &key);
2474                 if (strncmp(key, "psk", 4) == 0 ||
2475                         strncmp(key, "wep_key", 7) == 0) {
2476                         err = -ENOKEY;
2477                         break;
2478                 }
2479                 dbus_message_iter_next(iter);
2480         }
2481
2482         return err;
2483 }
2484
2485 static void interface_select_network_result(const char *error,
2486                                 DBusMessageIter *iter, void *user_data)
2487 {
2488         struct interface_connect_data *data = user_data;
2489         int err;
2490
2491         SUPPLICANT_DBG("");
2492
2493         err = 0;
2494         if (error != NULL) {
2495                 SUPPLICANT_DBG("SelectNetwork error %s", error);
2496                 err = parse_supplicant_error(iter);
2497         }
2498
2499         if (data->callback != NULL)
2500                 data->callback(err, data->interface, data->user_data);
2501
2502         g_free(data->ssid);
2503         dbus_free(data);
2504 }
2505
2506 static void interface_select_network_params(DBusMessageIter *iter,
2507                                                         void *user_data)
2508 {
2509         struct interface_connect_data *data = user_data;
2510         GSupplicantInterface *interface = data->interface;
2511
2512         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2513                                         &interface->network_path);
2514 }
2515
2516 static void interface_add_network_result(const char *error,
2517                                 DBusMessageIter *iter, void *user_data)
2518 {
2519         struct interface_connect_data *data = user_data;
2520         GSupplicantInterface *interface = data->interface;
2521         const char *path;
2522         int err;
2523
2524         if (error != NULL)
2525                 goto error;
2526
2527         dbus_message_iter_get_basic(iter, &path);
2528         if (path == NULL)
2529                 goto error;
2530
2531         SUPPLICANT_DBG("PATH: %s", path);
2532
2533         g_free(interface->network_path);
2534         interface->network_path = g_strdup(path);
2535
2536         supplicant_dbus_method_call(data->interface->path,
2537                         SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
2538                         interface_select_network_params,
2539                         interface_select_network_result, data);
2540
2541         return;
2542
2543 error:
2544         SUPPLICANT_DBG("AddNetwork error %s", error);
2545         err = parse_supplicant_error(iter);
2546         if (data->callback != NULL)
2547                 data->callback(err, data->interface, data->user_data);
2548
2549         g_free(interface->network_path);
2550         interface->network_path = NULL;
2551         g_free(data->ssid);
2552         g_free(data);
2553 }
2554
2555 static void add_network_security_wep(DBusMessageIter *dict,
2556                                         GSupplicantSSID *ssid)
2557 {
2558         const char *auth_alg = "OPEN SHARED";
2559         const char *key_index = "0";
2560
2561         supplicant_dbus_dict_append_basic(dict, "auth_alg",
2562                                         DBUS_TYPE_STRING, &auth_alg);
2563
2564         if (ssid->passphrase) {
2565                 int size = strlen(ssid->passphrase);
2566                 if (size == 10 || size == 26) {
2567                         unsigned char *key = g_try_malloc(13);
2568                         char tmp[3];
2569                         int i;
2570
2571                         memset(tmp, 0, sizeof(tmp));
2572                         if (key == NULL)
2573                                 size = 0;
2574
2575                         for (i = 0; i < size / 2; i++) {
2576                                 memcpy(tmp, ssid->passphrase + (i * 2), 2);
2577                                 key[i] = (unsigned char) strtol(tmp, NULL, 16);
2578                         }
2579
2580                         supplicant_dbus_dict_append_fixed_array(dict,
2581                                                         "wep_key0",
2582                                                         DBUS_TYPE_BYTE,
2583                                                         &key, size / 2);
2584                         g_free(key);
2585                 } else if (size == 5 || size == 13) {
2586                         unsigned char *key = g_try_malloc(13);
2587                         int i;
2588
2589                         if (key == NULL)
2590                                 size = 0;
2591
2592                         for (i = 0; i < size; i++)
2593                                 key[i] = (unsigned char) ssid->passphrase[i];
2594
2595                         supplicant_dbus_dict_append_fixed_array(dict,
2596                                                                 "wep_key0",
2597                                                                 DBUS_TYPE_BYTE,
2598                                                                 &key, size);
2599                         g_free(key);
2600                 } else
2601                         supplicant_dbus_dict_append_basic(dict,
2602                                                         "wep_key0",
2603                                                         DBUS_TYPE_STRING,
2604                                                         &ssid->passphrase);
2605
2606                 supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx",
2607                                         DBUS_TYPE_STRING, &key_index);
2608         }
2609 }
2610
2611 static dbus_bool_t is_psk_raw_key(const char *psk)
2612 {
2613         int i;
2614
2615         /* A raw key is always 64 bytes length... */
2616         if (strlen(psk) != 64)
2617                 return FALSE;
2618
2619         /* ... and its content is in hex representation */
2620         for (i = 0; i < 64; i++)
2621                 if (!isxdigit((unsigned char) psk[i]))
2622                         return FALSE;
2623
2624         return TRUE;
2625 }
2626
2627 static void add_network_security_psk(DBusMessageIter *dict,
2628                                         GSupplicantSSID *ssid)
2629 {
2630         if (ssid->passphrase && strlen(ssid->passphrase) > 0) {
2631
2632                 if (is_psk_raw_key(ssid->passphrase) == TRUE)
2633                         supplicant_dbus_property_append_fixed_array(dict,
2634                                                         "psk", DBUS_TYPE_BYTE,
2635                                                         &ssid->passphrase, 64);
2636                 else
2637                         supplicant_dbus_dict_append_basic(dict, "psk",
2638                                                         DBUS_TYPE_STRING,
2639                                                         &ssid->passphrase);
2640         }
2641 }
2642
2643 static void add_network_security_tls(DBusMessageIter *dict,
2644                                         GSupplicantSSID *ssid)
2645 {
2646         /*
2647          * For TLS, we at least need:
2648          *              The client certificate
2649          *              The client private key file
2650          *              The client private key file password
2651          *
2652          * The Authority certificate is optional.
2653          */
2654         if (ssid->client_cert_path == NULL)
2655                 return;
2656
2657         if (ssid->private_key_path == NULL)
2658                 return;
2659
2660         if (ssid->private_key_passphrase == NULL)
2661                 return;
2662
2663         if (ssid->ca_cert_path)
2664                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
2665                                         DBUS_TYPE_STRING, &ssid->ca_cert_path);
2666
2667         supplicant_dbus_dict_append_basic(dict, "private_key",
2668                                                 DBUS_TYPE_STRING,
2669                                                 &ssid->private_key_path);
2670         supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
2671                                                 DBUS_TYPE_STRING,
2672                                                 &ssid->private_key_passphrase);
2673         supplicant_dbus_dict_append_basic(dict, "client_cert",
2674                                                 DBUS_TYPE_STRING,
2675                                                 &ssid->client_cert_path);
2676 }
2677
2678 static void add_network_security_peap(DBusMessageIter *dict,
2679                                         GSupplicantSSID *ssid)
2680 {
2681         char *phase2_auth;
2682
2683         /*
2684          * For PEAP/TTLS, we at least need
2685          *              The authority certificate
2686          *              The 2nd phase authentication method
2687          *              The 2nd phase passphrase
2688          *
2689          * The Client certificate is optional although strongly recommended
2690          * When setting it, we need in addition
2691          *              The Client private key file
2692          *              The Client private key file password
2693          */
2694         if (ssid->passphrase == NULL)
2695                 return;
2696
2697         if (ssid->phase2_auth == NULL)
2698                 return;
2699
2700         if (ssid->client_cert_path) {
2701                 if (ssid->private_key_path == NULL)
2702                         return;
2703
2704                 if (ssid->private_key_passphrase == NULL)
2705                         return;
2706
2707                 supplicant_dbus_dict_append_basic(dict, "client_cert",
2708                                                 DBUS_TYPE_STRING,
2709                                                 &ssid->client_cert_path);
2710
2711                 supplicant_dbus_dict_append_basic(dict, "private_key",
2712                                                 DBUS_TYPE_STRING,
2713                                                 &ssid->private_key_path);
2714
2715                 supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
2716                                                 DBUS_TYPE_STRING,
2717                                                 &ssid->private_key_passphrase);
2718
2719         }
2720
2721         if (g_str_has_prefix(ssid->phase2_auth, "EAP-") == TRUE) {
2722                 phase2_auth = g_strdup_printf("autheap=%s",
2723                                         ssid->phase2_auth + strlen("EAP-"));
2724         } else
2725                 phase2_auth = g_strdup_printf("auth=%s", ssid->phase2_auth);
2726
2727         supplicant_dbus_dict_append_basic(dict, "password",
2728                                                 DBUS_TYPE_STRING,
2729                                                 &ssid->passphrase);
2730
2731         if (ssid->ca_cert_path)
2732                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
2733                                                 DBUS_TYPE_STRING,
2734                                                 &ssid->ca_cert_path);
2735
2736         supplicant_dbus_dict_append_basic(dict, "phase2",
2737                                                 DBUS_TYPE_STRING,
2738                                                 &phase2_auth);
2739
2740         g_free(phase2_auth);
2741 }
2742
2743 static void add_network_security_eap(DBusMessageIter *dict,
2744                                         GSupplicantSSID *ssid)
2745 {
2746         char *eap_value;
2747
2748         if (ssid->eap == NULL || ssid->identity == NULL)
2749                 return;
2750
2751         if (g_strcmp0(ssid->eap, "tls") == 0) {
2752                 add_network_security_tls(dict, ssid);
2753         } else if (g_strcmp0(ssid->eap, "peap") == 0 ||
2754                                 g_strcmp0(ssid->eap, "ttls") == 0) {
2755                 add_network_security_peap(dict, ssid);
2756         } else
2757                 return;
2758
2759         eap_value = g_ascii_strup(ssid->eap, -1);
2760
2761         supplicant_dbus_dict_append_basic(dict, "eap",
2762                                                 DBUS_TYPE_STRING,
2763                                                 &eap_value);
2764         supplicant_dbus_dict_append_basic(dict, "identity",
2765                                                 DBUS_TYPE_STRING,
2766                                                 &ssid->identity);
2767
2768         g_free(eap_value);
2769 }
2770
2771 static void add_network_security_ciphers(DBusMessageIter *dict,
2772                                                 GSupplicantSSID *ssid)
2773 {
2774         unsigned int p_cipher, g_cipher, i;
2775         char *pairwise, *group;
2776         char *pair_ciphers[4];
2777         char *group_ciphers[5];
2778
2779         p_cipher = ssid->pairwise_cipher;
2780         g_cipher = ssid->group_cipher;
2781
2782         if (p_cipher == 0 && g_cipher == 0)
2783                 return;
2784
2785         i = 0;
2786
2787         if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP)
2788                 pair_ciphers[i++] = "CCMP";
2789
2790         if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP)
2791                 pair_ciphers[i++] = "TKIP";
2792
2793         if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE)
2794                 pair_ciphers[i++] = "NONE";
2795
2796         pair_ciphers[i] = NULL;
2797
2798         i = 0;
2799
2800         if (g_cipher & G_SUPPLICANT_GROUP_CCMP)
2801                 group_ciphers[i++] = "CCMP";
2802
2803         if (g_cipher & G_SUPPLICANT_GROUP_TKIP)
2804                 group_ciphers[i++] = "TKIP";
2805
2806         if (g_cipher & G_SUPPLICANT_GROUP_WEP104)
2807                 group_ciphers[i++] = "WEP104";
2808
2809         if (g_cipher & G_SUPPLICANT_GROUP_WEP40)
2810                 group_ciphers[i++] = "WEP40";
2811
2812         group_ciphers[i] = NULL;
2813
2814         pairwise = g_strjoinv(" ", pair_ciphers);
2815         group = g_strjoinv(" ", group_ciphers);
2816
2817         SUPPLICANT_DBG("cipher %s %s", pairwise, group);
2818
2819         supplicant_dbus_dict_append_basic(dict, "pairwise",
2820                                                 DBUS_TYPE_STRING,
2821                                                 &pairwise);
2822         supplicant_dbus_dict_append_basic(dict, "group",
2823                                                 DBUS_TYPE_STRING,
2824                                                 &group);
2825
2826         g_free(pairwise);
2827         g_free(group);
2828 }
2829
2830 static void add_network_security_proto(DBusMessageIter *dict,
2831                                                 GSupplicantSSID *ssid)
2832 {
2833         unsigned int protocol, i;
2834         char *proto;
2835         char *protos[3];
2836
2837         protocol = ssid->protocol;
2838
2839         if (protocol == 0)
2840                 return;
2841
2842         i = 0;
2843
2844         if (protocol & G_SUPPLICANT_PROTO_RSN)
2845                 protos[i++] = "RSN";
2846
2847         if (protocol & G_SUPPLICANT_PROTO_WPA)
2848                 protos[i++] = "WPA";
2849
2850         protos[i] = NULL;
2851
2852         proto = g_strjoinv(" ", protos);
2853
2854         SUPPLICANT_DBG("proto %s", proto);
2855
2856         supplicant_dbus_dict_append_basic(dict, "proto",
2857                                                 DBUS_TYPE_STRING,
2858                                                 &proto);
2859
2860         g_free(proto);
2861 }
2862
2863 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
2864 {
2865         char *key_mgmt;
2866
2867         switch (ssid->security) {
2868         case G_SUPPLICANT_SECURITY_UNKNOWN:
2869         case G_SUPPLICANT_SECURITY_NONE:
2870         case G_SUPPLICANT_SECURITY_WEP:
2871                 key_mgmt = "NONE";
2872                 add_network_security_wep(dict, ssid);
2873                 add_network_security_ciphers(dict, ssid);
2874                 break;
2875         case G_SUPPLICANT_SECURITY_PSK:
2876                 key_mgmt = "WPA-PSK";
2877                 add_network_security_psk(dict, ssid);
2878                 add_network_security_ciphers(dict, ssid);
2879                 add_network_security_proto(dict, ssid);
2880                 break;
2881         case G_SUPPLICANT_SECURITY_IEEE8021X:
2882                 key_mgmt = "WPA-EAP";
2883                 add_network_security_eap(dict, ssid);
2884                 add_network_security_ciphers(dict, ssid);
2885                 add_network_security_proto(dict, ssid);
2886                 break;
2887         }
2888
2889         supplicant_dbus_dict_append_basic(dict, "key_mgmt",
2890                                 DBUS_TYPE_STRING, &key_mgmt);
2891 }
2892
2893 static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid)
2894 {
2895         dbus_uint32_t mode;
2896
2897         switch (ssid->mode) {
2898         case G_SUPPLICANT_MODE_UNKNOWN:
2899         case G_SUPPLICANT_MODE_INFRA:
2900                 mode = 0;
2901                 break;
2902         case G_SUPPLICANT_MODE_IBSS:
2903                 mode = 1;
2904                 break;
2905         case G_SUPPLICANT_MODE_MASTER:
2906                 mode = 2;
2907                 break;
2908         }
2909
2910         supplicant_dbus_dict_append_basic(dict, "mode",
2911                                 DBUS_TYPE_UINT32, &mode);
2912 }
2913
2914 static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
2915 {
2916         DBusMessageIter dict;
2917         struct interface_connect_data *data = user_data;
2918         GSupplicantSSID *ssid = data->ssid;
2919
2920         supplicant_dbus_dict_open(iter, &dict);
2921
2922         if (ssid->scan_ssid)
2923                 supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
2924                                          DBUS_TYPE_UINT32, &ssid->scan_ssid);
2925
2926         if (ssid->freq)
2927                 supplicant_dbus_dict_append_basic(&dict, "frequency",
2928                                          DBUS_TYPE_UINT32, &ssid->freq);
2929
2930         add_network_mode(&dict, ssid);
2931
2932         add_network_security(&dict, ssid);
2933
2934         supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
2935                                         DBUS_TYPE_BYTE, &ssid->ssid,
2936                                                 ssid->ssid_len);
2937
2938         supplicant_dbus_dict_close(iter, &dict);
2939 }
2940
2941 static void interface_wps_start_result(const char *error,
2942                                 DBusMessageIter *iter, void *user_data)
2943 {
2944         struct interface_connect_data *data = user_data;
2945
2946         SUPPLICANT_DBG("");
2947         if (error != NULL)
2948                 SUPPLICANT_DBG("error: %s", error);
2949
2950         g_free(data->ssid);
2951         dbus_free(data);
2952 }
2953
2954 static void interface_add_wps_params(DBusMessageIter *iter, void *user_data)
2955 {
2956         struct interface_connect_data *data = user_data;
2957         GSupplicantSSID *ssid = data->ssid;
2958         const char *role = "enrollee", *type;
2959         DBusMessageIter dict;
2960
2961         SUPPLICANT_DBG("");
2962
2963         supplicant_dbus_dict_open(iter, &dict);
2964
2965         supplicant_dbus_dict_append_basic(&dict, "Role",
2966                                                 DBUS_TYPE_STRING, &role);
2967
2968         type = "pbc";
2969         if (ssid->pin_wps != NULL) {
2970                 type = "pin";
2971                 supplicant_dbus_dict_append_basic(&dict, "Pin",
2972                                         DBUS_TYPE_STRING, &ssid->pin_wps);
2973         }
2974
2975         supplicant_dbus_dict_append_basic(&dict, "Type",
2976                                         DBUS_TYPE_STRING, &type);
2977
2978         supplicant_dbus_dict_close(iter, &dict);
2979 }
2980
2981 static void wps_start(const char *error, DBusMessageIter *iter, void *user_data)
2982 {
2983         struct interface_connect_data *data = user_data;
2984
2985         SUPPLICANT_DBG("");
2986
2987         if (error != NULL) {
2988                 SUPPLICANT_DBG("error: %s", error);
2989                 g_free(data->ssid);
2990                 dbus_free(data);
2991                 return;
2992         }
2993
2994         supplicant_dbus_method_call(data->interface->path,
2995                         SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
2996                         interface_add_wps_params,
2997                         interface_wps_start_result, data);
2998 }
2999
3000 static void wps_process_credentials(DBusMessageIter *iter, void *user_data)
3001 {
3002         dbus_bool_t credentials = TRUE;
3003
3004         SUPPLICANT_DBG("");
3005
3006         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials);
3007 }
3008
3009
3010 int g_supplicant_interface_connect(GSupplicantInterface *interface,
3011                                 GSupplicantSSID *ssid,
3012                                 GSupplicantInterfaceCallback callback,
3013                                                         void *user_data)
3014 {
3015         struct interface_connect_data *data;
3016         int ret;
3017
3018         if (interface == NULL)
3019                 return -EINVAL;
3020
3021         if (system_available == FALSE)
3022                 return -EFAULT;
3023
3024         /* TODO: Check if we're already connected and switch */
3025
3026         data = dbus_malloc0(sizeof(*data));
3027         if (data == NULL)
3028                 return -ENOMEM;
3029
3030         data->interface = interface;
3031         data->callback = callback;
3032         data->ssid = ssid;
3033         data->user_data = user_data;
3034
3035         if (ssid->use_wps == TRUE) {
3036                 g_free(interface->wps_cred.key);
3037                 memset(&interface->wps_cred, 0,
3038                                 sizeof(struct _GSupplicantWpsCredentials));
3039
3040                 ret = supplicant_dbus_property_set(interface->path,
3041                         SUPPLICANT_INTERFACE ".Interface.WPS",
3042                         "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
3043                         wps_process_credentials, wps_start, data);
3044         } else
3045                 ret = supplicant_dbus_method_call(interface->path,
3046                         SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
3047                         interface_add_network_params,
3048                         interface_add_network_result, data);
3049
3050         if (ret < 0)
3051                 return ret;
3052
3053         return -EINPROGRESS;
3054 }
3055
3056 static void network_remove_result(const char *error,
3057                                 DBusMessageIter *iter, void *user_data)
3058 {
3059         struct interface_data *data = user_data;
3060         int result = 0;
3061
3062         SUPPLICANT_DBG("");
3063
3064         if (error != NULL)
3065                 result = -EIO;
3066
3067         if (data->callback != NULL)
3068                 data->callback(result, data->interface, data->user_data);
3069
3070         dbus_free(data);
3071 }
3072
3073 static void network_remove_params(DBusMessageIter *iter, void *user_data)
3074 {
3075         struct interface_data *data = user_data;
3076         const char *path = data->interface->network_path;
3077
3078         SUPPLICANT_DBG("path %s", path);
3079
3080         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
3081 }
3082
3083 static int network_remove(struct interface_data *data)
3084 {
3085         GSupplicantInterface *interface = data->interface;
3086
3087         SUPPLICANT_DBG("");
3088
3089         return supplicant_dbus_method_call(interface->path,
3090                         SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
3091                         network_remove_params, network_remove_result, data);
3092 }
3093
3094 static void interface_disconnect_result(const char *error,
3095                                 DBusMessageIter *iter, void *user_data)
3096 {
3097         struct interface_data *data = user_data;
3098
3099         SUPPLICANT_DBG("");
3100
3101         if (error != NULL && data->callback != NULL)
3102                 data->callback(-EIO, data->interface, data->user_data);
3103
3104         /* If we are disconnecting from previous WPS successful
3105          * association. i.e.: it did not went through AddNetwork,
3106          * and interface->network_path was never set. */
3107         if (data->interface->network_path == NULL)
3108                 return;
3109
3110         network_remove(data);
3111 }
3112
3113 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
3114                                         GSupplicantInterfaceCallback callback,
3115                                                         void *user_data)
3116 {
3117         struct interface_data *data;
3118
3119         SUPPLICANT_DBG("");
3120
3121         if (interface == NULL)
3122                 return -EINVAL;
3123
3124         if (system_available == FALSE)
3125                 return -EFAULT;
3126
3127         data = dbus_malloc0(sizeof(*data));
3128         if (data == NULL)
3129                 return -ENOMEM;
3130
3131         data->interface = interface;
3132         data->callback = callback;
3133         data->user_data = user_data;
3134
3135         return supplicant_dbus_method_call(interface->path,
3136                         SUPPLICANT_INTERFACE ".Interface", "Disconnect",
3137                                 NULL, interface_disconnect_result, data);
3138 }
3139
3140
3141 static const char *g_supplicant_rule0 = "type=signal,"
3142                                         "path=" DBUS_PATH_DBUS ","
3143                                         "sender=" DBUS_SERVICE_DBUS ","
3144                                         "interface=" DBUS_INTERFACE_DBUS ","
3145                                         "member=NameOwnerChanged,"
3146                                         "arg0=" SUPPLICANT_SERVICE;
3147 static const char *g_supplicant_rule1 = "type=signal,"
3148                         "interface=" SUPPLICANT_INTERFACE;
3149 static const char *g_supplicant_rule2 = "type=signal,"
3150                         "interface=" SUPPLICANT_INTERFACE ".Interface";
3151 static const char *g_supplicant_rule3 = "type=signal,"
3152                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
3153 static const char *g_supplicant_rule4 = "type=signal,"
3154                         "interface=" SUPPLICANT_INTERFACE ".BSS";
3155 static const char *g_supplicant_rule5 = "type=signal,"
3156                         "interface=" SUPPLICANT_INTERFACE ".Network";
3157
3158 static void invoke_introspect_method(void)
3159 {
3160         DBusMessage *message;
3161
3162         message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
3163                                         SUPPLICANT_PATH,
3164                                         DBUS_INTERFACE_INTROSPECTABLE,
3165                                         "Introspect");
3166
3167         if (message == NULL)
3168                 return;
3169
3170         dbus_message_set_no_reply(message, TRUE);
3171         dbus_connection_send(connection, message, NULL);
3172         dbus_message_unref(message);
3173 }
3174
3175 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
3176 {
3177         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
3178         if (connection == NULL)
3179                 return -EIO;
3180
3181         if (dbus_connection_add_filter(connection,
3182                                 g_supplicant_filter, NULL, NULL) == FALSE) {
3183                 dbus_connection_unref(connection);
3184                 connection = NULL;
3185                 return -EIO;
3186         }
3187
3188         callbacks_pointer = callbacks;
3189         eap_methods = 0;
3190
3191         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
3192                                                 NULL, remove_interface);
3193
3194         bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
3195                                                                 NULL, NULL);
3196
3197         supplicant_dbus_setup(connection);
3198
3199         dbus_bus_add_match(connection, g_supplicant_rule0, NULL);
3200         dbus_bus_add_match(connection, g_supplicant_rule1, NULL);
3201         dbus_bus_add_match(connection, g_supplicant_rule2, NULL);
3202         dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
3203         dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
3204         dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
3205         dbus_connection_flush(connection);
3206
3207         if (dbus_bus_name_has_owner(connection,
3208                                         SUPPLICANT_SERVICE, NULL) == TRUE) {
3209                 system_available = TRUE;
3210                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
3211                                                 SUPPLICANT_INTERFACE,
3212                                                 service_property, NULL);
3213         } else
3214                 invoke_introspect_method();
3215
3216         return 0;
3217 }
3218
3219 static void unregister_interface_remove_params(DBusMessageIter *iter,
3220                                                 void *user_data)
3221 {
3222         const char *path = user_data;
3223
3224         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
3225                                                         &path);
3226 }
3227
3228
3229 static void unregister_remove_interface(gpointer key, gpointer value,
3230                                                 gpointer user_data)
3231 {
3232         GSupplicantInterface *interface = value;
3233
3234         supplicant_dbus_method_call(SUPPLICANT_PATH,
3235                                         SUPPLICANT_INTERFACE,
3236                                         "RemoveInterface",
3237                                         unregister_interface_remove_params,
3238                                                 NULL, interface->path);
3239 }
3240
3241 void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
3242 {
3243         SUPPLICANT_DBG("");
3244
3245         if (connection != NULL) {
3246                 dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
3247                 dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
3248                 dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);
3249                 dbus_bus_remove_match(connection, g_supplicant_rule2, NULL);
3250                 dbus_bus_remove_match(connection, g_supplicant_rule1, NULL);
3251                 dbus_bus_remove_match(connection, g_supplicant_rule0, NULL);
3252                 dbus_connection_flush(connection);
3253
3254                 dbus_connection_remove_filter(connection,
3255                                                 g_supplicant_filter, NULL);
3256         }
3257
3258         if (bss_mapping != NULL) {
3259                 g_hash_table_destroy(bss_mapping);
3260                 bss_mapping = NULL;
3261         }
3262
3263         if (system_available == TRUE)
3264                 callback_system_killed();
3265
3266         if (interface_table != NULL) {
3267                 g_hash_table_foreach(interface_table,   
3268                                         unregister_remove_interface, NULL);
3269                 g_hash_table_destroy(interface_table);
3270                 interface_table = NULL;
3271         }
3272
3273         if (connection != NULL) {
3274                 dbus_connection_unref(connection);
3275                 connection = NULL;
3276         }
3277
3278         callbacks_pointer = NULL;
3279         eap_methods = 0;
3280 }