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