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