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