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