Add interface and network handling to supplicant test program
[framework/connectivity/connman.git] / tools / supplicant.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <string.h>
28 #include <syslog.h>
29
30 #include <glib.h>
31 #include <gdbus.h>
32
33 #include "supplicant-dbus.h"
34 #include "supplicant.h"
35
36 #define DBG(fmt, arg...) do { \
37         syslog(LOG_DEBUG, "%s() " fmt, __FUNCTION__ , ## arg); \
38 } while (0)
39
40 #define TIMEOUT 5000
41
42 static DBusConnection *connection;
43
44 static const struct supplicant_callbacks *callbacks_pointer;
45
46 static unsigned int eap_methods;
47
48 static struct {
49         const char *str;
50         unsigned int val;
51 } eap_method_map[] = {
52         { "MD5",        SUPPLICANT_EAP_METHOD_MD5       },
53         { "TLS",        SUPPLICANT_EAP_METHOD_TLS       },
54         { "MSCHAPV2",   SUPPLICANT_EAP_METHOD_MSCHAPV2  },
55         { "PEAP",       SUPPLICANT_EAP_METHOD_PEAP      },
56         { "TTLS",       SUPPLICANT_EAP_METHOD_TTLS      },
57         { "GTC",        SUPPLICANT_EAP_METHOD_GTC       },
58         { "OTP",        SUPPLICANT_EAP_METHOD_OTP       },
59         { "LEAP",       SUPPLICANT_EAP_METHOD_LEAP      },
60         { }
61 };
62
63 static struct {
64         const char *str;
65         unsigned int val;
66 } scan_capa_map[] = {
67         { "active",     SUPPLICANT_CAPABILITY_SCAN_ACTIVE       },
68         { "passive",    SUPPLICANT_CAPABILITY_SCAN_PASSIVE      },
69         { "ssid",       SUPPLICANT_CAPABILITY_SCAN_SSID         },
70         { }
71 };
72
73 static GHashTable *interface_table;
74
75 struct supplicant_interface {
76         char *path;
77         unsigned int scan_capa;
78         enum supplicant_state state;
79         dbus_bool_t scanning;
80         int apscan;
81         char *ifname;
82         char *driver;
83         char *bridge;
84         GHashTable *network_table;
85         GHashTable *bss_mapping;
86 };
87
88 struct supplicant_network {
89         struct supplicant_interface *interface;
90         char *group;
91         char *name;
92         enum supplicant_network_mode mode;
93         GHashTable *bss_table;
94 };
95
96 struct supplicant_bss {
97         struct supplicant_interface *interface;
98         char *path;
99         unsigned char bssid[6];
100         unsigned char ssid[32];
101         unsigned int ssid_len;
102         unsigned int frequency;
103 };
104
105 static enum supplicant_state string2state(const char *state)
106 {
107         if (state == NULL)
108                 return SUPPLICANT_STATE_UNKNOWN;
109
110         if (g_str_equal(state, "unknown") == TRUE)
111                 return SUPPLICANT_STATE_UNKNOWN;
112         else if (g_str_equal(state, "disconnected") == TRUE)
113                 return SUPPLICANT_STATE_DISCONNECTED;
114         else if (g_str_equal(state, "inactive") == TRUE)
115                 return SUPPLICANT_STATE_INACTIVE;
116         else if (g_str_equal(state, "scanning") == TRUE)
117                 return SUPPLICANT_STATE_SCANNING;
118         else if (g_str_equal(state, "authenticating") == TRUE)
119                 return SUPPLICANT_STATE_AUTHENTICATING;
120         else if (g_str_equal(state, "associating") == TRUE)
121                 return SUPPLICANT_STATE_ASSOCIATING;
122         else if (g_str_equal(state, "associated") == TRUE)
123                 return SUPPLICANT_STATE_ASSOCIATED;
124         else if (g_str_equal(state, "group_handshake") == TRUE)
125                 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
126         else if (g_str_equal(state, "4way_handshake") == TRUE)
127                 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
128         else if (g_str_equal(state, "completed") == TRUE)
129                 return SUPPLICANT_STATE_COMPLETED;
130
131         return SUPPLICANT_STATE_UNKNOWN;
132 }
133
134 static void callback_interface_added(struct supplicant_interface *interface)
135 {
136         if (callbacks_pointer == NULL)
137                 return;
138
139         if (callbacks_pointer->interface_added == NULL)
140                 return;
141
142         callbacks_pointer->interface_added(interface);
143 }
144
145 static void callback_interface_removed(struct supplicant_interface *interface)
146 {
147         if (callbacks_pointer == NULL)
148                 return;
149
150         if (callbacks_pointer->interface_removed == NULL)
151                 return;
152
153         callbacks_pointer->interface_removed(interface);
154 }
155
156 static void callback_network_added(struct supplicant_network *network)
157 {
158         if (callbacks_pointer == NULL)
159                 return;
160
161         if (callbacks_pointer->network_added == NULL)
162                 return;
163
164         callbacks_pointer->network_added(network);
165 }
166
167 static void callback_network_removed(struct supplicant_network *network)
168 {
169         if (callbacks_pointer == NULL)
170                 return;
171
172         if (callbacks_pointer->network_removed == NULL)
173                 return;
174
175         callbacks_pointer->network_removed(network);
176 }
177
178 static void remove_interface(gpointer data)
179 {
180         struct supplicant_interface *interface = data;
181
182         callback_interface_removed(interface);
183
184         g_hash_table_destroy(interface->bss_mapping);
185         g_hash_table_destroy(interface->network_table);
186
187         g_free(interface->path);
188         g_free(interface->ifname);
189         g_free(interface->driver);
190         g_free(interface->bridge);
191         g_free(interface);
192 }
193
194 static void remove_network(gpointer data)
195 {
196         struct supplicant_network *network = data;
197
198         callback_network_removed(network);
199
200         g_free(network->group);
201         g_free(network->name);
202         g_free(network);
203 }
204
205 static void remove_bss(gpointer data)
206 {
207         struct supplicant_bss *bss = data;
208
209         g_free(bss->path);
210         g_free(bss);
211 }
212
213 static void debug_eap_methods(void)
214 {
215         int i;
216
217         for (i = 0; eap_method_map[i].str != NULL; i++) {
218                 if (eap_methods & eap_method_map[i].val)
219                         DBG("EAP Method: %s", eap_method_map[i].str);
220         }
221 }
222
223 static void debug_scan_capabilities(struct supplicant_interface *interface)
224 {
225         int i;
226
227         for (i = 0; scan_capa_map[i].str != NULL; i++) {
228                 if (interface->scan_capa & scan_capa_map[i].val)
229                         DBG("Scan Capability: %s", scan_capa_map[i].str);
230         }
231 }
232
233 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
234 {
235         struct supplicant_interface *interface = user_data;
236         const char *str = NULL;
237         int i;
238
239         dbus_message_iter_get_basic(iter, &str);
240         if (str == NULL)
241                 return;
242
243         for (i = 0; scan_capa_map[i].str != NULL; i++)
244                 if (strcmp(str, scan_capa_map[i].str) == 0) {
245                         interface->scan_capa |= scan_capa_map[i].val;
246                         break;
247                 }
248 }
249
250 static void interface_capability(const char *key, DBusMessageIter *iter,
251                                                         void *user_data)
252 {
253         struct supplicant_interface *interface = user_data;
254
255         if (key == NULL)
256                 return;
257
258         if (g_strcmp0(key, "Scan") == 0)
259                 supplicant_dbus_array_foreach(iter, interface_capability_scan,
260                                                                 interface);
261         else
262                 DBG("key %s type %c",
263                                 key, dbus_message_iter_get_arg_type(iter));
264 }
265
266 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
267 {
268         if (interface == NULL)
269                 return NULL;
270
271         return interface->ifname;
272 }
273
274 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
275 {
276         if (network == NULL)
277                 return NULL;
278
279         return network->interface;
280 }
281
282 const char *supplicant_network_get_name(struct supplicant_network *network)
283 {
284         if (network == NULL || network->name == NULL)
285                 return "";
286
287         return network->name;
288 }
289
290 enum supplicant_network_mode supplicant_network_get_mode(struct supplicant_network *network)
291 {
292         if (network == NULL)
293                 return SUPPLICANT_NETWORK_MODE_UNKNOWN;
294
295         return network->mode;
296 }
297
298 static void network_property(const char *key, DBusMessageIter *iter,
299                                                         void *user_data)
300 {
301         if (key == NULL)
302                 return;
303
304         DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
305 }
306
307 static void interface_network_added(DBusMessageIter *iter, void *user_data)
308 {
309         const char *path = NULL;
310
311         dbus_message_iter_get_basic(iter, &path);
312         if (path == NULL)
313                 return;
314
315         supplicant_dbus_property_get_all(path,
316                                 SUPPLICANT_INTERFACE ".Interface.Network",
317                                                 network_property, NULL);
318 }
319
320 static char *create_name(unsigned char *ssid, int ssid_len)
321 {
322         char *name;
323         int i;
324
325         if (ssid_len < 1 || ssid[0] == '\0')
326                 name = NULL;
327         else
328                 name = g_try_malloc0(ssid_len + 1);
329
330         if (name == NULL)
331                 return g_strdup("");
332
333         for (i = 0; i < ssid_len; i++) {
334                 if (g_ascii_isprint(ssid[i]))
335                         name[i] = ssid[i];
336                 else
337                         name[i] = ' ';
338         }
339
340         return name;
341 }
342
343 static void add_bss_to_network(struct supplicant_bss *bss)
344 {
345         struct supplicant_interface *interface = bss->interface;
346         struct supplicant_network *network;
347         GString *str;
348         char *group;
349         unsigned int i;
350
351         str = g_string_sized_new((bss->ssid_len * 2) + 24);
352         if (str == NULL)
353                 return;
354
355         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
356                 for (i = 0; i < bss->ssid_len; i++)
357                         g_string_append_printf(str, "%02x", bss->ssid[i]);
358         } else
359                 g_string_append_printf(str, "hidden");
360
361         group = g_string_free(str, FALSE);
362
363         network = g_hash_table_lookup(interface->network_table, group);
364         if (network != NULL) {
365                 g_free(group);
366                 goto done;
367         }
368
369         network = g_try_new0(struct supplicant_network, 1);
370         if (network == NULL) {
371                 g_free(group);
372                 return;
373         }
374
375         network->group = group;
376         network->name = create_name(bss->ssid, bss->ssid_len);
377
378         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
379                                                         NULL, remove_bss);
380
381         g_hash_table_replace(interface->network_table,
382                                                 network->group, network);
383
384         callback_network_added(network);
385
386 done:
387         g_hash_table_replace(interface->bss_mapping, bss->path, network);
388         g_hash_table_replace(network->bss_table, bss->path, bss);
389 }
390
391 static void bss_property(const char *key, DBusMessageIter *iter,
392                                                         void *user_data)
393 {
394         struct supplicant_bss *bss = user_data;
395
396         if (bss->interface == NULL)
397                 return;
398
399         if (key == NULL) {
400                 add_bss_to_network(bss);
401                 return;
402         }
403
404         if (g_strcmp0(key, "BSSID") == 0) {
405                 DBusMessageIter array;
406                 unsigned char *addr;
407                 int addr_len;
408
409                 dbus_message_iter_recurse(iter, &array);
410                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
411
412                 if (addr_len == 6)
413                         memcpy(bss->bssid, addr, addr_len);
414         } else if (g_strcmp0(key, "SSID") == 0) {
415                 DBusMessageIter array;
416                 unsigned char *ssid;
417                 int ssid_len;
418
419                 dbus_message_iter_recurse(iter, &array);
420                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
421
422                 if (ssid_len > 0 && ssid_len < 33) {
423                         memcpy(bss->ssid, ssid, ssid_len);
424                         bss->ssid_len = ssid_len;
425                 } else {
426                         memset(bss->ssid, 0, sizeof(bss->ssid));
427                         bss->ssid_len = 0;
428                 }
429         } else if (g_strcmp0(key, "Capabilities") == 0) {
430                 unsigned char capabilities = 0x00;
431
432                 dbus_message_iter_get_basic(iter, &capabilities);
433         } else if (g_strcmp0(key, "Frequency") == 0) {
434                 dbus_int32_t frequency = 0;
435
436                 dbus_message_iter_get_basic(iter, &frequency);
437                 bss->frequency = frequency;
438         } else if (g_strcmp0(key, "Level") == 0) {
439                 dbus_int32_t level = 0;
440
441                 dbus_message_iter_get_basic(iter, &level);
442         } else if (g_strcmp0(key, "MaxRate") == 0) {
443                 dbus_int32_t maxrate = 0;
444
445                 dbus_message_iter_get_basic(iter, &maxrate);
446         } else if (g_strcmp0(key, "RSNIE") == 0) {
447                 DBusMessageIter array;
448                 unsigned char *ie;
449                 int ie_len;
450
451                 dbus_message_iter_recurse(iter, &array);
452                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
453         } else if (g_strcmp0(key, "WPAIE") == 0) {
454                 DBusMessageIter array;
455                 unsigned char *ie;
456                 int ie_len;
457
458                 dbus_message_iter_recurse(iter, &array);
459                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
460         } else if (g_strcmp0(key, "WPSIE") == 0) {
461                 DBusMessageIter array;
462                 unsigned char *ie;
463                 int ie_len;
464
465                 dbus_message_iter_recurse(iter, &array);
466                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
467         } else
468                 DBG("key %s type %c",
469                                 key, dbus_message_iter_get_arg_type(iter));
470 }
471
472 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
473 {
474         struct supplicant_interface *interface = user_data;
475         struct supplicant_network *network;
476         struct supplicant_bss *bss;
477         const char *path = NULL;
478
479         dbus_message_iter_get_basic(iter, &path);
480         if (path == NULL)
481                 return;
482
483         network = g_hash_table_lookup(interface->bss_mapping, path);
484         if (network != NULL) {
485                 bss = g_hash_table_lookup(network->bss_table, path);
486                 if (bss != NULL)
487                         return;
488         }
489
490         bss = g_try_new0(struct supplicant_bss, 1);
491         if (bss == NULL)
492                 return;
493
494         bss->interface = interface;
495         bss->path = g_strdup(path);
496
497         supplicant_dbus_property_get_all(path,
498                                         SUPPLICANT_INTERFACE ".Interface.BSS",
499                                                         bss_property, bss);
500 }
501
502 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
503 {
504         struct supplicant_interface *interface = user_data;
505         struct supplicant_network *network;
506         const char *path = NULL;
507
508         dbus_message_iter_get_basic(iter, &path);
509         if (path == NULL)
510                 return;
511
512         network = g_hash_table_lookup(interface->bss_mapping, path);
513         if (network == NULL)
514                 return;
515
516         g_hash_table_remove(interface->bss_mapping, path);
517         g_hash_table_remove(network->bss_table, path);
518
519         if (g_hash_table_size(network->bss_table) == 0)
520                 g_hash_table_remove(interface->network_table, network->group);
521 }
522
523 static void interface_property(const char *key, DBusMessageIter *iter,
524                                                         void *user_data)
525 {
526         struct supplicant_interface *interface = user_data;
527
528         if (interface == NULL)
529                 return;
530
531         if (key == NULL) {
532                 debug_scan_capabilities(interface);
533
534                 g_hash_table_replace(interface_table,
535                                         interface->path, interface);
536
537                 callback_interface_added(interface);
538                 return;
539         }
540
541         if (g_strcmp0(key, "Capabilities") == 0) {
542                 supplicant_dbus_property_foreach(iter, interface_capability,
543                                                                 interface);
544         } else if (g_strcmp0(key, "State") == 0) {
545                 const char *str = NULL;
546
547                 dbus_message_iter_get_basic(iter, &str);
548                 if (str != NULL)
549                         interface->state = string2state(str);
550         } else if (g_strcmp0(key, "Scanning") == 0) {
551                 dbus_bool_t scanning = FALSE;
552
553                 dbus_message_iter_get_basic(iter, &scanning);
554                 interface->scanning = scanning;
555         } else if (g_strcmp0(key, "ApScan") == 0) {
556                 int apscan;
557
558                 dbus_message_iter_get_basic(iter, &apscan);
559                 interface->apscan = apscan;
560         } else if (g_strcmp0(key, "Ifname") == 0) {
561                 const char *str = NULL;
562
563                 dbus_message_iter_get_basic(iter, &str);
564                 if (str != NULL)
565                         interface->ifname = g_strdup(str);
566         } else if (g_strcmp0(key, "Driver") == 0) {
567                 const char *str = NULL;
568
569                 dbus_message_iter_get_basic(iter, &str);
570                 if (str != NULL)
571                         interface->driver = g_strdup(str);
572         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
573                 const char *str = NULL;
574
575                 dbus_message_iter_get_basic(iter, &str);
576                 if (str != NULL)
577                         interface->bridge = g_strdup(str);
578         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
579                 interface_bss_added(iter, interface);
580         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
581                 interface_network_added(iter, interface);
582         } else if (g_strcmp0(key, "BSSs") == 0) {
583                 supplicant_dbus_array_foreach(iter, interface_bss_added,
584                                                                 interface);
585         } else if (g_strcmp0(key, "Blobs") == 0) {
586         } else if (g_strcmp0(key, "Networks") == 0) {
587                 supplicant_dbus_array_foreach(iter, interface_network_added,
588                                                                 interface);
589         } else
590                 DBG("key %s type %c",
591                                 key, dbus_message_iter_get_arg_type(iter));
592 }
593
594 static void interface_path(DBusMessageIter *iter, void *user_data)
595 {
596         struct supplicant_interface *interface;
597         const char *path = NULL;
598
599         dbus_message_iter_get_basic(iter, &path);
600         if (path == NULL)
601                 return;
602
603         interface = g_hash_table_lookup(interface_table, path);
604         if (interface != NULL)
605                 return;
606
607         interface = g_try_new0(struct supplicant_interface, 1);
608         if (interface == NULL)
609                 return;
610
611         interface->path = g_strdup(path);
612
613         interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
614                                                         NULL, remove_network);
615
616         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
617                                                                 NULL, NULL);
618
619         supplicant_dbus_property_get_all(path,
620                                         SUPPLICANT_INTERFACE ".Interface",
621                                                 interface_property, interface);
622 }
623
624 static void eap_method(DBusMessageIter *iter, void *user_data)
625 {
626         const char *str = NULL;
627         int i;
628
629         dbus_message_iter_get_basic(iter, &str);
630         if (str == NULL)
631                 return;
632
633         for (i = 0; eap_method_map[i].str != NULL; i++)
634                 if (strcmp(str, eap_method_map[i].str) == 0) {
635                         eap_methods |= eap_method_map[i].val;
636                         break;
637                 }
638 }
639
640 static void service_property(const char *key, DBusMessageIter *iter,
641                                                         void *user_data)
642 {
643         if (key == NULL)
644                 return;
645
646         if (g_strcmp0(key, "Interfaces") == 0)
647                 supplicant_dbus_array_foreach(iter, interface_path, user_data);
648         else if (g_strcmp0(key, "EapMethods") == 0) {
649                 supplicant_dbus_array_foreach(iter, eap_method, user_data);
650                 debug_eap_methods();
651         } else if (g_strcmp0(key, "DebugParams") == 0) {
652         }
653 }
654
655 static void signal_interface_added(const char *path, DBusMessageIter *iter)
656 {
657         interface_path(iter, NULL);
658 }
659
660 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
661 {
662         DBG("path %s", path);
663 }
664
665 static void signal_bss_added(const char *path, DBusMessageIter *iter)
666 {
667         struct supplicant_interface *interface;
668
669         interface = g_hash_table_lookup(interface_table, path);
670         if (interface == NULL)
671                 return;
672
673         interface_bss_added(iter, interface);
674 }
675
676 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
677 {
678         struct supplicant_interface *interface;
679
680         interface = g_hash_table_lookup(interface_table, path);
681         if (interface == NULL)
682                 return;
683
684         interface_bss_removed(iter, interface);
685 }
686
687 static struct {
688         const char *interface;
689         const char *member;
690         void (*function) (const char *path, DBusMessageIter *iter);
691 } signal_map[] = {
692         { SUPPLICANT_INTERFACE, "InterfaceAdded",   signal_interface_added    },
693         { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed  },
694         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",   signal_bss_added   },
695         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
696         { }
697 };
698
699 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
700                                         DBusMessage *message, void *data)
701 {
702         DBusMessageIter iter;
703         const char *path;
704         int i;
705
706         path = dbus_message_get_path(message);
707         if (path == NULL)
708                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
709
710         if (dbus_message_iter_init(message, &iter) == FALSE)
711                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
712
713         for (i = 0; signal_map[i].interface != NULL; i++) {
714                 if (dbus_message_has_interface(message,
715                                         signal_map[i].interface) == FALSE)
716                         continue;
717
718                 if (dbus_message_has_member(message,
719                                         signal_map[i].member) == FALSE)
720                         continue;
721
722                 signal_map[i].function(path, &iter);
723                 break;
724         }
725
726         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
727 }
728
729 static const char *supplicant_rule1 = "type=signal,"
730                         "interface=" SUPPLICANT_INTERFACE;
731 static const char *supplicant_rule2 = "type=signal,"
732                         "interface=" SUPPLICANT_INTERFACE ".Interface";
733 static const char *supplicant_rule3 = "type=signal,"
734                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
735 static const char *supplicant_rule4 = "type=signal,"
736                         "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
737 static const char *supplicant_rule5 = "type=signal,"
738                         "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
739 static const char *supplicant_rule6 = "type=signal,"
740                         "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
741
742 int supplicant_register(const struct supplicant_callbacks *callbacks)
743 {
744         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
745         if (connection == NULL)
746                 return -EIO;
747
748         if (dbus_connection_add_filter(connection,
749                                 supplicant_filter, NULL, NULL) == FALSE) {
750                 dbus_connection_unref(connection);
751                 connection = NULL;
752                 return -EIO;
753         }
754
755         callbacks_pointer = callbacks;
756         eap_methods = 0;
757
758         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
759                                                 NULL, remove_interface);
760
761         supplicant_dbus_setup(connection);
762
763         dbus_bus_add_match(connection, supplicant_rule1, NULL);
764         dbus_bus_add_match(connection, supplicant_rule2, NULL);
765         dbus_bus_add_match(connection, supplicant_rule3, NULL);
766         dbus_bus_add_match(connection, supplicant_rule4, NULL);
767         dbus_bus_add_match(connection, supplicant_rule5, NULL);
768         dbus_bus_add_match(connection, supplicant_rule6, NULL);
769         dbus_connection_flush(connection);
770
771         supplicant_dbus_property_get_all(SUPPLICANT_PATH,
772                                                 SUPPLICANT_INTERFACE,
773                                                 service_property, NULL);
774
775         return 0;
776 }
777
778 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
779 {
780         if (connection != NULL) {
781                 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
782                 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
783                 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
784                 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
785                 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
786                 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
787                 dbus_connection_flush(connection);
788
789                 dbus_connection_remove_filter(connection,
790                                                 supplicant_filter, NULL);
791         }
792
793         if (interface_table != NULL) {
794                 g_hash_table_destroy(interface_table);
795                 interface_table = NULL;
796         }
797
798         if (connection != NULL) {
799                 dbus_connection_unref(connection);
800                 connection = NULL;
801         }
802
803         callbacks_pointer = NULL;
804         eap_methods = 0;
805 }