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