Handle supplicant restarts in 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_added(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 interface_removed(DBusMessageIter *iter, void *user_data)
625 {
626         const char *path = NULL;
627
628         dbus_message_iter_get_basic(iter, &path);
629         if (path == NULL)
630                 return;
631
632         g_hash_table_remove(interface_table, path);
633 }
634
635 static void eap_method(DBusMessageIter *iter, void *user_data)
636 {
637         const char *str = NULL;
638         int i;
639
640         dbus_message_iter_get_basic(iter, &str);
641         if (str == NULL)
642                 return;
643
644         for (i = 0; eap_method_map[i].str != NULL; i++)
645                 if (strcmp(str, eap_method_map[i].str) == 0) {
646                         eap_methods |= eap_method_map[i].val;
647                         break;
648                 }
649 }
650
651 static void service_property(const char *key, DBusMessageIter *iter,
652                                                         void *user_data)
653 {
654         if (key == NULL)
655                 return;
656
657         if (g_strcmp0(key, "Interfaces") == 0)
658                 supplicant_dbus_array_foreach(iter, interface_added, user_data);
659         else if (g_strcmp0(key, "EapMethods") == 0) {
660                 supplicant_dbus_array_foreach(iter, eap_method, user_data);
661                 debug_eap_methods();
662         } else if (g_strcmp0(key, "DebugParams") == 0) {
663         }
664 }
665
666 static void supplicant_bootstrap(void)
667 {
668         supplicant_dbus_property_get_all(SUPPLICANT_PATH,
669                                                 SUPPLICANT_INTERFACE,
670                                                 service_property, NULL);
671 }
672
673 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
674 {
675         const char *name = NULL, *old = NULL, *new = NULL;
676
677         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
678                 return;
679
680         dbus_message_iter_get_basic(iter, &name);
681         if (name == NULL)
682                 return;
683
684         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
685                 return;
686
687         dbus_message_iter_next(iter);
688         dbus_message_iter_get_basic(iter, &old);
689         dbus_message_iter_next(iter);
690         dbus_message_iter_get_basic(iter, &new);
691
692         if (old == NULL || new == NULL)
693                 return;
694
695         if (strlen(old) > 0 && strlen(new) == 0)
696                 g_hash_table_remove_all(interface_table);
697
698         if (strlen(new) > 0 && strlen(old) == 0)
699                 supplicant_bootstrap();
700 }
701
702 static void signal_interface_added(const char *path, DBusMessageIter *iter)
703 {
704         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
705                 interface_added(iter, NULL);
706 }
707
708 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
709 {
710         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
711                 interface_removed(iter, NULL);
712 }
713
714 static void signal_bss_added(const char *path, DBusMessageIter *iter)
715 {
716         struct supplicant_interface *interface;
717
718         interface = g_hash_table_lookup(interface_table, path);
719         if (interface == NULL)
720                 return;
721
722         interface_bss_added(iter, interface);
723 }
724
725 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
726 {
727         struct supplicant_interface *interface;
728
729         interface = g_hash_table_lookup(interface_table, path);
730         if (interface == NULL)
731                 return;
732
733         interface_bss_removed(iter, interface);
734 }
735
736 static struct {
737         const char *interface;
738         const char *member;
739         void (*function) (const char *path, DBusMessageIter *iter);
740 } signal_map[] = {
741         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged", signal_name_owner_changed },
742         { SUPPLICANT_INTERFACE, "InterfaceAdded",   signal_interface_added    },
743         { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added    },
744         { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed  },
745         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",   signal_bss_added   },
746         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
747         { }
748 };
749
750 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
751                                         DBusMessage *message, void *data)
752 {
753         DBusMessageIter iter;
754         const char *path;
755         int i;
756
757         path = dbus_message_get_path(message);
758         if (path == NULL)
759                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
760
761         if (dbus_message_iter_init(message, &iter) == FALSE)
762                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
763
764         for (i = 0; signal_map[i].interface != NULL; i++) {
765                 if (dbus_message_has_interface(message,
766                                         signal_map[i].interface) == FALSE)
767                         continue;
768
769                 if (dbus_message_has_member(message,
770                                         signal_map[i].member) == FALSE)
771                         continue;
772
773                 signal_map[i].function(path, &iter);
774                 break;
775         }
776
777         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
778 }
779
780 static const char *supplicant_rule0 = "type=signal,"
781                                         "path=" DBUS_PATH_DBUS ","
782                                         "sender=" DBUS_SERVICE_DBUS ","
783                                         "interface=" DBUS_INTERFACE_DBUS ","
784                                         "member=NameOwnerChanged,"
785                                         "arg0=" SUPPLICANT_SERVICE;
786 static const char *supplicant_rule1 = "type=signal,"
787                         "interface=" SUPPLICANT_INTERFACE;
788 static const char *supplicant_rule2 = "type=signal,"
789                         "interface=" SUPPLICANT_INTERFACE ".Interface";
790 static const char *supplicant_rule3 = "type=signal,"
791                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
792 static const char *supplicant_rule4 = "type=signal,"
793                         "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
794 static const char *supplicant_rule5 = "type=signal,"
795                         "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
796 static const char *supplicant_rule6 = "type=signal,"
797                         "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
798
799 int supplicant_register(const struct supplicant_callbacks *callbacks)
800 {
801         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
802         if (connection == NULL)
803                 return -EIO;
804
805         if (dbus_connection_add_filter(connection,
806                                 supplicant_filter, NULL, NULL) == FALSE) {
807                 dbus_connection_unref(connection);
808                 connection = NULL;
809                 return -EIO;
810         }
811
812         callbacks_pointer = callbacks;
813         eap_methods = 0;
814
815         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
816                                                 NULL, remove_interface);
817
818         supplicant_dbus_setup(connection);
819
820         dbus_bus_add_match(connection, supplicant_rule0, NULL);
821         dbus_bus_add_match(connection, supplicant_rule1, NULL);
822         dbus_bus_add_match(connection, supplicant_rule2, NULL);
823         dbus_bus_add_match(connection, supplicant_rule3, NULL);
824         dbus_bus_add_match(connection, supplicant_rule4, NULL);
825         dbus_bus_add_match(connection, supplicant_rule5, NULL);
826         dbus_bus_add_match(connection, supplicant_rule6, NULL);
827         dbus_connection_flush(connection);
828
829         supplicant_bootstrap();
830
831         return 0;
832 }
833
834 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
835 {
836         if (connection != NULL) {
837                 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
838                 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
839                 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
840                 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
841                 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
842                 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
843                 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
844                 dbus_connection_flush(connection);
845
846                 dbus_connection_remove_filter(connection,
847                                                 supplicant_filter, NULL);
848         }
849
850         if (interface_table != NULL) {
851                 g_hash_table_destroy(interface_table);
852                 interface_table = NULL;
853         }
854
855         if (connection != NULL) {
856                 dbus_connection_unref(connection);
857                 connection = NULL;
858         }
859
860         callbacks_pointer = NULL;
861         eap_methods = 0;
862 }