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