Update copyright information
[framework/connectivity/connman.git] / tools / supplicant.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-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 <string.h>
28 #include <stdint.h>
29 #include <syslog.h>
30
31 #include <glib.h>
32 #include <gdbus.h>
33
34 #include "supplicant-dbus.h"
35 #include "supplicant.h"
36
37 #define DBG(fmt, arg...) do { \
38         syslog(LOG_DEBUG, "%s() " fmt, __FUNCTION__ , ## arg); \
39 } while (0)
40
41 #define TIMEOUT 5000
42
43 #define IEEE80211_CAP_ESS       0x0001
44 #define IEEE80211_CAP_IBSS      0x0002
45 #define IEEE80211_CAP_PRIVACY   0x0010
46
47 static DBusConnection *connection;
48
49 static const struct supplicant_callbacks *callbacks_pointer;
50
51 static dbus_bool_t system_available = FALSE;
52 static dbus_bool_t system_ready = FALSE;
53
54 static dbus_int32_t debug_level = 0;
55 static dbus_bool_t debug_timestamp = FALSE;
56 static dbus_bool_t debug_showkeys = FALSE;
57
58 static unsigned int eap_methods;
59
60 struct strvalmap {
61         const char *str;
62         unsigned int val;
63 };
64
65 static struct strvalmap eap_method_map[] = {
66         { "MD5",        SUPPLICANT_EAP_METHOD_MD5       },
67         { "TLS",        SUPPLICANT_EAP_METHOD_TLS       },
68         { "MSCHAPV2",   SUPPLICANT_EAP_METHOD_MSCHAPV2  },
69         { "PEAP",       SUPPLICANT_EAP_METHOD_PEAP      },
70         { "TTLS",       SUPPLICANT_EAP_METHOD_TTLS      },
71         { "GTC",        SUPPLICANT_EAP_METHOD_GTC       },
72         { "OTP",        SUPPLICANT_EAP_METHOD_OTP       },
73         { "LEAP",       SUPPLICANT_EAP_METHOD_LEAP      },
74         { "WSC",        SUPPLICANT_EAP_METHOD_WSC       },
75         { }
76 };
77
78 static struct strvalmap keymgmt_capa_map[] = {
79         { "none",       SUPPLICANT_CAPABILITY_KEYMGMT_NONE      },
80         { "ieee8021x",  SUPPLICANT_CAPABILITY_KEYMGMT_IEEE8021X },
81         { "wpa-none",   SUPPLICANT_CAPABILITY_KEYMGMT_WPA_NONE  },
82         { "wpa-psk",    SUPPLICANT_CAPABILITY_KEYMGMT_WPA_PSK   },
83         { "wpa-eap",    SUPPLICANT_CAPABILITY_KEYMGMT_WPA_EAP   },
84         { "wps",        SUPPLICANT_CAPABILITY_KEYMGMT_WPS       },
85         { }
86 };
87
88 static struct strvalmap authalg_capa_map[] = {
89         { "open",       SUPPLICANT_CAPABILITY_AUTHALG_OPEN      },
90         { "shared",     SUPPLICANT_CAPABILITY_AUTHALG_SHARED    },
91         { "leap",       SUPPLICANT_CAPABILITY_AUTHALG_LEAP      },
92         { }
93 };
94
95 static struct strvalmap proto_capa_map[] = {
96         { "wpa",        SUPPLICANT_CAPABILITY_PROTO_WPA         },
97         { "rsn",        SUPPLICANT_CAPABILITY_PROTO_RSN         },
98         { }
99 };
100
101 static struct strvalmap group_capa_map[] = {
102         { "wep40",      SUPPLICANT_CAPABILITY_GROUP_WEP40       },
103         { "wep104",     SUPPLICANT_CAPABILITY_GROUP_WEP104      },
104         { "tkip",       SUPPLICANT_CAPABILITY_GROUP_TKIP        },
105         { "ccmp",       SUPPLICANT_CAPABILITY_GROUP_CCMP        },
106         { }
107 };
108
109 static struct strvalmap pairwise_capa_map[] = {
110         { "none",       SUPPLICANT_CAPABILITY_PAIRWISE_NONE     },
111         { "tkip",       SUPPLICANT_CAPABILITY_PAIRWISE_TKIP     },
112         { "ccmp",       SUPPLICANT_CAPABILITY_PAIRWISE_CCMP     },
113         { }
114 };
115
116 static struct strvalmap scan_capa_map[] = {
117         { "active",     SUPPLICANT_CAPABILITY_SCAN_ACTIVE       },
118         { "passive",    SUPPLICANT_CAPABILITY_SCAN_PASSIVE      },
119         { "ssid",       SUPPLICANT_CAPABILITY_SCAN_SSID         },
120         { }
121 };
122
123 static struct strvalmap mode_capa_map[] = {
124         { "infrastructure",     SUPPLICANT_CAPABILITY_MODE_INFRA        },
125         { "ad-hoc",             SUPPLICANT_CAPABILITY_MODE_IBSS         },
126         { "ap",                 SUPPLICANT_CAPABILITY_MODE_AP           },
127         { }
128 };
129
130 static GHashTable *interface_table;
131
132 struct supplicant_interface {
133         char *path;
134         unsigned int keymgmt_capa;
135         unsigned int authalg_capa;
136         unsigned int proto_capa;
137         unsigned int group_capa;
138         unsigned int pairwise_capa;
139         unsigned int scan_capa;
140         unsigned int mode_capa;
141         enum supplicant_state state;
142         dbus_bool_t scanning;
143         int apscan;
144         char *ifname;
145         char *driver;
146         char *bridge;
147         GHashTable *network_table;
148         GHashTable *bss_mapping;
149 };
150
151 struct supplicant_network {
152         struct supplicant_interface *interface;
153         char *group;
154         char *name;
155         enum supplicant_mode mode;
156         GHashTable *bss_table;
157 };
158
159 struct supplicant_bss {
160         struct supplicant_interface *interface;
161         char *path;
162         unsigned char bssid[6];
163         unsigned char ssid[32];
164         unsigned int ssid_len;
165         dbus_uint16_t frequency;
166         enum supplicant_mode mode;
167         enum supplicant_security security;
168         dbus_bool_t privacy;
169         dbus_bool_t psk;
170         dbus_bool_t ieee8021x;
171 };
172
173 static enum supplicant_mode string2mode(const char *mode)
174 {
175         if (mode == NULL)
176                 return SUPPLICANT_MODE_UNKNOWN;
177
178         if (g_str_equal(mode, "infrastructure") == TRUE)
179                 return SUPPLICANT_MODE_INFRA;
180         else if (g_str_equal(mode, "ad-hoc") == TRUE)
181                 return SUPPLICANT_MODE_IBSS;
182
183         return SUPPLICANT_MODE_UNKNOWN;
184 }
185
186 static const char *mode2string(enum supplicant_mode mode)
187 {
188         switch (mode) {
189         case SUPPLICANT_MODE_UNKNOWN:
190                 break;
191         case SUPPLICANT_MODE_INFRA:
192                 return "infra";
193         case SUPPLICANT_MODE_IBSS:
194                 return "adhoc";
195         }
196
197         return NULL;
198 }
199
200 static const char *security2string(enum supplicant_security security)
201 {
202         switch (security) {
203         case SUPPLICANT_SECURITY_UNKNOWN:
204                 break;
205         case SUPPLICANT_SECURITY_NONE:
206                 return "none";
207         case SUPPLICANT_SECURITY_WEP:
208                 return "wep";
209         case SUPPLICANT_SECURITY_PSK:
210                 return "psk";
211         case SUPPLICANT_SECURITY_IEEE8021X:
212                 return "ieee8021x";
213         }
214
215         return NULL;
216 }
217
218 static enum supplicant_state string2state(const char *state)
219 {
220         if (state == NULL)
221                 return SUPPLICANT_STATE_UNKNOWN;
222
223         if (g_str_equal(state, "unknown") == TRUE)
224                 return SUPPLICANT_STATE_UNKNOWN;
225         else if (g_str_equal(state, "disconnected") == TRUE)
226                 return SUPPLICANT_STATE_DISCONNECTED;
227         else if (g_str_equal(state, "inactive") == TRUE)
228                 return SUPPLICANT_STATE_INACTIVE;
229         else if (g_str_equal(state, "scanning") == TRUE)
230                 return SUPPLICANT_STATE_SCANNING;
231         else if (g_str_equal(state, "authenticating") == TRUE)
232                 return SUPPLICANT_STATE_AUTHENTICATING;
233         else if (g_str_equal(state, "associating") == TRUE)
234                 return SUPPLICANT_STATE_ASSOCIATING;
235         else if (g_str_equal(state, "associated") == TRUE)
236                 return SUPPLICANT_STATE_ASSOCIATED;
237         else if (g_str_equal(state, "group_handshake") == TRUE)
238                 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
239         else if (g_str_equal(state, "4way_handshake") == TRUE)
240                 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
241         else if (g_str_equal(state, "completed") == TRUE)
242                 return SUPPLICANT_STATE_COMPLETED;
243
244         return SUPPLICANT_STATE_UNKNOWN;
245 }
246
247 static void callback_system_ready(void)
248 {
249         if (system_ready == TRUE)
250                 return;
251
252         system_ready = TRUE;
253
254         if (callbacks_pointer == NULL)
255                 return;
256
257         if (callbacks_pointer->system_ready == NULL)
258                 return;
259
260         callbacks_pointer->system_ready();
261 }
262
263 static void callback_system_killed(void)
264 {
265         system_ready = FALSE;
266
267         if (callbacks_pointer == NULL)
268                 return;
269
270         if (callbacks_pointer->system_killed == NULL)
271                 return;
272
273         callbacks_pointer->system_killed();
274 }
275
276 static void callback_interface_added(struct supplicant_interface *interface)
277 {
278         if (callbacks_pointer == NULL)
279                 return;
280
281         if (callbacks_pointer->interface_added == NULL)
282                 return;
283
284         callbacks_pointer->interface_added(interface);
285 }
286
287 static void callback_interface_removed(struct supplicant_interface *interface)
288 {
289         if (callbacks_pointer == NULL)
290                 return;
291
292         if (callbacks_pointer->interface_removed == NULL)
293                 return;
294
295         callbacks_pointer->interface_removed(interface);
296 }
297
298 static void callback_scan_started(struct supplicant_interface *interface)
299 {
300         if (callbacks_pointer == NULL)
301                 return;
302
303         if (callbacks_pointer->scan_started == NULL)
304                 return;
305
306         callbacks_pointer->scan_started(interface);
307 }
308
309 static void callback_scan_finished(struct supplicant_interface *interface)
310 {
311         if (callbacks_pointer == NULL)
312                 return;
313
314         if (callbacks_pointer->scan_finished == NULL)
315                 return;
316
317         callbacks_pointer->scan_finished(interface);
318 }
319
320 static void callback_network_added(struct supplicant_network *network)
321 {
322         if (callbacks_pointer == NULL)
323                 return;
324
325         if (callbacks_pointer->network_added == NULL)
326                 return;
327
328         callbacks_pointer->network_added(network);
329 }
330
331 static void callback_network_removed(struct supplicant_network *network)
332 {
333         if (callbacks_pointer == NULL)
334                 return;
335
336         if (callbacks_pointer->network_removed == NULL)
337                 return;
338
339         callbacks_pointer->network_removed(network);
340 }
341
342 static void remove_interface(gpointer data)
343 {
344         struct supplicant_interface *interface = data;
345
346         g_hash_table_destroy(interface->bss_mapping);
347         g_hash_table_destroy(interface->network_table);
348
349         callback_interface_removed(interface);
350
351         g_free(interface->path);
352         g_free(interface->ifname);
353         g_free(interface->driver);
354         g_free(interface->bridge);
355         g_free(interface);
356 }
357
358 static void remove_network(gpointer data)
359 {
360         struct supplicant_network *network = data;
361
362         callback_network_removed(network);
363
364         g_free(network->group);
365         g_free(network->name);
366         g_free(network);
367 }
368
369 static void remove_bss(gpointer data)
370 {
371         struct supplicant_bss *bss = data;
372
373         g_free(bss->path);
374         g_free(bss);
375 }
376
377 static void debug_strvalmap(const char *label, struct strvalmap *map,
378                                                         unsigned int val)
379 {
380         int i;
381
382         for (i = 0; map[i].str != NULL; i++) {
383                 if (val & map[i].val)
384                         DBG("%s: %s", label, map[i].str);
385         }
386 }
387
388 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
389 {
390         struct supplicant_interface *interface = user_data;
391         const char *str = NULL;
392         int i;
393
394         dbus_message_iter_get_basic(iter, &str);
395         if (str == NULL)
396                 return;
397
398         for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
399                 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
400                         interface->keymgmt_capa |= keymgmt_capa_map[i].val;
401                         break;
402                 }
403 }
404
405 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
406 {
407         struct supplicant_interface *interface = user_data;
408         const char *str = NULL;
409         int i;
410
411         dbus_message_iter_get_basic(iter, &str);
412         if (str == NULL)
413                 return;
414
415         for (i = 0; authalg_capa_map[i].str != NULL; i++)
416                 if (strcmp(str, authalg_capa_map[i].str) == 0) {
417                         interface->authalg_capa |= authalg_capa_map[i].val;
418                         break;
419                 }
420 }
421
422 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
423 {
424         struct supplicant_interface *interface = user_data;
425         const char *str = NULL;
426         int i;
427
428         dbus_message_iter_get_basic(iter, &str);
429         if (str == NULL)
430                 return;
431
432         for (i = 0; proto_capa_map[i].str != NULL; i++)
433                 if (strcmp(str, proto_capa_map[i].str) == 0) {
434                         interface->proto_capa |= proto_capa_map[i].val;
435                         break;
436                 }
437 }
438
439 static void interface_capability_pairwise(DBusMessageIter *iter, void *user_data)
440 {
441         struct supplicant_interface *interface = user_data;
442         const char *str = NULL;
443         int i;
444
445         dbus_message_iter_get_basic(iter, &str);
446         if (str == NULL)
447                 return;
448
449         for (i = 0; pairwise_capa_map[i].str != NULL; i++)
450                 if (strcmp(str, pairwise_capa_map[i].str) == 0) {
451                         interface->pairwise_capa |= pairwise_capa_map[i].val;
452                         break;
453                 }
454 }
455
456 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
457 {
458         struct supplicant_interface *interface = user_data;
459         const char *str = NULL;
460         int i;
461
462         dbus_message_iter_get_basic(iter, &str);
463         if (str == NULL)
464                 return;
465
466         for (i = 0; group_capa_map[i].str != NULL; i++)
467                 if (strcmp(str, group_capa_map[i].str) == 0) {
468                         interface->group_capa |= group_capa_map[i].val;
469                         break;
470                 }
471 }
472
473 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
474 {
475         struct supplicant_interface *interface = user_data;
476         const char *str = NULL;
477         int i;
478
479         dbus_message_iter_get_basic(iter, &str);
480         if (str == NULL)
481                 return;
482
483         for (i = 0; scan_capa_map[i].str != NULL; i++)
484                 if (strcmp(str, scan_capa_map[i].str) == 0) {
485                         interface->scan_capa |= scan_capa_map[i].val;
486                         break;
487                 }
488 }
489
490 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
491 {
492         struct supplicant_interface *interface = user_data;
493         const char *str = NULL;
494         int i;
495
496         dbus_message_iter_get_basic(iter, &str);
497         if (str == NULL)
498                 return;
499
500         for (i = 0; mode_capa_map[i].str != NULL; i++)
501                 if (strcmp(str, mode_capa_map[i].str) == 0) {
502                         interface->mode_capa |= mode_capa_map[i].val;
503                         break;
504                 }
505 }
506
507 static void interface_capability(const char *key, DBusMessageIter *iter,
508                                                         void *user_data)
509 {
510         struct supplicant_interface *interface = user_data;
511
512         if (key == NULL)
513                 return;
514
515         if (g_strcmp0(key, "KeyMgmt") == 0)
516                 supplicant_dbus_array_foreach(iter,
517                                 interface_capability_keymgmt, interface);
518         else if (g_strcmp0(key, "AuthAlg") == 0)
519                 supplicant_dbus_array_foreach(iter,
520                                 interface_capability_authalg, interface);
521         else if (g_strcmp0(key, "Protocol") == 0)
522                 supplicant_dbus_array_foreach(iter,
523                                 interface_capability_proto, interface);
524         else if (g_strcmp0(key, "Pairwise") == 0)
525                 supplicant_dbus_array_foreach(iter,
526                                 interface_capability_pairwise, interface);
527         else if (g_strcmp0(key, "Group") == 0)
528                 supplicant_dbus_array_foreach(iter,
529                                 interface_capability_group, interface);
530         else if (g_strcmp0(key, "Scan") == 0)
531                 supplicant_dbus_array_foreach(iter,
532                                 interface_capability_scan, interface);
533         else if (g_strcmp0(key, "Modes") == 0)
534                 supplicant_dbus_array_foreach(iter,
535                                 interface_capability_mode, interface);
536         else
537                 DBG("key %s type %c",
538                                 key, dbus_message_iter_get_arg_type(iter));
539 }
540
541 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
542 {
543         if (interface == NULL)
544                 return NULL;
545
546         return interface->ifname;
547 }
548
549 const char *supplicant_interface_get_driver(struct supplicant_interface *interface)
550 {
551         if (interface == NULL)
552                 return NULL;
553
554         return interface->driver;
555 }
556
557 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
558 {
559         if (network == NULL)
560                 return NULL;
561
562         return network->interface;
563 }
564
565 const char *supplicant_network_get_name(struct supplicant_network *network)
566 {
567         if (network == NULL || network->name == NULL)
568                 return "";
569
570         return network->name;
571 }
572
573 const char *supplicant_network_get_identifier(struct supplicant_network *network)
574 {
575         if (network == NULL || network->group == NULL)
576                 return "";
577
578         return network->group;
579 }
580
581 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
582 {
583         if (network == NULL)
584                 return SUPPLICANT_MODE_UNKNOWN;
585
586         return network->mode;
587 }
588
589 static void network_property(const char *key, DBusMessageIter *iter,
590                                                         void *user_data)
591 {
592         if (key == NULL)
593                 return;
594
595         //DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
596 }
597
598 static void interface_network_added(DBusMessageIter *iter, void *user_data)
599 {
600         //struct supplicant_interface *interface = user_data;
601         const char *path = NULL;
602
603         dbus_message_iter_get_basic(iter, &path);
604         if (path == NULL)
605                 return;
606
607         if (g_strcmp0(path, "/") == 0)
608                 return;
609
610         dbus_message_iter_next(iter);
611         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
612                 supplicant_dbus_property_foreach(iter, network_property, NULL);
613                 network_property(NULL, NULL, NULL);
614                 return;
615         }
616
617         DBG("path %s", path);
618
619         supplicant_dbus_property_get_all(path,
620                                 SUPPLICANT_INTERFACE ".Interface.Network",
621                                                 network_property, NULL);
622 }
623
624 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
625 {
626         const char *path = NULL;
627
628         dbus_message_iter_get_basic(iter, &path);
629         if (path == NULL)
630                 return;
631
632         DBG("path %s", path);
633 }
634
635 static char *create_name(unsigned char *ssid, int ssid_len)
636 {
637         char *name;
638         int i;
639
640         if (ssid_len < 1 || ssid[0] == '\0')
641                 name = NULL;
642         else
643                 name = g_try_malloc0(ssid_len + 1);
644
645         if (name == NULL)
646                 return g_strdup("");
647
648         for (i = 0; i < ssid_len; i++) {
649                 if (g_ascii_isprint(ssid[i]))
650                         name[i] = ssid[i];
651                 else
652                         name[i] = ' ';
653         }
654
655         return name;
656 }
657
658 static char *create_group(struct supplicant_bss *bss)
659 {
660         GString *str;
661         unsigned int i;
662         const char *mode, *security;
663
664         str = g_string_sized_new((bss->ssid_len * 2) + 24);
665         if (str == NULL)
666                 return NULL;
667
668         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
669                 for (i = 0; i < bss->ssid_len; i++)
670                         g_string_append_printf(str, "%02x", bss->ssid[i]);
671         } else
672                 g_string_append_printf(str, "hidden");
673
674         mode = mode2string(bss->mode);
675         if (mode != NULL)
676                 g_string_append_printf(str, "_%s", mode);
677
678         security = security2string(bss->security);
679         if (security != NULL)
680                 g_string_append_printf(str, "_%s", security);
681
682         return g_string_free(str, FALSE);
683 }
684
685 static void add_bss_to_network(struct supplicant_bss *bss)
686 {
687         struct supplicant_interface *interface = bss->interface;
688         struct supplicant_network *network;
689         char *group;
690
691         group = create_group(bss);
692         if (group == NULL)
693                 return;
694
695         network = g_hash_table_lookup(interface->network_table, group);
696         if (network != NULL) {
697                 g_free(group);
698                 goto done;
699         }
700
701         network = g_try_new0(struct supplicant_network, 1);
702         if (network == NULL) {
703                 g_free(group);
704                 return;
705         }
706
707         network->group = group;
708         network->name = create_name(bss->ssid, bss->ssid_len);
709         network->mode = bss->mode;
710
711         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
712                                                         NULL, remove_bss);
713
714         g_hash_table_replace(interface->network_table,
715                                                 network->group, network);
716
717         callback_network_added(network);
718
719 done:
720         g_hash_table_replace(interface->bss_mapping, bss->path, network);
721         g_hash_table_replace(network->bss_table, bss->path, bss);
722 }
723
724 static unsigned char wifi_oui[3]      = { 0x00, 0x50, 0xf2 };
725 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
726
727 static void extract_rsn(struct supplicant_bss *bss,
728                                         const unsigned char *buf, int len)
729 {
730         uint16_t count;
731         int i;
732
733         /* Version */
734         if (len < 2)
735                 return;
736
737         buf += 2;
738         len -= 2;
739
740         /* Group cipher */
741         if (len < 4)
742                 return;
743
744         buf += 4;
745         len -= 4;
746
747         /* Pairwise cipher */
748         if (len < 2)
749                 return;
750
751         count = buf[0] | (buf[1] << 8);
752         if (2 + (count * 4) > len)
753                 return;
754
755         buf += 2 + (count * 4);
756         len -= 2 + (count * 4);
757
758         /* Authentication */
759         if (len < 2)
760                 return;
761
762         count = buf[0] | (buf[1] << 8);
763         if (2 + (count * 4) > len)
764                 return;
765
766         for (i = 0; i < count; i++) {
767                 const unsigned char *ptr = buf + 2 + (i * 4);
768
769                 if (memcmp(ptr, wifi_oui, 3) == 0) {
770                         switch (ptr[3]) {
771                         case 1:
772                                 bss->ieee8021x = TRUE;
773                                 break;
774                         case 2:
775                                 bss->psk = TRUE;
776                                 break;
777                         }
778                 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
779                         switch (ptr[3]) {
780                         case 1:
781                                 bss->ieee8021x = TRUE;
782                                 break;
783                         case 2:
784                                 bss->psk = TRUE;
785                                 break;
786                         }
787                 }
788         }
789
790         buf += 2 + (count * 4);
791         len -= 2 + (count * 4);
792 }
793
794 static void bss_property(const char *key, DBusMessageIter *iter,
795                                                         void *user_data)
796 {
797         struct supplicant_bss *bss = user_data;
798
799         if (bss->interface == NULL)
800                 return;
801
802         if (key == NULL) {
803                 if (bss->ieee8021x == TRUE)
804                         bss->security = SUPPLICANT_SECURITY_IEEE8021X;
805                 else if (bss->psk == TRUE)
806                         bss->security = SUPPLICANT_SECURITY_PSK;
807                 else if (bss->privacy == TRUE)
808                         bss->security = SUPPLICANT_SECURITY_WEP;
809                 else
810                         bss->security = SUPPLICANT_SECURITY_NONE;
811
812                 add_bss_to_network(bss);
813                 return;
814         }
815
816         if (g_strcmp0(key, "BSSID") == 0) {
817                 DBusMessageIter array;
818                 unsigned char *addr;
819                 int addr_len;
820
821                 dbus_message_iter_recurse(iter, &array);
822                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
823
824                 if (addr_len == 6)
825                         memcpy(bss->bssid, addr, addr_len);
826         } else if (g_strcmp0(key, "SSID") == 0) {
827                 DBusMessageIter array;
828                 unsigned char *ssid;
829                 int ssid_len;
830
831                 dbus_message_iter_recurse(iter, &array);
832                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
833
834                 if (ssid_len > 0 && ssid_len < 33) {
835                         memcpy(bss->ssid, ssid, ssid_len);
836                         bss->ssid_len = ssid_len;
837                 } else {
838                         memset(bss->ssid, 0, sizeof(bss->ssid));
839                         bss->ssid_len = 0;
840                 }
841         } else if (g_strcmp0(key, "Capabilities") == 0) {
842                 dbus_uint16_t capabilities = 0x0000;
843
844                 dbus_message_iter_get_basic(iter, &capabilities);
845
846                 if (capabilities & IEEE80211_CAP_ESS)
847                         bss->mode = SUPPLICANT_MODE_INFRA;
848                 else if (capabilities & IEEE80211_CAP_IBSS)
849                         bss->mode = SUPPLICANT_MODE_IBSS;
850
851                 if (capabilities & IEEE80211_CAP_PRIVACY)
852                         bss->privacy = TRUE;
853         } else if (g_strcmp0(key, "Mode") == 0) {
854                 const char *mode = NULL;
855
856                 dbus_message_iter_get_basic(iter, &mode);
857                 bss->mode = string2mode(mode);
858         } else if (g_strcmp0(key, "Frequency") == 0) {
859                 dbus_uint16_t frequency = 0;
860
861                 dbus_message_iter_get_basic(iter, &frequency);
862                 bss->frequency = frequency;
863         } else if (g_strcmp0(key, "Signal") == 0) {
864                 dbus_int16_t signal = 0;
865
866                 dbus_message_iter_get_basic(iter, &signal);
867         } else if (g_strcmp0(key, "Level") == 0) {
868                 dbus_int32_t level = 0;
869
870                 dbus_message_iter_get_basic(iter, &level);
871         } else if (g_strcmp0(key, "MaxRate") == 0) {
872                 dbus_uint16_t maxrate = 0;
873
874                 dbus_message_iter_get_basic(iter, &maxrate);
875         } else if (g_strcmp0(key, "Privacy") == 0) {
876                 dbus_bool_t privacy = FALSE;
877
878                 dbus_message_iter_get_basic(iter, &privacy);
879                 bss->privacy = privacy;
880         } else if (g_strcmp0(key, "RSNIE") == 0) {
881                 DBusMessageIter array;
882                 unsigned char *ie;
883                 int ie_len;
884
885                 dbus_message_iter_recurse(iter, &array);
886                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
887
888                 if (ie_len > 2)
889                         extract_rsn(bss, ie + 2, ie_len - 2);
890         } else if (g_strcmp0(key, "WPAIE") == 0) {
891                 DBusMessageIter array;
892                 unsigned char *ie;
893                 int ie_len;
894
895                 dbus_message_iter_recurse(iter, &array);
896                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
897
898                 if (ie_len > 6)
899                         extract_rsn(bss, ie + 6, ie_len - 6);
900         } else if (g_strcmp0(key, "WPSIE") == 0) {
901                 DBusMessageIter array;
902                 unsigned char *ie;
903                 int ie_len;
904
905                 dbus_message_iter_recurse(iter, &array);
906                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
907         } else
908                 DBG("key %s type %c",
909                                 key, dbus_message_iter_get_arg_type(iter));
910 }
911
912 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
913 {
914         struct supplicant_interface *interface = user_data;
915         struct supplicant_network *network;
916         struct supplicant_bss *bss;
917         const char *path = NULL;
918
919         dbus_message_iter_get_basic(iter, &path);
920         if (path == NULL)
921                 return;
922
923         if (g_strcmp0(path, "/") == 0)
924                 return;
925
926         network = g_hash_table_lookup(interface->bss_mapping, path);
927         if (network != NULL) {
928                 bss = g_hash_table_lookup(network->bss_table, path);
929                 if (bss != NULL)
930                         return;
931         }
932
933         bss = g_try_new0(struct supplicant_bss, 1);
934         if (bss == NULL)
935                 return;
936
937         bss->interface = interface;
938         bss->path = g_strdup(path);
939
940         dbus_message_iter_next(iter);
941         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
942                 supplicant_dbus_property_foreach(iter, bss_property, bss);
943                 bss_property(NULL, NULL, bss);
944                 return;
945         }
946
947         supplicant_dbus_property_get_all(path,
948                                         SUPPLICANT_INTERFACE ".Interface.BSS",
949                                                         bss_property, bss);
950 }
951
952 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
953 {
954         struct supplicant_interface *interface = user_data;
955         struct supplicant_network *network;
956         const char *path = NULL;
957
958         dbus_message_iter_get_basic(iter, &path);
959         if (path == NULL)
960                 return;
961
962         network = g_hash_table_lookup(interface->bss_mapping, path);
963         if (network == NULL)
964                 return;
965
966         g_hash_table_remove(interface->bss_mapping, path);
967         g_hash_table_remove(network->bss_table, path);
968
969         if (g_hash_table_size(network->bss_table) == 0)
970                 g_hash_table_remove(interface->network_table, network->group);
971 }
972
973 static void interface_property(const char *key, DBusMessageIter *iter,
974                                                         void *user_data)
975 {
976         struct supplicant_interface *interface = user_data;
977
978         if (interface == NULL)
979                 return;
980
981         if (key == NULL) {
982                 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
983                                                 interface->keymgmt_capa);
984                 debug_strvalmap("AuthAlg capability", authalg_capa_map,
985                                                 interface->authalg_capa);
986                 debug_strvalmap("Protocol capability", proto_capa_map,
987                                                 interface->proto_capa);
988                 debug_strvalmap("Pairwise capability", pairwise_capa_map,
989                                                 interface->pairwise_capa);
990                 debug_strvalmap("Group capability", group_capa_map,
991                                                 interface->group_capa);
992                 debug_strvalmap("Scan capability", scan_capa_map,
993                                                 interface->scan_capa);
994                 debug_strvalmap("Mode capability", mode_capa_map,
995                                                 interface->mode_capa);
996
997                 callback_interface_added(interface);
998                 return;
999         }
1000
1001         if (g_strcmp0(key, "Capabilities") == 0) {
1002                 supplicant_dbus_property_foreach(iter, interface_capability,
1003                                                                 interface);
1004         } else if (g_strcmp0(key, "State") == 0) {
1005                 const char *str = NULL;
1006
1007                 dbus_message_iter_get_basic(iter, &str);
1008                 if (str != NULL)
1009                         interface->state = string2state(str);
1010         } else if (g_strcmp0(key, "Scanning") == 0) {
1011                 dbus_bool_t scanning = FALSE;
1012
1013                 dbus_message_iter_get_basic(iter, &scanning);
1014                 interface->scanning = scanning;
1015
1016                 DBG("scanning %u", interface->scanning);
1017
1018                 if (interface->scanning == TRUE)
1019                         callback_scan_started(interface);
1020         } else if (g_strcmp0(key, "ApScan") == 0) {
1021                 int apscan = 1;
1022
1023                 dbus_message_iter_get_basic(iter, &apscan);
1024                 interface->apscan = apscan;
1025         } else if (g_strcmp0(key, "Ifname") == 0) {
1026                 const char *str = NULL;
1027
1028                 dbus_message_iter_get_basic(iter, &str);
1029                 if (str != NULL)
1030                         interface->ifname = g_strdup(str);
1031         } else if (g_strcmp0(key, "Driver") == 0) {
1032                 const char *str = NULL;
1033
1034                 dbus_message_iter_get_basic(iter, &str);
1035                 if (str != NULL)
1036                         interface->driver = g_strdup(str);
1037         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1038                 const char *str = NULL;
1039
1040                 dbus_message_iter_get_basic(iter, &str);
1041                 if (str != NULL)
1042                         interface->bridge = g_strdup(str);
1043         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1044                 interface_bss_added(iter, interface);
1045         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1046                 interface_network_added(iter, interface);
1047         } else if (g_strcmp0(key, "BSSs") == 0) {
1048                 supplicant_dbus_array_foreach(iter, interface_bss_added,
1049                                                                 interface);
1050         } else if (g_strcmp0(key, "Blobs") == 0) {
1051         } else if (g_strcmp0(key, "Networks") == 0) {
1052                 supplicant_dbus_array_foreach(iter, interface_network_added,
1053                                                                 interface);
1054         } else
1055                 DBG("key %s type %c",
1056                                 key, dbus_message_iter_get_arg_type(iter));
1057 }
1058
1059 static struct supplicant_interface *interface_alloc(const char *path)
1060 {
1061         struct supplicant_interface *interface;
1062
1063         interface = g_try_new0(struct supplicant_interface, 1);
1064         if (interface == NULL)
1065                 return NULL;
1066
1067         interface->path = g_strdup(path);
1068
1069         interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1070                                                         NULL, remove_network);
1071
1072         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1073                                                                 NULL, NULL);
1074
1075         g_hash_table_replace(interface_table, interface->path, interface);
1076
1077         return interface;
1078 }
1079
1080 static void interface_added(DBusMessageIter *iter, void *user_data)
1081 {
1082         struct supplicant_interface *interface;
1083         const char *path = NULL;
1084
1085         dbus_message_iter_get_basic(iter, &path);
1086         if (path == NULL)
1087                 return;
1088
1089         if (g_strcmp0(path, "/") == 0)
1090                 return;
1091
1092         interface = g_hash_table_lookup(interface_table, path);
1093         if (interface != NULL)
1094                 return;
1095
1096         interface = interface_alloc(path);
1097         if (interface == NULL)
1098                 return;
1099
1100         dbus_message_iter_next(iter);
1101         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1102                 supplicant_dbus_property_foreach(iter, interface_property,
1103                                                                 interface);
1104                 interface_property(NULL, NULL, interface);
1105                 return;
1106         }
1107
1108         supplicant_dbus_property_get_all(path,
1109                                         SUPPLICANT_INTERFACE ".Interface",
1110                                                 interface_property, interface);
1111 }
1112
1113 static void interface_removed(DBusMessageIter *iter, void *user_data)
1114 {
1115         const char *path = NULL;
1116
1117         dbus_message_iter_get_basic(iter, &path);
1118         if (path == NULL)
1119                 return;
1120
1121         g_hash_table_remove(interface_table, path);
1122 }
1123
1124 static void eap_method(DBusMessageIter *iter, void *user_data)
1125 {
1126         const char *str = NULL;
1127         int i;
1128
1129         dbus_message_iter_get_basic(iter, &str);
1130         if (str == NULL)
1131                 return;
1132
1133         for (i = 0; eap_method_map[i].str != NULL; i++)
1134                 if (strcmp(str, eap_method_map[i].str) == 0) {
1135                         eap_methods |= eap_method_map[i].val;
1136                         break;
1137                 }
1138 }
1139
1140 static void service_property(const char *key, DBusMessageIter *iter,
1141                                                         void *user_data)
1142 {
1143         if (key == NULL) {
1144                 callback_system_ready();
1145                 return;
1146         }
1147
1148         if (g_strcmp0(key, "DebugParams") == 0) {
1149                 DBusMessageIter list;
1150
1151                 dbus_message_iter_recurse(iter, &list);
1152                 dbus_message_iter_get_basic(&list, &debug_level);
1153
1154                 dbus_message_iter_next(&list);
1155                 dbus_message_iter_get_basic(&list, &debug_timestamp);
1156
1157                 dbus_message_iter_next(&list);
1158                 dbus_message_iter_get_basic(&list, &debug_showkeys);
1159
1160                 DBG("Debug level %d (timestamp %u show keys %u)",
1161                                 debug_level, debug_timestamp, debug_showkeys);
1162         } else if (g_strcmp0(key, "DebugLevel") == 0) {
1163                 dbus_message_iter_get_basic(iter, &debug_level);
1164                 DBG("Debug level %d", debug_level);
1165         } else if (g_strcmp0(key, "DebugTimeStamp") == 0) {
1166                 dbus_message_iter_get_basic(iter, &debug_timestamp);
1167                 DBG("Debug timestamp %u", debug_timestamp);
1168         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1169                 dbus_message_iter_get_basic(iter, &debug_showkeys);
1170                 DBG("Debug show keys %u", debug_showkeys);
1171         } else if (g_strcmp0(key, "Interfaces") == 0) {
1172                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1173         } else if (g_strcmp0(key, "EapMethods") == 0) {
1174                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1175                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1176         } else
1177                 DBG("key %s type %c",
1178                                 key, dbus_message_iter_get_arg_type(iter));
1179 }
1180
1181 static void supplicant_bootstrap(void)
1182 {
1183         supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1184                                                 SUPPLICANT_INTERFACE,
1185                                                 service_property, NULL);
1186 }
1187
1188 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1189 {
1190         const char *name = NULL, *old = NULL, *new = NULL;
1191
1192         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1193                 return;
1194
1195         dbus_message_iter_get_basic(iter, &name);
1196         if (name == NULL)
1197                 return;
1198
1199         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1200                 return;
1201
1202         dbus_message_iter_next(iter);
1203         dbus_message_iter_get_basic(iter, &old);
1204         dbus_message_iter_next(iter);
1205         dbus_message_iter_get_basic(iter, &new);
1206
1207         if (old == NULL || new == NULL)
1208                 return;
1209
1210         if (strlen(old) > 0 && strlen(new) == 0) {
1211                 system_available = FALSE;
1212                 g_hash_table_remove_all(interface_table);
1213                 callback_system_killed();
1214         }
1215
1216         if (strlen(new) > 0 && strlen(old) == 0) {
1217                 system_available = TRUE;
1218                 supplicant_bootstrap();
1219         }
1220 }
1221
1222 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1223 {
1224         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1225                 return;
1226
1227         supplicant_dbus_property_foreach(iter, service_property, NULL);
1228 }
1229
1230 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1231 {
1232         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1233                 interface_added(iter, NULL);
1234 }
1235
1236 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1237 {
1238         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1239                 interface_removed(iter, NULL);
1240 }
1241
1242 static void signal_scan_done(const char *path, DBusMessageIter *iter)
1243 {
1244         struct supplicant_interface *interface;
1245         dbus_bool_t success = FALSE;
1246
1247         interface = g_hash_table_lookup(interface_table, path);
1248         if (interface == NULL)
1249                 return;
1250
1251         dbus_message_iter_get_basic(iter, &success);
1252
1253         callback_scan_finished(interface);
1254 }
1255
1256 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1257 {
1258         struct supplicant_interface *interface;
1259
1260         interface = g_hash_table_lookup(interface_table, path);
1261         if (interface == NULL)
1262                 return;
1263
1264         interface_bss_added(iter, interface);
1265 }
1266
1267 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1268 {
1269         struct supplicant_interface *interface;
1270
1271         interface = g_hash_table_lookup(interface_table, path);
1272         if (interface == NULL)
1273                 return;
1274
1275         interface_bss_removed(iter, interface);
1276 }
1277
1278 static void signal_network_added(const char *path, DBusMessageIter *iter)
1279 {
1280         struct supplicant_interface *interface;
1281
1282         interface = g_hash_table_lookup(interface_table, path);
1283         if (interface == NULL)
1284                 return;
1285
1286         interface_network_added(iter, interface);
1287 }
1288
1289 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1290 {
1291         struct supplicant_interface *interface;
1292
1293         interface = g_hash_table_lookup(interface_table, path);
1294         if (interface == NULL)
1295                 return;
1296
1297         interface_network_removed(iter, interface);
1298 }
1299
1300 static struct {
1301         const char *interface;
1302         const char *member;
1303         void (*function) (const char *path, DBusMessageIter *iter);
1304 } signal_map[] = {
1305         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
1306
1307         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1308         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
1309         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
1310         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
1311
1312         { SUPPLICANT_INTERFACE ".Interface", "ScanDone",       signal_scan_done       },
1313         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",       signal_bss_added       },
1314         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",     signal_bss_removed     },
1315         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",   signal_network_added   },
1316         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1317
1318         { }
1319 };
1320
1321 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1322                                         DBusMessage *message, void *data)
1323 {
1324         DBusMessageIter iter;
1325         const char *path;
1326         int i;
1327
1328         path = dbus_message_get_path(message);
1329         if (path == NULL)
1330                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1331
1332         if (dbus_message_iter_init(message, &iter) == FALSE)
1333                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1334
1335         for (i = 0; signal_map[i].interface != NULL; i++) {
1336                 if (dbus_message_has_interface(message,
1337                                         signal_map[i].interface) == FALSE)
1338                         continue;
1339
1340                 if (dbus_message_has_member(message,
1341                                         signal_map[i].member) == FALSE)
1342                         continue;
1343
1344                 signal_map[i].function(path, &iter);
1345                 break;
1346         }
1347
1348         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1349 }
1350
1351 static const char *supplicant_rule0 = "type=signal,"
1352                                         "path=" DBUS_PATH_DBUS ","
1353                                         "sender=" DBUS_SERVICE_DBUS ","
1354                                         "interface=" DBUS_INTERFACE_DBUS ","
1355                                         "member=NameOwnerChanged,"
1356                                         "arg0=" SUPPLICANT_SERVICE;
1357 static const char *supplicant_rule1 = "type=signal,"
1358                         "interface=" SUPPLICANT_INTERFACE;
1359 static const char *supplicant_rule2 = "type=signal,"
1360                         "interface=" SUPPLICANT_INTERFACE ".Interface";
1361 static const char *supplicant_rule3 = "type=signal,"
1362                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1363 static const char *supplicant_rule4 = "type=signal,"
1364                         "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1365 static const char *supplicant_rule5 = "type=signal,"
1366                         "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1367 static const char *supplicant_rule6 = "type=signal,"
1368                         "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1369
1370 int supplicant_register(const struct supplicant_callbacks *callbacks)
1371 {
1372         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1373         if (connection == NULL)
1374                 return -EIO;
1375
1376         if (dbus_connection_add_filter(connection,
1377                                 supplicant_filter, NULL, NULL) == FALSE) {
1378                 dbus_connection_unref(connection);
1379                 connection = NULL;
1380                 return -EIO;
1381         }
1382
1383         callbacks_pointer = callbacks;
1384         eap_methods = 0;
1385
1386         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1387                                                 NULL, remove_interface);
1388
1389         supplicant_dbus_setup(connection);
1390
1391         dbus_bus_add_match(connection, supplicant_rule0, NULL);
1392         dbus_bus_add_match(connection, supplicant_rule1, NULL);
1393         dbus_bus_add_match(connection, supplicant_rule2, NULL);
1394         dbus_bus_add_match(connection, supplicant_rule3, NULL);
1395         dbus_bus_add_match(connection, supplicant_rule4, NULL);
1396         dbus_bus_add_match(connection, supplicant_rule5, NULL);
1397         dbus_bus_add_match(connection, supplicant_rule6, NULL);
1398         dbus_connection_flush(connection);
1399
1400         if (dbus_bus_name_has_owner(connection,
1401                                         SUPPLICANT_SERVICE, NULL) == TRUE) {
1402                 system_available = TRUE;
1403                 supplicant_bootstrap();
1404         }
1405
1406         return 0;
1407 }
1408
1409 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1410 {
1411         if (connection != NULL) {
1412                 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1413                 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1414                 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1415                 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1416                 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1417                 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1418                 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1419                 dbus_connection_flush(connection);
1420
1421                 dbus_connection_remove_filter(connection,
1422                                                 supplicant_filter, NULL);
1423         }
1424
1425         if (interface_table != NULL) {
1426                 g_hash_table_destroy(interface_table);
1427                 interface_table = NULL;
1428         }
1429
1430         if (system_available == TRUE)
1431                 callback_system_killed();
1432
1433         if (connection != NULL) {
1434                 dbus_connection_unref(connection);
1435                 connection = NULL;
1436         }
1437
1438         callbacks_pointer = NULL;
1439         eap_methods = 0;
1440 }
1441
1442 static void debug_level_result(const char *error,
1443                                 DBusMessageIter *iter, void *user_data)
1444 {
1445         if (error != NULL)
1446                 DBG("debug level failure: %s", error);
1447 }
1448
1449 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1450 {
1451         dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1452         DBusMessageIter entry;
1453
1454         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1455                                                         NULL, &entry);
1456
1457         dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1458         dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1459                                                 &debug_timestamp);
1460         dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1461                                                 &debug_showkeys);
1462
1463         dbus_message_iter_close_container(iter, &entry);
1464 }
1465
1466 void supplicant_set_debug_level(unsigned int level)
1467 {
1468         if (system_available == FALSE)
1469                 return;
1470
1471         supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1472                                 "DebugParams", "(ibb)", add_debug_level,
1473                                 debug_level_result, GUINT_TO_POINTER(level));
1474 }
1475
1476 struct interface_create_data {
1477         const char *ifname;
1478         const char *driver;
1479         struct supplicant_interface *interface;
1480         supplicant_interface_create_callback callback;
1481         void *user_data;
1482 };
1483
1484 static void interface_create_property(const char *key, DBusMessageIter *iter,
1485                                                         void *user_data)
1486 {
1487         struct interface_create_data *data = user_data;
1488         struct supplicant_interface *interface = data->interface;
1489
1490         if (key == NULL) {
1491                 if (data->callback != NULL)
1492                         data->callback(0, data->interface, data->user_data);
1493
1494                 dbus_free(data);
1495         }
1496
1497         interface_property(key, iter, interface);
1498 }
1499
1500 static void interface_create_result(const char *error,
1501                                 DBusMessageIter *iter, void *user_data)
1502 {
1503         struct interface_create_data *data = user_data;
1504         const char *path = NULL;
1505         int err;
1506
1507         if (error != NULL) {
1508                 err = -EIO;
1509                 goto done;
1510         }
1511
1512         dbus_message_iter_get_basic(iter, &path);
1513         if (path == NULL) {
1514                 err = -EINVAL;
1515                 goto done;
1516         }
1517
1518         if (system_available == FALSE) {
1519                 err = -EFAULT;
1520                 goto done;
1521         }
1522
1523         data->interface = g_hash_table_lookup(interface_table, path);
1524         if (data->interface == NULL) {
1525                 data->interface = interface_alloc(path);
1526                 if (data->interface == NULL) {
1527                         err = -ENOMEM;
1528                         goto done;
1529                 }
1530         }
1531
1532         err = supplicant_dbus_property_get_all(path,
1533                                         SUPPLICANT_INTERFACE ".Interface",
1534                                         interface_create_property, data);
1535         if (err == 0)
1536                 return;
1537
1538 done:
1539         if (data->callback != NULL)
1540                 data->callback(err, NULL, data->user_data);
1541
1542         dbus_free(data);
1543 }
1544
1545 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1546 {
1547         struct interface_create_data *data = user_data;
1548         DBusMessageIter dict;
1549
1550         supplicant_dbus_dict_open(iter, &dict);
1551
1552         supplicant_dbus_dict_append_basic(&dict, "Ifname",
1553                                         DBUS_TYPE_STRING, &data->ifname);
1554         supplicant_dbus_dict_append_basic(&dict, "Driver",
1555                                         DBUS_TYPE_STRING, &data->driver);
1556
1557         supplicant_dbus_dict_close(iter, &dict);
1558 }
1559
1560 static void interface_get_result(const char *error,
1561                                 DBusMessageIter *iter, void *user_data)
1562 {
1563         struct interface_create_data *data = user_data;
1564         struct supplicant_interface *interface;
1565         const char *path = NULL;
1566         int err;
1567
1568         if (error != NULL) {
1569                 err = -EIO;
1570                 goto create;
1571         }
1572
1573         dbus_message_iter_get_basic(iter, &path);
1574         if (path == NULL) {
1575                 err = -EINVAL;
1576                 goto done;
1577         }
1578
1579         interface = g_hash_table_lookup(interface_table, path);
1580         if (interface == NULL) {
1581                 err = -ENOENT;
1582                 goto done;
1583         }
1584
1585         if (data->callback != NULL)
1586                 data->callback(0, interface, data->user_data);
1587
1588         dbus_free(data);
1589
1590         return;
1591
1592 create:
1593         if (system_available == FALSE) {
1594                 err = -EFAULT;
1595                 goto done;
1596         }
1597
1598         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1599                                                 SUPPLICANT_INTERFACE,
1600                                                 "CreateInterface",
1601                                                 interface_create_params,
1602                                                 interface_create_result, data);
1603         if (err == 0)
1604                 return;
1605
1606 done:
1607         if (data->callback != NULL)
1608                 data->callback(err, NULL, data->user_data);
1609
1610         dbus_free(data);
1611 }
1612
1613 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1614 {
1615         struct interface_create_data *data = user_data;
1616
1617         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1618 }
1619
1620 int supplicant_interface_create(const char *ifname, const char *driver,
1621                         supplicant_interface_create_callback callback,
1622                                                         void *user_data)
1623 {
1624         struct interface_create_data *data;
1625
1626         if (system_available == FALSE)
1627                 return -EFAULT;
1628
1629         data = dbus_malloc0(sizeof(*data));
1630         if (data == NULL)
1631                 return -ENOMEM;
1632
1633         data->ifname = ifname;
1634         data->driver = driver;
1635         data->callback = callback;
1636         data->user_data = user_data;
1637
1638         return supplicant_dbus_method_call(SUPPLICANT_PATH,
1639                                                 SUPPLICANT_INTERFACE,
1640                                                 "GetInterface",
1641                                                 interface_get_params,
1642                                                 interface_get_result, data);
1643 }
1644
1645 int supplicant_interface_remove(struct supplicant_interface *interface,
1646                         supplicant_interface_remove_callback callback,
1647                                                         void *user_data)
1648 {
1649         if (system_available == FALSE)
1650                 return -EFAULT;
1651
1652         return 0;
1653 }
1654
1655 static void interface_scan_result(const char *error,
1656                                 DBusMessageIter *iter, void *user_data)
1657 {
1658         DBG("error %s", error);
1659 }
1660
1661 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
1662 {
1663         DBusMessageIter dict;
1664         const char *type = "passive";
1665
1666         DBG("");
1667
1668         supplicant_dbus_dict_open(iter, &dict);
1669
1670         supplicant_dbus_dict_append_basic(&dict, "Type",
1671                                                 DBUS_TYPE_STRING, &type);
1672
1673         supplicant_dbus_dict_close(iter, &dict);
1674 }
1675
1676 int supplicant_interface_scan(struct supplicant_interface *interface)
1677 {
1678         if (system_available == FALSE)
1679                 return -EFAULT;
1680
1681         return supplicant_dbus_method_call(interface->path,
1682                         SUPPLICANT_INTERFACE ".Interface", "Scan",
1683                         interface_scan_params, interface_scan_result, NULL);
1684 }
1685
1686 static void interface_disconnect_result(const char *error,
1687                                 DBusMessageIter *iter, void *user_data)
1688 {
1689         DBG("error %s", error);
1690 }
1691
1692 int supplicant_interface_disconnect(struct supplicant_interface *interface)
1693 {
1694         if (system_available == FALSE)
1695                 return -EFAULT;
1696
1697         return supplicant_dbus_method_call(interface->path,
1698                         SUPPLICANT_INTERFACE ".Interface", "Disconnect",
1699                                 NULL, interface_disconnect_result, NULL);
1700 }