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