4850b634f181d986d26fad80ee49f4d51c9246fb
[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 <string.h>
28 #include <stdint.h>
29 #include <syslog.h>
30
31 #include <glib.h>
32 #include <gdbus.h>
33
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/log.h>
36
37 #include "dbus.h"
38 #include "gsupplicant.h"
39
40 #define TIMEOUT 5000
41
42 #define IEEE80211_CAP_ESS       0x0001
43 #define IEEE80211_CAP_IBSS      0x0002
44 #define IEEE80211_CAP_PRIVACY   0x0010
45
46 static DBusConnection *connection;
47
48 static const GSupplicantCallbacks *callbacks_pointer;
49
50 static dbus_bool_t system_available = FALSE;
51 static dbus_bool_t system_ready = FALSE;
52
53 static dbus_int32_t debug_level;
54 static dbus_bool_t debug_timestamp = FALSE;
55 static dbus_bool_t debug_showkeys = FALSE;
56
57 static const char *debug_strings[] = {
58         "msgdump", "debug", "info", "warning", "error", NULL
59 };
60
61 static unsigned int eap_methods;
62
63 struct strvalmap {
64         const char *str;
65         unsigned int val;
66 };
67
68 static struct strvalmap eap_method_map[] = {
69         { "MD5",        G_SUPPLICANT_EAP_METHOD_MD5     },
70         { "TLS",        G_SUPPLICANT_EAP_METHOD_TLS     },
71         { "MSCHAPV2",   G_SUPPLICANT_EAP_METHOD_MSCHAPV2        },
72         { "PEAP",       G_SUPPLICANT_EAP_METHOD_PEAP    },
73         { "TTLS",       G_SUPPLICANT_EAP_METHOD_TTLS    },
74         { "GTC",        G_SUPPLICANT_EAP_METHOD_GTC     },
75         { "OTP",        G_SUPPLICANT_EAP_METHOD_OTP     },
76         { "LEAP",       G_SUPPLICANT_EAP_METHOD_LEAP    },
77         { "WSC",        G_SUPPLICANT_EAP_METHOD_WSC     },
78         { }
79 };
80
81 static struct strvalmap keymgmt_map[] = {
82         { "none",               G_SUPPLICANT_KEYMGMT_NONE               },
83         { "ieee8021x",          G_SUPPLICANT_KEYMGMT_IEEE8021X  },
84         { "wpa-none",           G_SUPPLICANT_KEYMGMT_WPA_NONE   },
85         { "wpa-psk",            G_SUPPLICANT_KEYMGMT_WPA_PSK    },
86         { "wpa-psk-sha256",     G_SUPPLICANT_KEYMGMT_WPA_PSK_256        },
87         { "wpa-ft-psk",         G_SUPPLICANT_KEYMGMT_WPA_FT_PSK },
88         { "wpa-ft-eap",         G_SUPPLICANT_KEYMGMT_WPA_FT_EAP },
89         { "wpa-eap",            G_SUPPLICANT_KEYMGMT_WPA_EAP    },
90         { "wpa-eap-sha256",     G_SUPPLICANT_KEYMGMT_WPA_EAP_256        },
91         { "wps",                G_SUPPLICANT_KEYMGMT_WPS                },
92         { }
93 };
94
95 static struct strvalmap authalg_capa_map[] = {
96         { "open",       G_SUPPLICANT_CAPABILITY_AUTHALG_OPEN    },
97         { "shared",     G_SUPPLICANT_CAPABILITY_AUTHALG_SHARED  },
98         { "leap",       G_SUPPLICANT_CAPABILITY_AUTHALG_LEAP    },
99         { }
100 };
101
102 static struct strvalmap proto_capa_map[] = {
103         { "wpa",        G_SUPPLICANT_CAPABILITY_PROTO_WPA               },
104         { "rsn",        G_SUPPLICANT_CAPABILITY_PROTO_RSN               },
105         { }
106 };
107
108 static struct strvalmap group_map[] = {
109         { "wep40",      G_SUPPLICANT_GROUP_WEP40        },
110         { "wep104",     G_SUPPLICANT_GROUP_WEP104       },
111         { "tkip",       G_SUPPLICANT_GROUP_TKIP },
112         { "ccmp",       G_SUPPLICANT_GROUP_CCMP },
113         { }
114 };
115
116 static struct strvalmap pairwise_map[] = {
117         { "none",       G_SUPPLICANT_PAIRWISE_NONE      },
118         { "tkip",       G_SUPPLICANT_PAIRWISE_TKIP      },
119         { "ccmp",       G_SUPPLICANT_PAIRWISE_CCMP      },
120         { }
121 };
122
123 static struct strvalmap scan_capa_map[] = {
124         { "active",     G_SUPPLICANT_CAPABILITY_SCAN_ACTIVE     },
125         { "passive",    G_SUPPLICANT_CAPABILITY_SCAN_PASSIVE    },
126         { "ssid",       G_SUPPLICANT_CAPABILITY_SCAN_SSID               },
127         { }
128 };
129
130 static struct strvalmap mode_capa_map[] = {
131         { "infrastructure",     G_SUPPLICANT_CAPABILITY_MODE_INFRA      },
132         { "ad-hoc",             G_SUPPLICANT_CAPABILITY_MODE_IBSS       },
133         { "ap",                 G_SUPPLICANT_CAPABILITY_MODE_AP         },
134         { }
135 };
136
137 static GHashTable *interface_table;
138 static GHashTable *bss_mapping;
139
140 struct _GSupplicantInterface {
141         char *path;
142         unsigned int keymgmt_capa;
143         unsigned int authalg_capa;
144         unsigned int proto_capa;
145         unsigned int group_capa;
146         unsigned int pairwise_capa;
147         unsigned int scan_capa;
148         unsigned int mode_capa;
149         dbus_bool_t ready;
150         GSupplicantState state;
151         dbus_bool_t scanning;
152         GSupplicantInterfaceCallback scan_callback;
153         void *scan_data;
154         int apscan;
155         char *ifname;
156         char *driver;
157         char *bridge;
158         GHashTable *network_table;
159         GHashTable *net_mapping;
160         GHashTable *bss_mapping;
161         void *data;
162 };
163
164 struct _GSupplicantNetwork {
165         GSupplicantInterface *interface;
166         char *path;
167         char *group;
168         char *name;
169         unsigned char ssid[32];
170         unsigned int ssid_len;
171         dbus_int16_t signal;
172         GSupplicantMode mode;
173         GSupplicantSecurity security;
174         GHashTable *bss_table;
175         GHashTable *config_table;
176 };
177
178 struct g_supplicant_bss {
179         GSupplicantInterface *interface;
180         char *path;
181         unsigned char bssid[6];
182         unsigned char ssid[32];
183         unsigned int ssid_len;
184         dbus_uint16_t frequency;
185         dbus_uint32_t maxrate;
186         dbus_int16_t signal;
187         GSupplicantMode mode;
188         GSupplicantSecurity security;
189         unsigned int keymgmt;
190         unsigned int pairwise;
191         unsigned int group;
192         dbus_bool_t privacy;
193         dbus_bool_t psk;
194         dbus_bool_t ieee8021x;
195 };
196
197 static GSupplicantMode string2mode(const char *mode)
198 {
199         if (mode == NULL)
200                 return G_SUPPLICANT_MODE_UNKNOWN;
201
202         if (g_str_equal(mode, "infrastructure") == TRUE)
203                 return G_SUPPLICANT_MODE_INFRA;
204         else if (g_str_equal(mode, "ad-hoc") == TRUE)
205                 return G_SUPPLICANT_MODE_IBSS;
206
207         return G_SUPPLICANT_MODE_UNKNOWN;
208 }
209
210 static const char *mode2string(GSupplicantMode mode)
211 {
212         switch (mode) {
213         case G_SUPPLICANT_MODE_UNKNOWN:
214                 break;
215         case G_SUPPLICANT_MODE_INFRA:
216                 return "infra";
217         case G_SUPPLICANT_MODE_IBSS:
218                 return "adhoc";
219         }
220
221         return NULL;
222 }
223
224 static const char *security2string(GSupplicantSecurity security)
225 {
226         switch (security) {
227         case G_SUPPLICANT_SECURITY_UNKNOWN:
228                 break;
229         case G_SUPPLICANT_SECURITY_NONE:
230                 return "none";
231         case G_SUPPLICANT_SECURITY_WEP:
232                 return "wep";
233         case G_SUPPLICANT_SECURITY_PSK:
234                 return "psk";
235         case G_SUPPLICANT_SECURITY_IEEE8021X:
236                 return "ieee8021x";
237         }
238
239         return NULL;
240 }
241
242 static GSupplicantState string2state(const char *state)
243 {
244         if (state == NULL)
245                 return G_SUPPLICANT_STATE_UNKNOWN;
246
247         if (g_str_equal(state, "unknown") == TRUE)
248                 return G_SUPPLICANT_STATE_UNKNOWN;
249         else if (g_str_equal(state, "disconnected") == TRUE)
250                 return G_SUPPLICANT_STATE_DISCONNECTED;
251         else if (g_str_equal(state, "inactive") == TRUE)
252                 return G_SUPPLICANT_STATE_INACTIVE;
253         else if (g_str_equal(state, "scanning") == TRUE)
254                 return G_SUPPLICANT_STATE_SCANNING;
255         else if (g_str_equal(state, "authenticating") == TRUE)
256                 return G_SUPPLICANT_STATE_AUTHENTICATING;
257         else if (g_str_equal(state, "associating") == TRUE)
258                 return G_SUPPLICANT_STATE_ASSOCIATING;
259         else if (g_str_equal(state, "associated") == TRUE)
260                 return G_SUPPLICANT_STATE_ASSOCIATED;
261         else if (g_str_equal(state, "group_handshake") == TRUE)
262                 return G_SUPPLICANT_STATE_GROUP_HANDSHAKE;
263         else if (g_str_equal(state, "4way_handshake") == TRUE)
264                 return G_SUPPLICANT_STATE_4WAY_HANDSHAKE;
265         else if (g_str_equal(state, "completed") == TRUE)
266                 return G_SUPPLICANT_STATE_COMPLETED;
267
268         return G_SUPPLICANT_STATE_UNKNOWN;
269 }
270
271 static void callback_system_ready(void)
272 {
273         if (system_ready == TRUE)
274                 return;
275
276         system_ready = TRUE;
277
278         if (callbacks_pointer == NULL)
279                 return;
280
281         if (callbacks_pointer->system_ready == NULL)
282                 return;
283
284         callbacks_pointer->system_ready();
285 }
286
287 static void callback_system_killed(void)
288 {
289         system_ready = FALSE;
290
291         if (callbacks_pointer == NULL)
292                 return;
293
294         if (callbacks_pointer->system_killed == NULL)
295                 return;
296
297         callbacks_pointer->system_killed();
298 }
299
300 static void callback_interface_added(GSupplicantInterface *interface)
301 {
302         DBG("");
303
304         if (callbacks_pointer == NULL)
305                 return;
306
307         if (callbacks_pointer->interface_added == NULL)
308                 return;
309
310         callbacks_pointer->interface_added(interface);
311 }
312
313 static void callback_interface_state(GSupplicantInterface *interface)
314 {
315         if (callbacks_pointer == NULL)
316                 return;
317
318         if (callbacks_pointer->interface_state == NULL)
319                 return;
320
321         callbacks_pointer->interface_state(interface);
322 }
323
324 static void callback_interface_removed(GSupplicantInterface *interface)
325 {
326         if (callbacks_pointer == NULL)
327                 return;
328
329         if (callbacks_pointer->interface_removed == NULL)
330                 return;
331
332         callbacks_pointer->interface_removed(interface);
333 }
334
335 static void callback_scan_started(GSupplicantInterface *interface)
336 {
337         if (callbacks_pointer == NULL)
338                 return;
339
340         if (callbacks_pointer->scan_started == NULL)
341                 return;
342
343         callbacks_pointer->scan_started(interface);
344 }
345
346 static void callback_scan_finished(GSupplicantInterface *interface)
347 {
348         if (callbacks_pointer == NULL)
349                 return;
350
351         if (callbacks_pointer->scan_finished == NULL)
352                 return;
353
354         callbacks_pointer->scan_finished(interface);
355 }
356
357 static void callback_network_added(GSupplicantNetwork *network)
358 {
359         if (callbacks_pointer == NULL)
360                 return;
361
362         if (callbacks_pointer->network_added == NULL)
363                 return;
364
365         callbacks_pointer->network_added(network);
366 }
367
368 static void callback_network_removed(GSupplicantNetwork *network)
369 {
370         if (callbacks_pointer == NULL)
371                 return;
372
373         if (callbacks_pointer->network_removed == NULL)
374                 return;
375
376         callbacks_pointer->network_removed(network);
377 }
378
379 static void remove_interface(gpointer data)
380 {
381         GSupplicantInterface *interface = data;
382
383         g_hash_table_destroy(interface->bss_mapping);
384         g_hash_table_destroy(interface->net_mapping);
385         g_hash_table_destroy(interface->network_table);
386
387         callback_interface_removed(interface);
388
389         g_free(interface->path);
390         g_free(interface->ifname);
391         g_free(interface->driver);
392         g_free(interface->bridge);
393         g_free(interface);
394 }
395
396 static void remove_network(gpointer data)
397 {
398         GSupplicantNetwork *network = data;
399
400         g_hash_table_destroy(network->bss_table);
401
402         callback_network_removed(network);
403
404         g_hash_table_destroy(network->config_table);
405
406         g_free(network->group);
407         g_free(network->name);
408         g_free(network);
409 }
410
411 static void remove_bss(gpointer data)
412 {
413         struct g_supplicant_bss *bss = data;
414
415         g_free(bss->path);
416         g_free(bss);
417 }
418
419 static void debug_strvalmap(const char *label, struct strvalmap *map,
420                                                         unsigned int val)
421 {
422         int i;
423
424         for (i = 0; map[i].str != NULL; i++) {
425                 if (val & map[i].val)
426                         DBG("%s: %s", label, map[i].str);
427         }
428 }
429
430 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
431 {
432         GSupplicantInterface *interface = user_data;
433         const char *str = NULL;
434         int i;
435
436         dbus_message_iter_get_basic(iter, &str);
437         if (str == NULL)
438                 return;
439
440         for (i = 0; keymgmt_map[i].str != NULL; i++)
441                 if (strcmp(str, keymgmt_map[i].str) == 0) {
442                         interface->keymgmt_capa |= keymgmt_map[i].val;
443                         break;
444                 }
445 }
446
447 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
448 {
449         GSupplicantInterface *interface = user_data;
450         const char *str = NULL;
451         int i;
452
453         dbus_message_iter_get_basic(iter, &str);
454         if (str == NULL)
455                 return;
456
457         for (i = 0; authalg_capa_map[i].str != NULL; i++)
458                 if (strcmp(str, authalg_capa_map[i].str) == 0) {
459                         interface->authalg_capa |= authalg_capa_map[i].val;
460                         break;
461                 }
462 }
463
464 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
465 {
466         GSupplicantInterface *interface = user_data;
467         const char *str = NULL;
468         int i;
469
470         dbus_message_iter_get_basic(iter, &str);
471         if (str == NULL)
472                 return;
473
474         for (i = 0; proto_capa_map[i].str != NULL; i++)
475                 if (strcmp(str, proto_capa_map[i].str) == 0) {
476                         interface->proto_capa |= proto_capa_map[i].val;
477                         break;
478                 }
479 }
480
481 static void interface_capability_pairwise(DBusMessageIter *iter,
482                                                         void *user_data)
483 {
484         GSupplicantInterface *interface = user_data;
485         const char *str = NULL;
486         int i;
487
488         dbus_message_iter_get_basic(iter, &str);
489         if (str == NULL)
490                 return;
491
492         for (i = 0; pairwise_map[i].str != NULL; i++)
493                 if (strcmp(str, pairwise_map[i].str) == 0) {
494                         interface->pairwise_capa |= pairwise_map[i].val;
495                         break;
496                 }
497 }
498
499 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
500 {
501         GSupplicantInterface *interface = user_data;
502         const char *str = NULL;
503         int i;
504
505         dbus_message_iter_get_basic(iter, &str);
506         if (str == NULL)
507                 return;
508
509         for (i = 0; group_map[i].str != NULL; i++)
510                 if (strcmp(str, group_map[i].str) == 0) {
511                         interface->group_capa |= group_map[i].val;
512                         break;
513                 }
514 }
515
516 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
517 {
518         GSupplicantInterface *interface = user_data;
519         const char *str = NULL;
520         int i;
521
522         dbus_message_iter_get_basic(iter, &str);
523         if (str == NULL)
524                 return;
525
526         for (i = 0; scan_capa_map[i].str != NULL; i++)
527                 if (strcmp(str, scan_capa_map[i].str) == 0) {
528                         interface->scan_capa |= scan_capa_map[i].val;
529                         break;
530                 }
531 }
532
533 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
534 {
535         GSupplicantInterface *interface = user_data;
536         const char *str = NULL;
537         int i;
538
539         dbus_message_iter_get_basic(iter, &str);
540         if (str == NULL)
541                 return;
542
543         for (i = 0; mode_capa_map[i].str != NULL; i++)
544                 if (strcmp(str, mode_capa_map[i].str) == 0) {
545                         interface->mode_capa |= mode_capa_map[i].val;
546                         break;
547                 }
548 }
549
550 static void interface_capability(const char *key, DBusMessageIter *iter,
551                                                         void *user_data)
552 {
553         GSupplicantInterface *interface = user_data;
554
555         if (key == NULL)
556                 return;
557
558         if (g_strcmp0(key, "KeyMgmt") == 0)
559                 supplicant_dbus_array_foreach(iter,
560                                 interface_capability_keymgmt, interface);
561         else if (g_strcmp0(key, "AuthAlg") == 0)
562                 supplicant_dbus_array_foreach(iter,
563                                 interface_capability_authalg, interface);
564         else if (g_strcmp0(key, "Protocol") == 0)
565                 supplicant_dbus_array_foreach(iter,
566                                 interface_capability_proto, interface);
567         else if (g_strcmp0(key, "Pairwise") == 0)
568                 supplicant_dbus_array_foreach(iter,
569                                 interface_capability_pairwise, interface);
570         else if (g_strcmp0(key, "Group") == 0)
571                 supplicant_dbus_array_foreach(iter,
572                                 interface_capability_group, interface);
573         else if (g_strcmp0(key, "Scan") == 0)
574                 supplicant_dbus_array_foreach(iter,
575                                 interface_capability_scan, interface);
576         else if (g_strcmp0(key, "Modes") == 0)
577                 supplicant_dbus_array_foreach(iter,
578                                 interface_capability_mode, interface);
579         else
580                 DBG("key %s type %c",
581                                 key, dbus_message_iter_get_arg_type(iter));
582 }
583
584 void g_supplicant_interface_set_data(GSupplicantInterface *interface,
585                                                                 void *data)
586 {
587         if (interface == NULL)
588                 return;
589
590         interface->data = data;
591 }
592
593 const void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
594 {
595         if (interface == NULL)
596                 return NULL;
597
598         return interface->data;
599 }
600
601 const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface)
602 {
603         if (interface == NULL)
604                 return NULL;
605
606         return interface->ifname;
607 }
608
609 const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface)
610 {
611         if (interface == NULL)
612                 return NULL;
613
614         return interface->driver;
615 }
616
617 GSupplicantState g_supplicant_interface_get_state(
618                                         GSupplicantInterface *interface)
619 {
620         if (interface == NULL)
621                 return G_SUPPLICANT_STATE_UNKNOWN;
622
623         return interface->state;
624 }
625
626 GSupplicantInterface *g_supplicant_network_get_interface(
627                                         GSupplicantNetwork *network)
628 {
629         if (network == NULL)
630                 return NULL;
631
632         return network->interface;
633 }
634
635 const char *g_supplicant_network_get_name(GSupplicantNetwork *network)
636 {
637         if (network == NULL || network->name == NULL)
638                 return "";
639
640         return network->name;
641 }
642
643 const char *g_supplicant_network_get_identifier(GSupplicantNetwork *network)
644 {
645         if (network == NULL || network->group == NULL)
646                 return "";
647
648         return network->group;
649 }
650
651 const char *g_supplicant_network_get_path(GSupplicantNetwork *network)
652 {
653         if (network == NULL || network->path == NULL)
654                 return NULL;
655
656         return network->path;
657 }
658
659 const char *g_supplicant_network_get_mode(GSupplicantNetwork *network)
660 {
661         if (network == NULL)
662                 return G_SUPPLICANT_MODE_UNKNOWN;
663
664         return mode2string(network->mode);
665 }
666
667 const char *g_supplicant_network_get_security(GSupplicantNetwork *network)
668 {
669         if (network == NULL)
670                 return G_SUPPLICANT_SECURITY_UNKNOWN;
671
672         return security2string(network->security);
673 }
674
675 const void *g_supplicant_network_get_ssid(GSupplicantNetwork *network,
676                                                 unsigned int *ssid_len)
677 {
678         if (network == NULL || network->ssid == NULL) {
679                 *ssid_len = 0;
680                 return NULL;
681         }
682
683         *ssid_len = network->ssid_len;
684         return network->ssid;
685 }
686
687 dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network)
688 {
689         if (network == NULL)
690                 return 0;
691
692         return network->signal;
693 }
694
695 static void merge_network(GSupplicantNetwork *network)
696 {
697         GString *str;
698         const char *ssid, *mode, *key_mgmt;
699         unsigned int i, ssid_len;
700         char *group;
701
702         ssid = g_hash_table_lookup(network->config_table, "ssid");
703         mode = g_hash_table_lookup(network->config_table, "mode");
704         key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
705
706         DBG("ssid %s mode %s", ssid, mode);
707
708         if (ssid != NULL)
709                 ssid_len = strlen(ssid);
710         else
711                 ssid_len = 0;
712
713         str = g_string_sized_new((ssid_len * 2) + 24);
714         if (str == NULL)
715                 return;
716
717         for (i = 0; i < ssid_len; i++)
718                 g_string_append_printf(str, "%02x", ssid[i]);
719
720         if (g_strcmp0(mode, "0") == 0)
721                 g_string_append_printf(str, "_infra");
722         else if (g_strcmp0(mode, "1") == 0)
723                 g_string_append_printf(str, "_adhoc");
724
725         if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
726                 g_string_append_printf(str, "_psk");
727
728         group = g_string_free(str, FALSE);
729
730         DBG("%s", group);
731
732         g_free(group);
733
734         g_hash_table_destroy(network->config_table);
735
736         g_free(network->path);
737         g_free(network);
738 }
739
740 static void network_property(const char *key, DBusMessageIter *iter,
741                                                         void *user_data)
742 {
743         GSupplicantNetwork *network = user_data;
744
745         if (network->interface == NULL)
746                 return;
747
748         if (key == NULL) {
749                 merge_network(network);
750                 return;
751         }
752
753         if (g_strcmp0(key, "Enabled") == 0) {
754                 dbus_bool_t enabled = FALSE;
755
756                 dbus_message_iter_get_basic(iter, &enabled);
757         } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
758                 const char *str = NULL;
759
760                 dbus_message_iter_get_basic(iter, &str);
761                 if (str != NULL) {
762                         g_hash_table_replace(network->config_table,
763                                                 g_strdup(key), g_strdup(str));
764                 }
765         } else
766                 DBG("key %s type %c",
767                                 key, dbus_message_iter_get_arg_type(iter));
768 }
769
770 static void interface_network_added(DBusMessageIter *iter, void *user_data)
771 {
772         GSupplicantInterface *interface = user_data;
773         GSupplicantNetwork *network;
774         const char *path = NULL;
775
776         DBG("");
777
778         dbus_message_iter_get_basic(iter, &path);
779         if (path == NULL)
780                 return;
781
782         if (g_strcmp0(path, "/") == 0)
783                 return;
784
785         network = g_hash_table_lookup(interface->net_mapping, path);
786         if (network != NULL)
787                 return;
788
789         network = g_try_new0(GSupplicantNetwork, 1);
790         if (network == NULL)
791                 return;
792
793         network->interface = interface;
794         network->path = g_strdup(path);
795
796         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
797                                                         g_free, g_free);
798
799         dbus_message_iter_next(iter);
800         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
801                 supplicant_dbus_property_foreach(iter, network_property,
802                                                                 network);
803                 network_property(NULL, NULL, network);
804                 return;
805         }
806
807         supplicant_dbus_property_get_all(path,
808                                 SUPPLICANT_INTERFACE ".Interface.Network",
809                                                 network_property, network);
810 }
811
812 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
813 {
814         GSupplicantInterface *interface = user_data;
815         GSupplicantNetwork *network;
816         const char *path = NULL;
817
818         dbus_message_iter_get_basic(iter, &path);
819         if (path == NULL)
820                 return;
821
822         network = g_hash_table_lookup(interface->net_mapping, path);
823         if (network == NULL)
824                 return;
825
826         g_hash_table_remove(interface->net_mapping, path);
827 }
828
829 static char *create_name(unsigned char *ssid, int ssid_len)
830 {
831         char *name;
832         int i;
833
834         if (ssid_len < 1 || ssid[0] == '\0')
835                 name = NULL;
836         else
837                 name = g_try_malloc0(ssid_len + 1);
838
839         if (name == NULL)
840                 return g_strdup("");
841
842         for (i = 0; i < ssid_len; i++) {
843                 if (g_ascii_isprint(ssid[i]))
844                         name[i] = ssid[i];
845                 else
846                         name[i] = ' ';
847         }
848
849         return name;
850 }
851
852 static char *create_group(struct g_supplicant_bss *bss)
853 {
854         GString *str;
855         unsigned int i;
856         const char *mode, *security;
857
858         str = g_string_sized_new((bss->ssid_len * 2) + 24);
859         if (str == NULL)
860                 return NULL;
861
862         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
863                 for (i = 0; i < bss->ssid_len; i++)
864                         g_string_append_printf(str, "%02x", bss->ssid[i]);
865         } else
866                 g_string_append_printf(str, "hidden");
867
868         mode = mode2string(bss->mode);
869         if (mode != NULL)
870                 g_string_append_printf(str, "_%s", mode);
871
872         security = security2string(bss->security);
873         if (security != NULL)
874                 g_string_append_printf(str, "_%s", security);
875
876         return g_string_free(str, FALSE);
877 }
878
879 static void add_bss_to_network(struct g_supplicant_bss *bss)
880 {
881         GSupplicantInterface *interface = bss->interface;
882         GSupplicantNetwork *network;
883         char *group;
884
885         group = create_group(bss);
886         if (group == NULL)
887                 return;
888
889         network = g_hash_table_lookup(interface->network_table, group);
890         if (network != NULL) {
891                 g_free(group);
892                 goto done;
893         }
894
895         network = g_try_new0(GSupplicantNetwork, 1);
896         if (network == NULL) {
897                 g_free(group);
898                 return;
899         }
900
901         network->interface = interface;
902         if (network->path == NULL)
903                 network->path = g_strdup(bss->path);
904         network->group = group;
905         network->name = create_name(bss->ssid, bss->ssid_len);
906         network->mode = bss->mode;
907         network->security = bss->security;
908         network->ssid_len = bss->ssid_len;
909         memcpy(network->ssid, bss->ssid, bss->ssid_len);
910         network->signal = bss->signal;
911
912         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
913                                                         NULL, remove_bss);
914
915         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
916                                                         g_free, g_free);
917
918         g_hash_table_replace(interface->network_table,
919                                                 network->group, network);
920
921         callback_network_added(network);
922
923 done:
924         g_hash_table_replace(interface->bss_mapping, bss->path, network);
925         g_hash_table_replace(network->bss_table, bss->path, bss);
926
927         g_hash_table_replace(bss_mapping, bss->path, interface);
928 }
929
930 static void bss_rates(DBusMessageIter *iter, void *user_data)
931 {
932         struct g_supplicant_bss *bss = user_data;
933         dbus_uint32_t rate = 0;
934
935         dbus_message_iter_get_basic(iter, &rate);
936         if (rate == 0)
937                 return;
938
939         if (rate > bss->maxrate)
940                 bss->maxrate = rate;
941 }
942
943 static void bss_keymgmt(DBusMessageIter *iter, void *user_data)
944 {
945         struct g_supplicant_bss *bss = user_data;
946         const char *str = NULL;
947         int i;
948
949         dbus_message_iter_get_basic(iter, &str);
950         if (str == NULL)
951                 return;
952
953         for (i = 0; keymgmt_map[i].str != NULL; i++)
954                 if (strcmp(str, keymgmt_map[i].str) == 0) {
955                         bss->keymgmt |= keymgmt_map[i].val;
956                         break;
957                 }
958 }
959
960 static void bss_group(DBusMessageIter *iter, void *user_data)
961 {
962         struct g_supplicant_bss *bss = user_data;
963         const char *str = NULL;
964         int i;
965
966         dbus_message_iter_get_basic(iter, &str);
967         if (str == NULL)
968                 return;
969
970         for (i = 0; group_map[i].str != NULL; i++)
971                 if (strcmp(str, group_map[i].str) == 0) {
972                         bss->group |= group_map[i].val;
973                         break;
974                 }
975 }
976
977 static void bss_pairwise(DBusMessageIter *iter, void *user_data)
978 {
979         struct g_supplicant_bss *bss = user_data;
980         const char *str = NULL;
981         int i;
982
983         dbus_message_iter_get_basic(iter, &str);
984         if (str == NULL)
985                 return;
986
987         for (i = 0; pairwise_map[i].str != NULL; i++)
988                 if (strcmp(str, pairwise_map[i].str) == 0) {
989                         bss->pairwise |= pairwise_map[i].val;
990                         break;
991                 }
992 }
993
994 static void bss_wpa(const char *key, DBusMessageIter *iter,
995                         void *user_data)
996 {
997         if (g_strcmp0(key, "KeyMgmt") == 0)
998                 supplicant_dbus_array_foreach(iter, bss_keymgmt, user_data);
999         else if (g_strcmp0(key, "Group") == 0)
1000                 supplicant_dbus_array_foreach(iter, bss_group, user_data);
1001         else if (g_strcmp0(key, "Pairwise") == 0)
1002                 supplicant_dbus_array_foreach(iter, bss_pairwise, user_data);
1003
1004 }
1005
1006
1007 static void bss_property(const char *key, DBusMessageIter *iter,
1008                                                         void *user_data)
1009 {
1010         struct g_supplicant_bss *bss = user_data;
1011
1012         if (bss->interface == NULL)
1013                 return;
1014
1015         DBG("key %s", key);
1016
1017         if (key == NULL) {
1018                 if (bss->ieee8021x == TRUE)
1019                         bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
1020                 else if (bss->psk == TRUE)
1021                         bss->security = G_SUPPLICANT_SECURITY_PSK;
1022                 else if (bss->privacy == TRUE)
1023                         bss->security = G_SUPPLICANT_SECURITY_WEP;
1024                 else
1025                         bss->security = G_SUPPLICANT_SECURITY_NONE;
1026
1027                 add_bss_to_network(bss);
1028                 return;
1029         }
1030
1031         if (g_strcmp0(key, "BSSID") == 0) {
1032                 DBusMessageIter array;
1033                 unsigned char *addr;
1034                 int addr_len;
1035
1036                 dbus_message_iter_recurse(iter, &array);
1037                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
1038
1039                 if (addr_len == 6)
1040                         memcpy(bss->bssid, addr, addr_len);
1041         } else if (g_strcmp0(key, "SSID") == 0) {
1042                 DBusMessageIter array;
1043                 unsigned char *ssid;
1044                 int ssid_len;
1045
1046                 dbus_message_iter_recurse(iter, &array);
1047                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
1048
1049                 if (ssid_len > 0 && ssid_len < 33) {
1050                         memcpy(bss->ssid, ssid, ssid_len);
1051                         bss->ssid_len = ssid_len;
1052                 } else {
1053                         memset(bss->ssid, 0, sizeof(bss->ssid));
1054                         bss->ssid_len = 0;
1055                 }
1056         } else if (g_strcmp0(key, "Capabilities") == 0) {
1057                 dbus_uint16_t capabilities = 0x0000;
1058
1059                 dbus_message_iter_get_basic(iter, &capabilities);
1060
1061                 if (capabilities & IEEE80211_CAP_ESS)
1062                         bss->mode = G_SUPPLICANT_MODE_INFRA;
1063                 else if (capabilities & IEEE80211_CAP_IBSS)
1064                         bss->mode = G_SUPPLICANT_MODE_IBSS;
1065
1066                 if (capabilities & IEEE80211_CAP_PRIVACY)
1067                         bss->privacy = TRUE;
1068         } else if (g_strcmp0(key, "Mode") == 0) {
1069                 const char *mode = NULL;
1070
1071                 dbus_message_iter_get_basic(iter, &mode);
1072                 bss->mode = string2mode(mode);
1073         } else if (g_strcmp0(key, "Frequency") == 0) {
1074                 dbus_uint16_t frequency = 0;
1075
1076                 dbus_message_iter_get_basic(iter, &frequency);
1077                 bss->frequency = frequency;
1078         } else if (g_strcmp0(key, "Signal") == 0) {
1079                 dbus_int16_t signal = 0;
1080
1081                 dbus_message_iter_get_basic(iter, &signal);
1082
1083                 bss->signal = signal;
1084         } else if (g_strcmp0(key, "Level") == 0) {
1085                 dbus_int32_t level = 0;
1086
1087                 dbus_message_iter_get_basic(iter, &level);
1088         } else if (g_strcmp0(key, "Rates") == 0) {
1089                 supplicant_dbus_array_foreach(iter, bss_rates, bss);
1090         } else if (g_strcmp0(key, "MaxRate") == 0) {
1091                 dbus_uint32_t maxrate = 0;
1092
1093                 dbus_message_iter_get_basic(iter, &maxrate);
1094                 if (maxrate != 0)
1095                         bss->maxrate = maxrate;
1096         } else if (g_strcmp0(key, "Privacy") == 0) {
1097                 dbus_bool_t privacy = FALSE;
1098
1099                 dbus_message_iter_get_basic(iter, &privacy);
1100                 bss->privacy = privacy;
1101         } else if ((g_strcmp0(key, "RSN") == 0) ||
1102                         (g_strcmp0(key, "WPA") == 0)) {
1103                 supplicant_dbus_property_foreach(iter, bss_wpa, bss);
1104
1105                 if (bss->keymgmt &
1106                         (G_SUPPLICANT_KEYMGMT_WPA_EAP |
1107                                 G_SUPPLICANT_KEYMGMT_WPA_FT_EAP |
1108                                 G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
1109                         bss->ieee8021x = TRUE;
1110
1111                 if (bss->keymgmt &
1112                         (G_SUPPLICANT_KEYMGMT_WPA_PSK |
1113                                 G_SUPPLICANT_KEYMGMT_WPA_FT_PSK |
1114                                 G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
1115                         bss->psk = TRUE;
1116         } else
1117                 DBG("key %s type %c",
1118                                 key, dbus_message_iter_get_arg_type(iter));
1119 }
1120
1121 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
1122 {
1123         GSupplicantInterface *interface = user_data;
1124         GSupplicantNetwork *network;
1125         struct g_supplicant_bss *bss;
1126         const char *path = NULL;
1127
1128         DBG("");
1129
1130         dbus_message_iter_get_basic(iter, &path);
1131         if (path == NULL)
1132                 return;
1133
1134         if (g_strcmp0(path, "/") == 0)
1135                 return;
1136
1137         DBG("%s", path);
1138
1139         network = g_hash_table_lookup(interface->bss_mapping, path);
1140         if (network != NULL) {
1141                 bss = g_hash_table_lookup(network->bss_table, path);
1142                 if (bss != NULL)
1143                         return;
1144         }
1145
1146         bss = g_try_new0(struct g_supplicant_bss, 1);
1147         if (bss == NULL)
1148                 return;
1149
1150         bss->interface = interface;
1151         bss->path = g_strdup(path);
1152
1153         dbus_message_iter_next(iter);
1154         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1155                 supplicant_dbus_property_foreach(iter, bss_property, bss);
1156                 bss_property(NULL, NULL, bss);
1157                 return;
1158         }
1159
1160         supplicant_dbus_property_get_all(path,
1161                                         SUPPLICANT_INTERFACE ".Interface.BSS",
1162                                                         bss_property, bss);
1163 }
1164
1165 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
1166 {
1167         GSupplicantInterface *interface = user_data;
1168         GSupplicantNetwork *network;
1169         const char *path = NULL;
1170
1171         dbus_message_iter_get_basic(iter, &path);
1172         if (path == NULL)
1173                 return;
1174
1175         network = g_hash_table_lookup(interface->bss_mapping, path);
1176         if (network == NULL)
1177                 return;
1178
1179         g_hash_table_remove(bss_mapping, path);
1180
1181         g_hash_table_remove(interface->bss_mapping, path);
1182         g_hash_table_remove(network->bss_table, path);
1183
1184         if (g_hash_table_size(network->bss_table) == 0)
1185                 g_hash_table_remove(interface->network_table, network->group);
1186 }
1187
1188 static void interface_property(const char *key, DBusMessageIter *iter,
1189                                                         void *user_data)
1190 {
1191         GSupplicantInterface *interface = user_data;
1192
1193         if (interface == NULL)
1194                 return;
1195
1196         DBG("%s", key);
1197
1198         if (key == NULL) {
1199                 debug_strvalmap("KeyMgmt capability", keymgmt_map,
1200                                                 interface->keymgmt_capa);
1201                 debug_strvalmap("AuthAlg capability", authalg_capa_map,
1202                                                 interface->authalg_capa);
1203                 debug_strvalmap("Protocol capability", proto_capa_map,
1204                                                 interface->proto_capa);
1205                 debug_strvalmap("Pairwise capability", pairwise_map,
1206                                                 interface->pairwise_capa);
1207                 debug_strvalmap("Group capability", group_map,
1208                                                 interface->group_capa);
1209                 debug_strvalmap("Scan capability", scan_capa_map,
1210                                                 interface->scan_capa);
1211                 debug_strvalmap("Mode capability", mode_capa_map,
1212                                                 interface->mode_capa);
1213
1214                 interface->ready = TRUE;
1215                 callback_interface_added(interface);
1216                 return;
1217         }
1218
1219         if (g_strcmp0(key, "Capabilities") == 0) {
1220                 supplicant_dbus_property_foreach(iter, interface_capability,
1221                                                                 interface);
1222         } else if (g_strcmp0(key, "State") == 0) {
1223                 const char *str = NULL;
1224
1225                 dbus_message_iter_get_basic(iter, &str);
1226                 if (str != NULL)
1227                         if (string2state(str) != interface->state) {
1228                                 interface->state = string2state(str);
1229                                 callback_interface_state(interface);
1230                         }
1231
1232                 DBG("state %s (%d)", str, interface->state);
1233         } else if (g_strcmp0(key, "Scanning") == 0) {
1234                 dbus_bool_t scanning = FALSE;
1235
1236                 dbus_message_iter_get_basic(iter, &scanning);
1237                 interface->scanning = scanning;
1238
1239                 if (interface->ready == TRUE) {
1240                         if (interface->scanning == TRUE)
1241                                 callback_scan_started(interface);
1242                         else
1243                                 callback_scan_finished(interface);
1244                 }
1245         } else if (g_strcmp0(key, "ApScan") == 0) {
1246                 int apscan = 1;
1247
1248                 dbus_message_iter_get_basic(iter, &apscan);
1249                 interface->apscan = apscan;
1250         } else if (g_strcmp0(key, "Ifname") == 0) {
1251                 const char *str = NULL;
1252
1253                 dbus_message_iter_get_basic(iter, &str);
1254                 if (str != NULL)
1255                         interface->ifname = g_strdup(str);
1256         } else if (g_strcmp0(key, "Driver") == 0) {
1257                 const char *str = NULL;
1258
1259                 dbus_message_iter_get_basic(iter, &str);
1260                 if (str != NULL)
1261                         interface->driver = g_strdup(str);
1262         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1263                 const char *str = NULL;
1264
1265                 dbus_message_iter_get_basic(iter, &str);
1266                 if (str != NULL)
1267                         interface->bridge = g_strdup(str);
1268         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1269                 interface_bss_added(iter, interface);
1270         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1271                 interface_network_added(iter, interface);
1272         } else if (g_strcmp0(key, "BSSs") == 0) {
1273                 supplicant_dbus_array_foreach(iter, interface_bss_added,
1274                                                                 interface);
1275         } else if (g_strcmp0(key, "Blobs") == 0) {
1276                 /* Nothing */
1277         } else if (g_strcmp0(key, "Networks") == 0) {
1278                 supplicant_dbus_array_foreach(iter, interface_network_added,
1279                                                                 interface);
1280         } else
1281                 DBG("key %s type %c",
1282                                 key, dbus_message_iter_get_arg_type(iter));
1283 }
1284
1285 static GSupplicantInterface *interface_alloc(const char *path)
1286 {
1287         GSupplicantInterface *interface;
1288
1289         interface = g_try_new0(GSupplicantInterface, 1);
1290         if (interface == NULL)
1291                 return NULL;
1292
1293         interface->path = g_strdup(path);
1294
1295         interface->network_table = g_hash_table_new_full(g_str_hash,
1296                                         g_str_equal, NULL, remove_network);
1297
1298         interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1299                                                                 NULL, NULL);
1300         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1301                                                                 NULL, NULL);
1302
1303         g_hash_table_replace(interface_table, interface->path, interface);
1304
1305         return interface;
1306 }
1307
1308 static void interface_added(DBusMessageIter *iter, void *user_data)
1309 {
1310         GSupplicantInterface *interface;
1311         const char *path = NULL;
1312
1313         DBG("");
1314
1315         dbus_message_iter_get_basic(iter, &path);
1316         if (path == NULL)
1317                 return;
1318
1319         if (g_strcmp0(path, "/") == 0)
1320                 return;
1321
1322         interface = g_hash_table_lookup(interface_table, path);
1323         if (interface != NULL)
1324                 return;
1325
1326         interface = interface_alloc(path);
1327         if (interface == NULL)
1328                 return;
1329
1330         dbus_message_iter_next(iter);
1331         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1332                 supplicant_dbus_property_foreach(iter, interface_property,
1333                                                                 interface);
1334                 DBG("NULL prop");
1335                 interface_property(NULL, NULL, interface);
1336                 DBG("DONE");
1337                 return;
1338         }
1339
1340         supplicant_dbus_property_get_all(path,
1341                                         SUPPLICANT_INTERFACE ".Interface",
1342                                                 interface_property, interface);
1343 }
1344
1345 static void interface_removed(DBusMessageIter *iter, void *user_data)
1346 {
1347         const char *path = NULL;
1348
1349         dbus_message_iter_get_basic(iter, &path);
1350         if (path == NULL)
1351                 return;
1352
1353         g_hash_table_remove(interface_table, path);
1354 }
1355
1356 static void eap_method(DBusMessageIter *iter, void *user_data)
1357 {
1358         const char *str = NULL;
1359         int i;
1360
1361         dbus_message_iter_get_basic(iter, &str);
1362         if (str == NULL)
1363                 return;
1364
1365         for (i = 0; eap_method_map[i].str != NULL; i++)
1366                 if (strcmp(str, eap_method_map[i].str) == 0) {
1367                         eap_methods |= eap_method_map[i].val;
1368                         break;
1369                 }
1370 }
1371
1372 static void service_property(const char *key, DBusMessageIter *iter,
1373                                                         void *user_data)
1374 {
1375         if (key == NULL) {
1376                 callback_system_ready();
1377                 return;
1378         }
1379
1380         if (g_strcmp0(key, "DebugLevel") == 0) {
1381                 const char *str = NULL;
1382                 int i;
1383
1384                 dbus_message_iter_get_basic(iter, &str);
1385                 for (i = 0; debug_strings[i] != NULL; i++)
1386                         if (g_strcmp0(debug_strings[i], str) == 0) {
1387                                 debug_level = i;
1388                                 break;
1389                         }
1390                 DBG("Debug level %d", debug_level);
1391         } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
1392                 dbus_message_iter_get_basic(iter, &debug_timestamp);
1393                 DBG("Debug timestamp %u", debug_timestamp);
1394         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1395                 dbus_message_iter_get_basic(iter, &debug_showkeys);
1396                 DBG("Debug show keys %u", debug_showkeys);
1397         } else if (g_strcmp0(key, "Interfaces") == 0) {
1398                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1399         } else if (g_strcmp0(key, "EapMethods") == 0) {
1400                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1401                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1402         } else
1403                 DBG("key %s type %c",
1404                                 key, dbus_message_iter_get_arg_type(iter));
1405 }
1406
1407 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1408 {
1409         const char *name = NULL, *old = NULL, *new = NULL;
1410
1411         DBG("");
1412
1413         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1414                 return;
1415
1416         dbus_message_iter_get_basic(iter, &name);
1417         if (name == NULL)
1418                 return;
1419
1420         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1421                 return;
1422
1423         dbus_message_iter_next(iter);
1424         dbus_message_iter_get_basic(iter, &old);
1425         dbus_message_iter_next(iter);
1426         dbus_message_iter_get_basic(iter, &new);
1427
1428         if (old == NULL || new == NULL)
1429                 return;
1430
1431         if (strlen(old) > 0 && strlen(new) == 0) {
1432                 system_available = FALSE;
1433                 g_hash_table_remove_all(bss_mapping);
1434                 g_hash_table_remove_all(interface_table);
1435                 callback_system_killed();
1436         }
1437
1438         if (strlen(new) > 0 && strlen(old) == 0) {
1439                 system_available = TRUE;
1440                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1441                                                         SUPPLICANT_INTERFACE,
1442                                                         service_property, NULL);
1443         }
1444 }
1445
1446 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1447 {
1448         DBG("");
1449
1450         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1451                 return;
1452
1453         supplicant_dbus_property_foreach(iter, service_property, NULL);
1454 }
1455
1456 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1457 {
1458         DBG("path %s %s", path, SUPPLICANT_PATH);
1459
1460         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1461                 interface_added(iter, NULL);
1462 }
1463
1464 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1465 {
1466         DBG("");
1467
1468         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1469                 interface_removed(iter, NULL);
1470 }
1471
1472 static void signal_interface_changed(const char *path, DBusMessageIter *iter)
1473 {
1474         GSupplicantInterface *interface;
1475
1476         DBG("");
1477
1478         interface = g_hash_table_lookup(interface_table, path);
1479         if (interface == NULL)
1480                 return;
1481
1482         supplicant_dbus_property_foreach(iter, interface_property, interface);
1483 }
1484
1485 static void signal_scan_done(const char *path, DBusMessageIter *iter)
1486 {
1487         GSupplicantInterface *interface;
1488         dbus_bool_t success = FALSE;
1489
1490         DBG("");
1491
1492         interface = g_hash_table_lookup(interface_table, path);
1493         if (interface == NULL)
1494                 return;
1495
1496         dbus_message_iter_get_basic(iter, &success);
1497
1498         if (interface->scan_callback != NULL) {
1499                 int result = 0;
1500
1501                 if (success == FALSE)
1502                         result = -EIO;
1503
1504                 interface->scan_callback(result, interface,
1505                                                 interface->scan_data);
1506         }
1507
1508         interface->scan_callback = NULL;
1509         interface->scan_data = NULL;
1510 }
1511
1512 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1513 {
1514         GSupplicantInterface *interface;
1515
1516         DBG("");
1517
1518         interface = g_hash_table_lookup(interface_table, path);
1519         if (interface == NULL)
1520                 return;
1521
1522         interface_bss_added(iter, interface);
1523 }
1524
1525 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1526 {
1527         GSupplicantInterface *interface;
1528
1529         DBG("");
1530
1531         interface = g_hash_table_lookup(interface_table, path);
1532         if (interface == NULL)
1533                 return;
1534
1535         interface_bss_removed(iter, interface);
1536 }
1537
1538 static void signal_network_added(const char *path, DBusMessageIter *iter)
1539 {
1540         GSupplicantInterface *interface;
1541
1542         DBG("");
1543
1544         interface = g_hash_table_lookup(interface_table, path);
1545         if (interface == NULL)
1546                 return;
1547
1548         interface_network_added(iter, interface);
1549 }
1550
1551 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1552 {
1553         GSupplicantInterface *interface;
1554
1555         DBG("");
1556
1557         interface = g_hash_table_lookup(interface_table, path);
1558         if (interface == NULL)
1559                 return;
1560
1561         interface_network_removed(iter, interface);
1562 }
1563
1564 static void signal_bss_changed(const char *path, DBusMessageIter *iter)
1565 {
1566         GSupplicantInterface *interface;
1567         GSupplicantNetwork *network;
1568         struct g_supplicant_bss *bss;
1569
1570         DBG("");
1571
1572         interface = g_hash_table_lookup(bss_mapping, path);
1573         if (interface == NULL)
1574                 return;
1575
1576         network = g_hash_table_lookup(interface->bss_mapping, path);
1577         if (network == NULL)
1578                 return;
1579
1580         bss = g_hash_table_lookup(network->bss_table, path);
1581         if (bss == NULL)
1582                 return;
1583
1584         supplicant_dbus_property_foreach(iter, bss_property, bss);
1585 }
1586
1587 static struct {
1588         const char *interface;
1589         const char *member;
1590         void (*function) (const char *path, DBusMessageIter *iter);
1591 } signal_map[] = {
1592         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
1593
1594         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1595         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
1596         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
1597         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
1598
1599         { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
1600         { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done         },
1601         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added         },
1602         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed       },
1603         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
1604         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
1605
1606         { SUPPLICANT_INTERFACE ".Interface.BSS", "PropertiesChanged", signal_bss_changed   },
1607
1608         { }
1609 };
1610
1611 static DBusHandlerResult g_supplicant_filter(DBusConnection *conn,
1612                                         DBusMessage *message, void *data)
1613 {
1614         DBusMessageIter iter;
1615         const char *path;
1616         int i;
1617
1618         path = dbus_message_get_path(message);
1619         if (path == NULL)
1620                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1621
1622         if (dbus_message_iter_init(message, &iter) == FALSE)
1623                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1624
1625         for (i = 0; signal_map[i].interface != NULL; i++) {
1626                 if (dbus_message_has_interface(message,
1627                                         signal_map[i].interface) == FALSE)
1628                         continue;
1629
1630                 if (dbus_message_has_member(message,
1631                                         signal_map[i].member) == FALSE)
1632                         continue;
1633
1634                 signal_map[i].function(path, &iter);
1635                 break;
1636         }
1637
1638         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1639 }
1640
1641 struct interface_data {
1642         GSupplicantInterface *interface;
1643         GSupplicantInterfaceCallback callback;
1644         void *user_data;
1645 };
1646
1647 struct interface_create_data {
1648         const char *ifname;
1649         const char *driver;
1650         GSupplicantInterface *interface;
1651         GSupplicantInterfaceCallback callback;
1652         void *user_data;
1653 };
1654
1655 struct interface_connect_data {
1656         GSupplicantInterface *interface;
1657         GSupplicantInterfaceCallback callback;
1658         GSupplicantSSID *ssid;
1659         void *user_data;
1660 };
1661
1662 static void interface_create_property(const char *key, DBusMessageIter *iter,
1663                                                         void *user_data)
1664 {
1665         struct interface_create_data *data = user_data;
1666         GSupplicantInterface *interface = data->interface;
1667
1668         if (key == NULL) {
1669                 if (data->callback != NULL)
1670                         data->callback(0, data->interface, data->user_data);
1671
1672                 dbus_free(data);
1673         }
1674
1675         interface_property(key, iter, interface);
1676 }
1677
1678 static void interface_create_result(const char *error,
1679                                 DBusMessageIter *iter, void *user_data)
1680 {
1681         struct interface_create_data *data = user_data;
1682         const char *path = NULL;
1683         int err;
1684
1685         DBG("");
1686
1687         if (error != NULL) {
1688                 connman_error("error %s", error);
1689                 err = -EIO;
1690                 goto done;
1691         }
1692
1693         dbus_message_iter_get_basic(iter, &path);
1694         if (path == NULL) {
1695                 err = -EINVAL;
1696                 goto done;
1697         }
1698
1699         if (system_available == FALSE) {
1700                 err = -EFAULT;
1701                 goto done;
1702         }
1703
1704         data->interface = g_hash_table_lookup(interface_table, path);
1705         if (data->interface == NULL) {
1706                 data->interface = interface_alloc(path);
1707                 if (data->interface == NULL) {
1708                         err = -ENOMEM;
1709                         goto done;
1710                 }
1711         }
1712
1713         err = supplicant_dbus_property_get_all(path,
1714                                         SUPPLICANT_INTERFACE ".Interface",
1715                                         interface_create_property, data);
1716         if (err == 0)
1717                 return;
1718
1719 done:
1720         if (data->callback != NULL)
1721                 data->callback(err, NULL, data->user_data);
1722
1723         dbus_free(data);
1724 }
1725
1726 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1727 {
1728         struct interface_create_data *data = user_data;
1729         DBusMessageIter dict;
1730
1731         DBG("");
1732
1733         supplicant_dbus_dict_open(iter, &dict);
1734
1735         supplicant_dbus_dict_append_basic(&dict, "Ifname",
1736                                         DBUS_TYPE_STRING, &data->ifname);
1737
1738         if (data->driver != NULL)
1739                 supplicant_dbus_dict_append_basic(&dict, "Driver",
1740                                         DBUS_TYPE_STRING, &data->driver);
1741
1742         supplicant_dbus_dict_close(iter, &dict);
1743 }
1744
1745 static void interface_get_result(const char *error,
1746                                 DBusMessageIter *iter, void *user_data)
1747 {
1748         struct interface_create_data *data = user_data;
1749         GSupplicantInterface *interface;
1750         const char *path = NULL;
1751         int err;
1752
1753         DBG("");
1754
1755         if (error != NULL) {
1756                 connman_error("error %s", error);
1757                 err = -EIO;
1758                 goto create;
1759         }
1760
1761         dbus_message_iter_get_basic(iter, &path);
1762         if (path == NULL) {
1763                 err = -EINVAL;
1764                 goto done;
1765         }
1766
1767         interface = g_hash_table_lookup(interface_table, path);
1768         if (interface == NULL) {
1769                 err = -ENOENT;
1770                 goto done;
1771         }
1772
1773         if (data->callback != NULL)
1774                 data->callback(0, interface, data->user_data);
1775
1776         dbus_free(data);
1777
1778         return;
1779
1780 create:
1781         if (system_available == FALSE) {
1782                 err = -EFAULT;
1783                 goto done;
1784         }
1785
1786         DBG("Creating interface");
1787
1788         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1789                                                 SUPPLICANT_INTERFACE,
1790                                                 "CreateInterface",
1791                                                 interface_create_params,
1792                                                 interface_create_result, data);
1793         if (err == 0)
1794                 return;
1795
1796 done:
1797         if (data->callback != NULL)
1798                 data->callback(err, NULL, data->user_data);
1799
1800         dbus_free(data);
1801 }
1802
1803 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1804 {
1805         struct interface_create_data *data = user_data;
1806
1807         DBG("");
1808
1809         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1810 }
1811
1812 int g_supplicant_interface_create(const char *ifname, const char *driver,
1813                                         GSupplicantInterfaceCallback callback,
1814                                                         void *user_data)
1815 {
1816         struct interface_create_data *data;
1817
1818         DBG("ifname %s", ifname);
1819
1820         if (ifname == NULL)
1821                 return -EINVAL;
1822
1823         if (system_available == FALSE)
1824                 return -EFAULT;
1825
1826         data = dbus_malloc0(sizeof(*data));
1827         if (data == NULL)
1828                 return -ENOMEM;
1829
1830         data->ifname = ifname;
1831         data->driver = driver;
1832         data->callback = callback;
1833         data->user_data = user_data;
1834
1835         return supplicant_dbus_method_call(SUPPLICANT_PATH,
1836                                                 SUPPLICANT_INTERFACE,
1837                                                 "GetInterface",
1838                                                 interface_get_params,
1839                                                 interface_get_result, data);
1840 }
1841
1842 static void interface_remove_result(const char *error,
1843                                 DBusMessageIter *iter, void *user_data)
1844 {
1845         struct interface_data *data = user_data;
1846         int err;
1847
1848         if (error != NULL) {
1849                 err = -EIO;
1850                 goto done;
1851         }
1852
1853         if (system_available == FALSE) {
1854                 err = -EFAULT;
1855                 goto done;
1856         }
1857
1858         g_hash_table_remove(interface_table, data->interface->path);
1859         err = 0;
1860
1861 done:
1862         if (data->callback != NULL)
1863                 data->callback(err, data->interface, data->user_data);
1864
1865         dbus_free(data);
1866 }
1867
1868
1869 static void interface_remove_params(DBusMessageIter *iter, void *user_data)
1870 {
1871         struct interface_data *data = user_data;
1872
1873         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
1874                                                         &data->interface->path);
1875 }
1876
1877
1878 int g_supplicant_interface_remove(GSupplicantInterface *interface,
1879                         GSupplicantInterfaceCallback callback,
1880                                                         void *user_data)
1881 {
1882         struct interface_data *data;
1883
1884         if (interface == NULL)
1885                 return -EINVAL;
1886
1887         if (system_available == FALSE)
1888                 return -EFAULT;
1889
1890         data = dbus_malloc0(sizeof(*data));
1891         if (data == NULL)
1892                 return -ENOMEM;
1893
1894         data->interface = interface;
1895         data->callback = callback;
1896         data->user_data = user_data;
1897
1898         return supplicant_dbus_method_call(SUPPLICANT_PATH,
1899                                                 SUPPLICANT_INTERFACE,
1900                                                 "RemoveInterface",
1901                                                 interface_remove_params,
1902                                                 interface_remove_result, data);
1903 }
1904
1905 static void interface_scan_result(const char *error,
1906                                 DBusMessageIter *iter, void *user_data)
1907 {
1908         struct interface_data *data = user_data;
1909
1910         if (error != NULL) {
1911                 if (data->callback != NULL)
1912                         data->callback(-EIO, data->interface, data->user_data);
1913         } else {
1914                 data->interface->scan_callback = data->callback;
1915                 data->interface->scan_data = data->user_data;
1916         }
1917
1918         dbus_free(data);
1919 }
1920
1921 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
1922 {
1923         DBusMessageIter dict;
1924         const char *type = "passive";
1925
1926         supplicant_dbus_dict_open(iter, &dict);
1927
1928         supplicant_dbus_dict_append_basic(&dict, "Type",
1929                                                 DBUS_TYPE_STRING, &type);
1930
1931         supplicant_dbus_dict_close(iter, &dict);
1932 }
1933
1934 int g_supplicant_interface_scan(GSupplicantInterface *interface,
1935                                 GSupplicantInterfaceCallback callback,
1936                                                         void *user_data)
1937 {
1938         struct interface_data *data;
1939
1940         if (interface == NULL)
1941                 return -EINVAL;
1942
1943         if (system_available == FALSE)
1944                 return -EFAULT;
1945
1946         if (interface->scanning == TRUE)
1947                 return -EALREADY;
1948
1949         data = dbus_malloc0(sizeof(*data));
1950         if (data == NULL)
1951                 return -ENOMEM;
1952
1953         data->interface = interface;
1954         data->callback = callback;
1955         data->user_data = user_data;
1956
1957         return supplicant_dbus_method_call(interface->path,
1958                         SUPPLICANT_INTERFACE ".Interface", "Scan",
1959                         interface_scan_params, interface_scan_result, data);
1960 }
1961
1962 static void interface_select_network_result(const char *error,
1963                                 DBusMessageIter *iter, void *user_data)
1964 {
1965         DBG("");
1966 }
1967
1968 static void interface_select_network_params(DBusMessageIter *iter,
1969                                                         void *user_data)
1970 {
1971         char *path = user_data;
1972
1973         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
1974 }
1975
1976 static void interface_add_network_result(const char *error,
1977                                 DBusMessageIter *iter, void *user_data)
1978 {
1979         struct interface_connect_data *data = user_data;
1980         char *path = NULL;
1981
1982         if (error != NULL)
1983                 goto done;
1984
1985         dbus_message_iter_get_basic(iter, &path);
1986         if (path == NULL)
1987                 goto done;
1988
1989         DBG("PATH: %s", path);
1990
1991         supplicant_dbus_method_call(data->interface->path,
1992                         SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
1993                         interface_select_network_params,
1994                         interface_select_network_result, path);
1995
1996 done:
1997         dbus_free(data);
1998 }
1999
2000 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
2001 {
2002         char *key_mgmt;
2003
2004         switch (ssid->security) {
2005         case G_SUPPLICANT_SECURITY_UNKNOWN:
2006         case G_SUPPLICANT_SECURITY_NONE:
2007         case G_SUPPLICANT_SECURITY_WEP:
2008                 key_mgmt = "NONE";
2009                 break;
2010         case G_SUPPLICANT_SECURITY_PSK:
2011                 key_mgmt = "WPA-PSK";
2012                 break;
2013         case G_SUPPLICANT_SECURITY_IEEE8021X:
2014                 key_mgmt = "WPA-EAP";
2015                 break;
2016         }
2017
2018         supplicant_dbus_dict_append_basic(dict, "key_mgmt",
2019                                 DBUS_TYPE_STRING, &key_mgmt);
2020 }
2021
2022 static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
2023 {
2024         DBusMessageIter dict;
2025         dbus_uint32_t scan_ssid = 1;
2026         struct interface_connect_data *data = user_data;
2027         GSupplicantSSID *ssid = data->ssid;
2028
2029         supplicant_dbus_dict_open(iter, &dict);
2030
2031         supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
2032                                          DBUS_TYPE_UINT32, &scan_ssid);
2033
2034         add_network_security(&dict, ssid);
2035
2036         supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
2037                                         DBUS_TYPE_BYTE, &ssid->ssid,
2038                                                 ssid->ssid_len);
2039
2040         supplicant_dbus_dict_close(iter, &dict);
2041 }
2042
2043 int g_supplicant_interface_connect(GSupplicantInterface *interface,
2044                                 GSupplicantSSID *ssid,
2045                                 GSupplicantInterfaceCallback callback,
2046                                                         void *user_data)
2047 {
2048         struct interface_connect_data *data;
2049         int ret;
2050
2051         if (interface == NULL)
2052                 return -EINVAL;
2053
2054         if (system_available == FALSE)
2055                 return -EFAULT;
2056
2057         /* TODO: Check if we're already connected and switch */
2058
2059         data = dbus_malloc0(sizeof(*data));
2060         if (data == NULL)
2061                 return -ENOMEM;
2062
2063         data->interface = interface;
2064         data->callback = callback;
2065         data->ssid = ssid;
2066         data->user_data = user_data;
2067
2068         ret = supplicant_dbus_method_call(interface->path,
2069                         SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
2070                         interface_add_network_params,
2071                         interface_add_network_result, data);
2072         if (ret < 0)
2073                 return ret;
2074
2075         return -EINPROGRESS;
2076 }
2077
2078 static void interface_disconnect_result(const char *error,
2079                                 DBusMessageIter *iter, void *user_data)
2080 {
2081         struct interface_data *data = user_data;
2082         int result = 0;
2083
2084         DBG("");
2085
2086         if (error != NULL)
2087                 result = -EIO;
2088
2089         if (data->callback != NULL)
2090                 data->callback(result, data->interface, data->user_data);
2091
2092         dbus_free(data);
2093 }
2094
2095 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
2096                                         GSupplicantInterfaceCallback callback,
2097                                                         void *user_data)
2098 {
2099         struct interface_data *data;
2100
2101         DBG("");
2102
2103         if (interface == NULL)
2104                 return -EINVAL;
2105
2106         if (system_available == FALSE)
2107                 return -EFAULT;
2108
2109         data = dbus_malloc0(sizeof(*data));
2110         if (data == NULL)
2111                 return -ENOMEM;
2112
2113         data->interface = interface;
2114         data->callback = callback;
2115         data->user_data = user_data;
2116
2117         return supplicant_dbus_method_call(interface->path,
2118                         SUPPLICANT_INTERFACE ".Interface", "Disconnect",
2119                                 NULL, interface_disconnect_result, data);
2120 }
2121
2122
2123 static const char *g_supplicant_rule0 = "type=signal,"
2124                                         "path=" DBUS_PATH_DBUS ","
2125                                         "sender=" DBUS_SERVICE_DBUS ","
2126                                         "interface=" DBUS_INTERFACE_DBUS ","
2127                                         "member=NameOwnerChanged,"
2128                                         "arg0=" SUPPLICANT_SERVICE;
2129 static const char *g_supplicant_rule1 = "type=signal,"
2130                         "interface=" SUPPLICANT_INTERFACE;
2131 static const char *g_supplicant_rule2 = "type=signal,"
2132                         "interface=" SUPPLICANT_INTERFACE ".Interface";
2133 static const char *g_supplicant_rule3 = "type=signal,"
2134                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
2135 static const char *g_supplicant_rule4 = "type=signal,"
2136                         "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
2137 static const char *g_supplicant_rule5 = "type=signal,"
2138                         "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
2139 static const char *g_supplicant_rule6 = "type=signal,"
2140                         "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
2141
2142 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
2143 {
2144         DBG("");
2145
2146         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2147         if (connection == NULL)
2148                 return -EIO;
2149
2150         if (dbus_connection_add_filter(connection,
2151                                 g_supplicant_filter, NULL, NULL) == FALSE) {
2152                 dbus_connection_unref(connection);
2153                 connection = NULL;
2154                 return -EIO;
2155         }
2156
2157         callbacks_pointer = callbacks;
2158         eap_methods = 0;
2159
2160         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
2161                                                 NULL, remove_interface);
2162
2163         bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
2164                                                                 NULL, NULL);
2165
2166         supplicant_dbus_setup(connection);
2167
2168         dbus_bus_add_match(connection, g_supplicant_rule0, NULL);
2169         dbus_bus_add_match(connection, g_supplicant_rule1, NULL);
2170         dbus_bus_add_match(connection, g_supplicant_rule2, NULL);
2171         dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
2172         dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
2173         dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
2174         dbus_bus_add_match(connection, g_supplicant_rule6, NULL);
2175         dbus_connection_flush(connection);
2176
2177         if (dbus_bus_name_has_owner(connection,
2178                                         SUPPLICANT_SERVICE, NULL) == TRUE) {
2179                 system_available = TRUE;
2180                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
2181                                                 SUPPLICANT_INTERFACE,
2182                                                 service_property, NULL);
2183         }
2184
2185         return 0;
2186 }
2187
2188 static void unregister_interface_remove_params(DBusMessageIter *iter,
2189                                                 void *user_data)
2190 {
2191         const char *path = user_data;
2192
2193         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2194                                                         &path);
2195 }
2196
2197
2198 static void unregister_remove_interface(gpointer key, gpointer value,
2199                                                 gpointer user_data)
2200 {
2201         GSupplicantInterface *interface = value;
2202
2203         supplicant_dbus_method_call(SUPPLICANT_PATH,
2204                                         SUPPLICANT_INTERFACE,
2205                                         "RemoveInterface",
2206                                         unregister_interface_remove_params,
2207                                                 NULL, interface->path);
2208 }
2209
2210 void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
2211 {
2212         DBG("");
2213
2214         if (connection != NULL) {
2215                 dbus_bus_remove_match(connection, g_supplicant_rule6, NULL);
2216                 dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
2217                 dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
2218                 dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);
2219                 dbus_bus_remove_match(connection, g_supplicant_rule2, NULL);
2220                 dbus_bus_remove_match(connection, g_supplicant_rule1, NULL);
2221                 dbus_bus_remove_match(connection, g_supplicant_rule0, NULL);
2222                 dbus_connection_flush(connection);
2223
2224                 dbus_connection_remove_filter(connection,
2225                                                 g_supplicant_filter, NULL);
2226         }
2227
2228         if (bss_mapping != NULL) {
2229                 g_hash_table_destroy(bss_mapping);
2230                 bss_mapping = NULL;
2231         }
2232
2233         if (interface_table != NULL) {
2234                 g_hash_table_foreach(interface_table,   
2235                                         unregister_remove_interface, NULL);
2236                 g_hash_table_destroy(interface_table);
2237                 interface_table = NULL;
2238         }
2239
2240         if (system_available == TRUE)
2241                 callback_system_killed();
2242
2243         if (connection != NULL) {
2244                 dbus_connection_unref(connection);
2245                 connection = NULL;
2246         }
2247
2248         callbacks_pointer = NULL;
2249         eap_methods = 0;
2250 }