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