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