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