Add support for network properties in supplicant test program
[platform/upstream/connman.git] / tools / supplicant.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-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 <string.h>
28 #include <stdint.h>
29 #include <syslog.h>
30
31 #include <glib.h>
32 #include <gdbus.h>
33
34 #include "supplicant-dbus.h"
35 #include "supplicant.h"
36
37 #define DBG(fmt, arg...) do { \
38         syslog(LOG_DEBUG, "%s() " fmt, __FUNCTION__ , ## arg); \
39 } while (0)
40
41 #define TIMEOUT 5000
42
43 #define IEEE80211_CAP_ESS       0x0001
44 #define IEEE80211_CAP_IBSS      0x0002
45 #define IEEE80211_CAP_PRIVACY   0x0010
46
47 static DBusConnection *connection;
48
49 static const struct supplicant_callbacks *callbacks_pointer;
50
51 static dbus_bool_t system_available = FALSE;
52 static dbus_bool_t system_ready = FALSE;
53
54 static dbus_int32_t debug_level = 0;
55 static dbus_bool_t debug_timestamp = FALSE;
56 static dbus_bool_t debug_showkeys = FALSE;
57
58 static const char *debug_strings[] = {
59         "msgdump", "debug", "info", "warning", "error", NULL
60 };
61
62 static unsigned int eap_methods;
63
64 struct strvalmap {
65         const char *str;
66         unsigned int val;
67 };
68
69 static struct strvalmap eap_method_map[] = {
70         { "MD5",        SUPPLICANT_EAP_METHOD_MD5       },
71         { "TLS",        SUPPLICANT_EAP_METHOD_TLS       },
72         { "MSCHAPV2",   SUPPLICANT_EAP_METHOD_MSCHAPV2  },
73         { "PEAP",       SUPPLICANT_EAP_METHOD_PEAP      },
74         { "TTLS",       SUPPLICANT_EAP_METHOD_TTLS      },
75         { "GTC",        SUPPLICANT_EAP_METHOD_GTC       },
76         { "OTP",        SUPPLICANT_EAP_METHOD_OTP       },
77         { "LEAP",       SUPPLICANT_EAP_METHOD_LEAP      },
78         { "WSC",        SUPPLICANT_EAP_METHOD_WSC       },
79         { }
80 };
81
82 static struct strvalmap keymgmt_capa_map[] = {
83         { "none",       SUPPLICANT_CAPABILITY_KEYMGMT_NONE      },
84         { "ieee8021x",  SUPPLICANT_CAPABILITY_KEYMGMT_IEEE8021X },
85         { "wpa-none",   SUPPLICANT_CAPABILITY_KEYMGMT_WPA_NONE  },
86         { "wpa-psk",    SUPPLICANT_CAPABILITY_KEYMGMT_WPA_PSK   },
87         { "wpa-eap",    SUPPLICANT_CAPABILITY_KEYMGMT_WPA_EAP   },
88         { "wps",        SUPPLICANT_CAPABILITY_KEYMGMT_WPS       },
89         { }
90 };
91
92 static struct strvalmap authalg_capa_map[] = {
93         { "open",       SUPPLICANT_CAPABILITY_AUTHALG_OPEN      },
94         { "shared",     SUPPLICANT_CAPABILITY_AUTHALG_SHARED    },
95         { "leap",       SUPPLICANT_CAPABILITY_AUTHALG_LEAP      },
96         { }
97 };
98
99 static struct strvalmap proto_capa_map[] = {
100         { "wpa",        SUPPLICANT_CAPABILITY_PROTO_WPA         },
101         { "rsn",        SUPPLICANT_CAPABILITY_PROTO_RSN         },
102         { }
103 };
104
105 static struct strvalmap group_capa_map[] = {
106         { "wep40",      SUPPLICANT_CAPABILITY_GROUP_WEP40       },
107         { "wep104",     SUPPLICANT_CAPABILITY_GROUP_WEP104      },
108         { "tkip",       SUPPLICANT_CAPABILITY_GROUP_TKIP        },
109         { "ccmp",       SUPPLICANT_CAPABILITY_GROUP_CCMP        },
110         { }
111 };
112
113 static struct strvalmap pairwise_capa_map[] = {
114         { "none",       SUPPLICANT_CAPABILITY_PAIRWISE_NONE     },
115         { "tkip",       SUPPLICANT_CAPABILITY_PAIRWISE_TKIP     },
116         { "ccmp",       SUPPLICANT_CAPABILITY_PAIRWISE_CCMP     },
117         { }
118 };
119
120 static struct strvalmap scan_capa_map[] = {
121         { "active",     SUPPLICANT_CAPABILITY_SCAN_ACTIVE       },
122         { "passive",    SUPPLICANT_CAPABILITY_SCAN_PASSIVE      },
123         { "ssid",       SUPPLICANT_CAPABILITY_SCAN_SSID         },
124         { }
125 };
126
127 static struct strvalmap mode_capa_map[] = {
128         { "infrastructure",     SUPPLICANT_CAPABILITY_MODE_INFRA        },
129         { "ad-hoc",             SUPPLICANT_CAPABILITY_MODE_IBSS         },
130         { "ap",                 SUPPLICANT_CAPABILITY_MODE_AP           },
131         { }
132 };
133
134 static GHashTable *interface_table;
135
136 struct supplicant_interface {
137         char *path;
138         unsigned int keymgmt_capa;
139         unsigned int authalg_capa;
140         unsigned int proto_capa;
141         unsigned int group_capa;
142         unsigned int pairwise_capa;
143         unsigned int scan_capa;
144         unsigned int mode_capa;
145         dbus_bool_t ready;
146         enum supplicant_state state;
147         dbus_bool_t scanning;
148         supplicant_interface_scan_callback scan_callback;
149         void *scan_data;
150         int apscan;
151         char *ifname;
152         char *driver;
153         char *bridge;
154         GHashTable *network_table;
155         GHashTable *net_mapping;
156         GHashTable *bss_mapping;
157 };
158
159 struct supplicant_network {
160         struct supplicant_interface *interface;
161         char *path;
162         char *group;
163         char *name;
164         enum supplicant_mode mode;
165         GHashTable *bss_table;
166         GHashTable *config_table;
167 };
168
169 struct supplicant_bss {
170         struct supplicant_interface *interface;
171         char *path;
172         unsigned char bssid[6];
173         unsigned char ssid[32];
174         unsigned int ssid_len;
175         dbus_uint16_t frequency;
176         dbus_uint32_t maxrate;
177         enum supplicant_mode mode;
178         enum supplicant_security security;
179         dbus_bool_t privacy;
180         dbus_bool_t psk;
181         dbus_bool_t ieee8021x;
182 };
183
184 static enum supplicant_mode string2mode(const char *mode)
185 {
186         if (mode == NULL)
187                 return SUPPLICANT_MODE_UNKNOWN;
188
189         if (g_str_equal(mode, "infrastructure") == TRUE)
190                 return SUPPLICANT_MODE_INFRA;
191         else if (g_str_equal(mode, "ad-hoc") == TRUE)
192                 return SUPPLICANT_MODE_IBSS;
193
194         return SUPPLICANT_MODE_UNKNOWN;
195 }
196
197 static const char *mode2string(enum supplicant_mode mode)
198 {
199         switch (mode) {
200         case SUPPLICANT_MODE_UNKNOWN:
201                 break;
202         case SUPPLICANT_MODE_INFRA:
203                 return "infra";
204         case SUPPLICANT_MODE_IBSS:
205                 return "adhoc";
206         }
207
208         return NULL;
209 }
210
211 static const char *security2string(enum supplicant_security security)
212 {
213         switch (security) {
214         case SUPPLICANT_SECURITY_UNKNOWN:
215                 break;
216         case SUPPLICANT_SECURITY_NONE:
217                 return "none";
218         case SUPPLICANT_SECURITY_WEP:
219                 return "wep";
220         case SUPPLICANT_SECURITY_PSK:
221                 return "psk";
222         case SUPPLICANT_SECURITY_IEEE8021X:
223                 return "ieee8021x";
224         }
225
226         return NULL;
227 }
228
229 static enum supplicant_state string2state(const char *state)
230 {
231         if (state == NULL)
232                 return SUPPLICANT_STATE_UNKNOWN;
233
234         if (g_str_equal(state, "unknown") == TRUE)
235                 return SUPPLICANT_STATE_UNKNOWN;
236         else if (g_str_equal(state, "disconnected") == TRUE)
237                 return SUPPLICANT_STATE_DISCONNECTED;
238         else if (g_str_equal(state, "inactive") == TRUE)
239                 return SUPPLICANT_STATE_INACTIVE;
240         else if (g_str_equal(state, "scanning") == TRUE)
241                 return SUPPLICANT_STATE_SCANNING;
242         else if (g_str_equal(state, "authenticating") == TRUE)
243                 return SUPPLICANT_STATE_AUTHENTICATING;
244         else if (g_str_equal(state, "associating") == TRUE)
245                 return SUPPLICANT_STATE_ASSOCIATING;
246         else if (g_str_equal(state, "associated") == TRUE)
247                 return SUPPLICANT_STATE_ASSOCIATED;
248         else if (g_str_equal(state, "group_handshake") == TRUE)
249                 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
250         else if (g_str_equal(state, "4way_handshake") == TRUE)
251                 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
252         else if (g_str_equal(state, "completed") == TRUE)
253                 return SUPPLICANT_STATE_COMPLETED;
254
255         return SUPPLICANT_STATE_UNKNOWN;
256 }
257
258 static void callback_system_ready(void)
259 {
260         if (system_ready == TRUE)
261                 return;
262
263         system_ready = TRUE;
264
265         if (callbacks_pointer == NULL)
266                 return;
267
268         if (callbacks_pointer->system_ready == NULL)
269                 return;
270
271         callbacks_pointer->system_ready();
272 }
273
274 static void callback_system_killed(void)
275 {
276         system_ready = FALSE;
277
278         if (callbacks_pointer == NULL)
279                 return;
280
281         if (callbacks_pointer->system_killed == NULL)
282                 return;
283
284         callbacks_pointer->system_killed();
285 }
286
287 static void callback_interface_added(struct supplicant_interface *interface)
288 {
289         if (callbacks_pointer == NULL)
290                 return;
291
292         if (callbacks_pointer->interface_added == NULL)
293                 return;
294
295         callbacks_pointer->interface_added(interface);
296 }
297
298 static void callback_interface_removed(struct supplicant_interface *interface)
299 {
300         if (callbacks_pointer == NULL)
301                 return;
302
303         if (callbacks_pointer->interface_removed == NULL)
304                 return;
305
306         callbacks_pointer->interface_removed(interface);
307 }
308
309 static void callback_scan_started(struct supplicant_interface *interface)
310 {
311         if (callbacks_pointer == NULL)
312                 return;
313
314         if (callbacks_pointer->scan_started == NULL)
315                 return;
316
317         callbacks_pointer->scan_started(interface);
318 }
319
320 static void callback_scan_finished(struct supplicant_interface *interface)
321 {
322         if (callbacks_pointer == NULL)
323                 return;
324
325         if (callbacks_pointer->scan_finished == NULL)
326                 return;
327
328         callbacks_pointer->scan_finished(interface);
329 }
330
331 static void callback_network_added(struct supplicant_network *network)
332 {
333         if (callbacks_pointer == NULL)
334                 return;
335
336         if (callbacks_pointer->network_added == NULL)
337                 return;
338
339         callbacks_pointer->network_added(network);
340 }
341
342 static void callback_network_removed(struct supplicant_network *network)
343 {
344         if (callbacks_pointer == NULL)
345                 return;
346
347         if (callbacks_pointer->network_removed == NULL)
348                 return;
349
350         callbacks_pointer->network_removed(network);
351 }
352
353 static void remove_interface(gpointer data)
354 {
355         struct supplicant_interface *interface = data;
356
357         g_hash_table_destroy(interface->bss_mapping);
358         g_hash_table_destroy(interface->net_mapping);
359         g_hash_table_destroy(interface->network_table);
360
361         callback_interface_removed(interface);
362
363         g_free(interface->path);
364         g_free(interface->ifname);
365         g_free(interface->driver);
366         g_free(interface->bridge);
367         g_free(interface);
368 }
369
370 static void remove_network(gpointer data)
371 {
372         struct supplicant_network *network = data;
373
374         g_hash_table_destroy(network->bss_table);
375
376         callback_network_removed(network);
377
378         g_hash_table_destroy(network->config_table);
379
380         g_free(network->group);
381         g_free(network->name);
382         g_free(network);
383 }
384
385 static void remove_bss(gpointer data)
386 {
387         struct supplicant_bss *bss = data;
388
389         g_free(bss->path);
390         g_free(bss);
391 }
392
393 static void debug_strvalmap(const char *label, struct strvalmap *map,
394                                                         unsigned int val)
395 {
396         int i;
397
398         for (i = 0; map[i].str != NULL; i++) {
399                 if (val & map[i].val)
400                         DBG("%s: %s", label, map[i].str);
401         }
402 }
403
404 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
405 {
406         struct supplicant_interface *interface = user_data;
407         const char *str = NULL;
408         int i;
409
410         dbus_message_iter_get_basic(iter, &str);
411         if (str == NULL)
412                 return;
413
414         for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
415                 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
416                         interface->keymgmt_capa |= keymgmt_capa_map[i].val;
417                         break;
418                 }
419 }
420
421 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
422 {
423         struct supplicant_interface *interface = user_data;
424         const char *str = NULL;
425         int i;
426
427         dbus_message_iter_get_basic(iter, &str);
428         if (str == NULL)
429                 return;
430
431         for (i = 0; authalg_capa_map[i].str != NULL; i++)
432                 if (strcmp(str, authalg_capa_map[i].str) == 0) {
433                         interface->authalg_capa |= authalg_capa_map[i].val;
434                         break;
435                 }
436 }
437
438 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
439 {
440         struct supplicant_interface *interface = user_data;
441         const char *str = NULL;
442         int i;
443
444         dbus_message_iter_get_basic(iter, &str);
445         if (str == NULL)
446                 return;
447
448         for (i = 0; proto_capa_map[i].str != NULL; i++)
449                 if (strcmp(str, proto_capa_map[i].str) == 0) {
450                         interface->proto_capa |= proto_capa_map[i].val;
451                         break;
452                 }
453 }
454
455 static void interface_capability_pairwise(DBusMessageIter *iter, void *user_data)
456 {
457         struct supplicant_interface *interface = user_data;
458         const char *str = NULL;
459         int i;
460
461         dbus_message_iter_get_basic(iter, &str);
462         if (str == NULL)
463                 return;
464
465         for (i = 0; pairwise_capa_map[i].str != NULL; i++)
466                 if (strcmp(str, pairwise_capa_map[i].str) == 0) {
467                         interface->pairwise_capa |= pairwise_capa_map[i].val;
468                         break;
469                 }
470 }
471
472 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
473 {
474         struct supplicant_interface *interface = user_data;
475         const char *str = NULL;
476         int i;
477
478         dbus_message_iter_get_basic(iter, &str);
479         if (str == NULL)
480                 return;
481
482         for (i = 0; group_capa_map[i].str != NULL; i++)
483                 if (strcmp(str, group_capa_map[i].str) == 0) {
484                         interface->group_capa |= group_capa_map[i].val;
485                         break;
486                 }
487 }
488
489 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
490 {
491         struct supplicant_interface *interface = user_data;
492         const char *str = NULL;
493         int i;
494
495         dbus_message_iter_get_basic(iter, &str);
496         if (str == NULL)
497                 return;
498
499         for (i = 0; scan_capa_map[i].str != NULL; i++)
500                 if (strcmp(str, scan_capa_map[i].str) == 0) {
501                         interface->scan_capa |= scan_capa_map[i].val;
502                         break;
503                 }
504 }
505
506 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
507 {
508         struct supplicant_interface *interface = user_data;
509         const char *str = NULL;
510         int i;
511
512         dbus_message_iter_get_basic(iter, &str);
513         if (str == NULL)
514                 return;
515
516         for (i = 0; mode_capa_map[i].str != NULL; i++)
517                 if (strcmp(str, mode_capa_map[i].str) == 0) {
518                         interface->mode_capa |= mode_capa_map[i].val;
519                         break;
520                 }
521 }
522
523 static void interface_capability(const char *key, DBusMessageIter *iter,
524                                                         void *user_data)
525 {
526         struct supplicant_interface *interface = user_data;
527
528         if (key == NULL)
529                 return;
530
531         if (g_strcmp0(key, "KeyMgmt") == 0)
532                 supplicant_dbus_array_foreach(iter,
533                                 interface_capability_keymgmt, interface);
534         else if (g_strcmp0(key, "AuthAlg") == 0)
535                 supplicant_dbus_array_foreach(iter,
536                                 interface_capability_authalg, interface);
537         else if (g_strcmp0(key, "Protocol") == 0)
538                 supplicant_dbus_array_foreach(iter,
539                                 interface_capability_proto, interface);
540         else if (g_strcmp0(key, "Pairwise") == 0)
541                 supplicant_dbus_array_foreach(iter,
542                                 interface_capability_pairwise, interface);
543         else if (g_strcmp0(key, "Group") == 0)
544                 supplicant_dbus_array_foreach(iter,
545                                 interface_capability_group, interface);
546         else if (g_strcmp0(key, "Scan") == 0)
547                 supplicant_dbus_array_foreach(iter,
548                                 interface_capability_scan, interface);
549         else if (g_strcmp0(key, "Modes") == 0)
550                 supplicant_dbus_array_foreach(iter,
551                                 interface_capability_mode, interface);
552         else
553                 DBG("key %s type %c",
554                                 key, dbus_message_iter_get_arg_type(iter));
555 }
556
557 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
558 {
559         if (interface == NULL)
560                 return NULL;
561
562         return interface->ifname;
563 }
564
565 const char *supplicant_interface_get_driver(struct supplicant_interface *interface)
566 {
567         if (interface == NULL)
568                 return NULL;
569
570         return interface->driver;
571 }
572
573 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
574 {
575         if (network == NULL)
576                 return NULL;
577
578         return network->interface;
579 }
580
581 const char *supplicant_network_get_name(struct supplicant_network *network)
582 {
583         if (network == NULL || network->name == NULL)
584                 return "";
585
586         return network->name;
587 }
588
589 const char *supplicant_network_get_identifier(struct supplicant_network *network)
590 {
591         if (network == NULL || network->group == NULL)
592                 return "";
593
594         return network->group;
595 }
596
597 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
598 {
599         if (network == NULL)
600                 return SUPPLICANT_MODE_UNKNOWN;
601
602         return network->mode;
603 }
604
605 static void merge_network(struct supplicant_network *network)
606 {
607         GString *str;
608         const char *ssid, *mode, *key_mgmt;
609         unsigned int i, ssid_len;
610         char *group;
611
612         ssid = g_hash_table_lookup(network->config_table, "ssid");
613         mode = g_hash_table_lookup(network->config_table, "mode");
614         key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
615
616         DBG("ssid %s mode %s", ssid, mode);
617
618         if (ssid != NULL)
619                 ssid_len = strlen(ssid);
620         else
621                 ssid_len = 0;
622
623         str = g_string_sized_new((ssid_len * 2) + 24);
624         if (str == NULL)
625                 return;
626
627         for (i = 0; i < ssid_len; i++)
628                 g_string_append_printf(str, "%02x", ssid[i]);
629
630         if (g_strcmp0(mode, "0") == 0)
631                 g_string_append_printf(str, "_infra");
632         else if (g_strcmp0(mode, "1") == 0)
633                 g_string_append_printf(str, "_adhoc");
634
635         if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
636                 g_string_append_printf(str, "_psk");
637
638         group = g_string_free(str, FALSE);
639
640         DBG("%s", group);
641
642         g_free(group);
643
644         g_hash_table_destroy(network->config_table);
645
646         g_free(network->path);
647         g_free(network);
648 }
649
650 static void network_property(const char *key, DBusMessageIter *iter,
651                                                         void *user_data)
652 {
653         struct supplicant_network *network = user_data;
654
655         if (network->interface == NULL)
656                 return;
657
658         if (key == NULL) {
659                 merge_network(network);
660                 return;
661         }
662
663         if (g_strcmp0(key, "Enabled") == 0) {
664                 dbus_bool_t enabled = FALSE;
665
666                 dbus_message_iter_get_basic(iter, &enabled);
667         } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
668                 const char *str = NULL;
669
670                 dbus_message_iter_get_basic(iter, &str);
671                 if (str != NULL)
672                         g_hash_table_replace(network->config_table,
673                                                 g_strdup(key), g_strdup(str));
674         } else
675                 DBG("key %s type %c",
676                                 key, dbus_message_iter_get_arg_type(iter));
677 }
678
679 static void interface_network_added(DBusMessageIter *iter, void *user_data)
680 {
681         struct supplicant_interface *interface = user_data;
682         struct supplicant_network *network;
683         const char *path = NULL;
684
685         dbus_message_iter_get_basic(iter, &path);
686         if (path == NULL)
687                 return;
688
689         if (g_strcmp0(path, "/") == 0)
690                 return;
691
692         network = g_hash_table_lookup(interface->net_mapping, path);
693         if (network != NULL)
694                 return;
695
696         network = g_try_new0(struct supplicant_network, 1);
697         if (network == NULL)
698                 return;
699
700         network->interface = interface;
701         network->path = g_strdup(path);
702
703         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
704                                                         g_free, g_free);
705
706         dbus_message_iter_next(iter);
707         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
708                 supplicant_dbus_property_foreach(iter, network_property,
709                                                                 network);
710                 network_property(NULL, NULL, network);
711                 return;
712         }
713
714         supplicant_dbus_property_get_all(path,
715                                 SUPPLICANT_INTERFACE ".Interface.Network",
716                                                 network_property, network);
717 }
718
719 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
720 {
721         struct supplicant_interface *interface = user_data;
722         struct supplicant_network *network;
723         const char *path = NULL;
724
725         dbus_message_iter_get_basic(iter, &path);
726         if (path == NULL)
727                 return;
728
729         network = g_hash_table_lookup(interface->net_mapping, path);
730         if (network == NULL)
731                 return;
732
733         g_hash_table_remove(interface->net_mapping, path);
734 }
735
736 static char *create_name(unsigned char *ssid, int ssid_len)
737 {
738         char *name;
739         int i;
740
741         if (ssid_len < 1 || ssid[0] == '\0')
742                 name = NULL;
743         else
744                 name = g_try_malloc0(ssid_len + 1);
745
746         if (name == NULL)
747                 return g_strdup("");
748
749         for (i = 0; i < ssid_len; i++) {
750                 if (g_ascii_isprint(ssid[i]))
751                         name[i] = ssid[i];
752                 else
753                         name[i] = ' ';
754         }
755
756         return name;
757 }
758
759 static char *create_group(struct supplicant_bss *bss)
760 {
761         GString *str;
762         unsigned int i;
763         const char *mode, *security;
764
765         str = g_string_sized_new((bss->ssid_len * 2) + 24);
766         if (str == NULL)
767                 return NULL;
768
769         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
770                 for (i = 0; i < bss->ssid_len; i++)
771                         g_string_append_printf(str, "%02x", bss->ssid[i]);
772         } else
773                 g_string_append_printf(str, "hidden");
774
775         mode = mode2string(bss->mode);
776         if (mode != NULL)
777                 g_string_append_printf(str, "_%s", mode);
778
779         security = security2string(bss->security);
780         if (security != NULL)
781                 g_string_append_printf(str, "_%s", security);
782
783         return g_string_free(str, FALSE);
784 }
785
786 static void add_bss_to_network(struct supplicant_bss *bss)
787 {
788         struct supplicant_interface *interface = bss->interface;
789         struct supplicant_network *network;
790         char *group;
791
792         group = create_group(bss);
793         if (group == NULL)
794                 return;
795
796         network = g_hash_table_lookup(interface->network_table, group);
797         if (network != NULL) {
798                 g_free(group);
799                 goto done;
800         }
801
802         network = g_try_new0(struct supplicant_network, 1);
803         if (network == NULL) {
804                 g_free(group);
805                 return;
806         }
807
808         network->group = group;
809         network->name = create_name(bss->ssid, bss->ssid_len);
810         network->mode = bss->mode;
811
812         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
813                                                         NULL, remove_bss);
814
815         network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
816                                                         g_free, g_free);
817
818         g_hash_table_replace(interface->network_table,
819                                                 network->group, network);
820
821         callback_network_added(network);
822
823 done:
824         g_hash_table_replace(interface->bss_mapping, bss->path, network);
825         g_hash_table_replace(network->bss_table, bss->path, bss);
826 }
827
828 static unsigned char wifi_oui[3]      = { 0x00, 0x50, 0xf2 };
829 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
830
831 static void extract_rsn(struct supplicant_bss *bss,
832                                         const unsigned char *buf, int len)
833 {
834         uint16_t count;
835         int i;
836
837         /* Version */
838         if (len < 2)
839                 return;
840
841         buf += 2;
842         len -= 2;
843
844         /* Group cipher */
845         if (len < 4)
846                 return;
847
848         buf += 4;
849         len -= 4;
850
851         /* Pairwise cipher */
852         if (len < 2)
853                 return;
854
855         count = buf[0] | (buf[1] << 8);
856         if (2 + (count * 4) > len)
857                 return;
858
859         buf += 2 + (count * 4);
860         len -= 2 + (count * 4);
861
862         /* Authentication */
863         if (len < 2)
864                 return;
865
866         count = buf[0] | (buf[1] << 8);
867         if (2 + (count * 4) > len)
868                 return;
869
870         for (i = 0; i < count; i++) {
871                 const unsigned char *ptr = buf + 2 + (i * 4);
872
873                 if (memcmp(ptr, wifi_oui, 3) == 0) {
874                         switch (ptr[3]) {
875                         case 1:
876                                 bss->ieee8021x = TRUE;
877                                 break;
878                         case 2:
879                                 bss->psk = TRUE;
880                                 break;
881                         }
882                 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
883                         switch (ptr[3]) {
884                         case 1:
885                                 bss->ieee8021x = TRUE;
886                                 break;
887                         case 2:
888                                 bss->psk = TRUE;
889                                 break;
890                         }
891                 }
892         }
893
894         buf += 2 + (count * 4);
895         len -= 2 + (count * 4);
896 }
897
898 static void bss_rates(DBusMessageIter *iter, void *user_data)
899 {
900         struct supplicant_bss *bss = user_data;
901         dbus_uint32_t rate = 0;
902
903         dbus_message_iter_get_basic(iter, &rate);
904         if (rate == 0)
905                 return;
906
907         if (rate > bss->maxrate)
908                 bss->maxrate = rate;
909 }
910
911 static void bss_property(const char *key, DBusMessageIter *iter,
912                                                         void *user_data)
913 {
914         struct supplicant_bss *bss = user_data;
915
916         if (bss->interface == NULL)
917                 return;
918
919         if (key == NULL) {
920                 if (bss->ieee8021x == TRUE)
921                         bss->security = SUPPLICANT_SECURITY_IEEE8021X;
922                 else if (bss->psk == TRUE)
923                         bss->security = SUPPLICANT_SECURITY_PSK;
924                 else if (bss->privacy == TRUE)
925                         bss->security = SUPPLICANT_SECURITY_WEP;
926                 else
927                         bss->security = SUPPLICANT_SECURITY_NONE;
928
929                 add_bss_to_network(bss);
930                 return;
931         }
932
933         if (g_strcmp0(key, "BSSID") == 0) {
934                 DBusMessageIter array;
935                 unsigned char *addr;
936                 int addr_len;
937
938                 dbus_message_iter_recurse(iter, &array);
939                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
940
941                 if (addr_len == 6)
942                         memcpy(bss->bssid, addr, addr_len);
943         } else if (g_strcmp0(key, "SSID") == 0) {
944                 DBusMessageIter array;
945                 unsigned char *ssid;
946                 int ssid_len;
947
948                 dbus_message_iter_recurse(iter, &array);
949                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
950
951                 if (ssid_len > 0 && ssid_len < 33) {
952                         memcpy(bss->ssid, ssid, ssid_len);
953                         bss->ssid_len = ssid_len;
954                 } else {
955                         memset(bss->ssid, 0, sizeof(bss->ssid));
956                         bss->ssid_len = 0;
957                 }
958         } else if (g_strcmp0(key, "Capabilities") == 0) {
959                 dbus_uint16_t capabilities = 0x0000;
960
961                 dbus_message_iter_get_basic(iter, &capabilities);
962
963                 if (capabilities & IEEE80211_CAP_ESS)
964                         bss->mode = SUPPLICANT_MODE_INFRA;
965                 else if (capabilities & IEEE80211_CAP_IBSS)
966                         bss->mode = SUPPLICANT_MODE_IBSS;
967
968                 if (capabilities & IEEE80211_CAP_PRIVACY)
969                         bss->privacy = TRUE;
970         } else if (g_strcmp0(key, "Mode") == 0) {
971                 const char *mode = NULL;
972
973                 dbus_message_iter_get_basic(iter, &mode);
974                 bss->mode = string2mode(mode);
975         } else if (g_strcmp0(key, "Frequency") == 0) {
976                 dbus_uint16_t frequency = 0;
977
978                 dbus_message_iter_get_basic(iter, &frequency);
979                 bss->frequency = frequency;
980         } else if (g_strcmp0(key, "Signal") == 0) {
981                 dbus_int16_t signal = 0;
982
983                 dbus_message_iter_get_basic(iter, &signal);
984         } else if (g_strcmp0(key, "Level") == 0) {
985                 dbus_int32_t level = 0;
986
987                 dbus_message_iter_get_basic(iter, &level);
988         } else if (g_strcmp0(key, "Rates") == 0) {
989                 supplicant_dbus_array_foreach(iter, bss_rates, bss);
990         } else if (g_strcmp0(key, "MaxRate") == 0) {
991                 dbus_uint32_t maxrate = 0;
992
993                 dbus_message_iter_get_basic(iter, &maxrate);
994                 if (maxrate != 0)
995                         bss->maxrate =maxrate;
996         } else if (g_strcmp0(key, "Privacy") == 0) {
997                 dbus_bool_t privacy = FALSE;
998
999                 dbus_message_iter_get_basic(iter, &privacy);
1000                 bss->privacy = privacy;
1001         } else if (g_strcmp0(key, "RSNIE") == 0) {
1002                 DBusMessageIter array;
1003                 unsigned char *ie;
1004                 int ie_len;
1005
1006                 dbus_message_iter_recurse(iter, &array);
1007                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1008
1009                 if (ie_len > 2)
1010                         extract_rsn(bss, ie + 2, ie_len - 2);
1011         } else if (g_strcmp0(key, "WPAIE") == 0) {
1012                 DBusMessageIter array;
1013                 unsigned char *ie;
1014                 int ie_len;
1015
1016                 dbus_message_iter_recurse(iter, &array);
1017                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1018
1019                 if (ie_len > 6)
1020                         extract_rsn(bss, ie + 6, ie_len - 6);
1021         } else if (g_strcmp0(key, "WPSIE") == 0) {
1022                 DBusMessageIter array;
1023                 unsigned char *ie;
1024                 int ie_len;
1025
1026                 dbus_message_iter_recurse(iter, &array);
1027                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1028         } else
1029                 DBG("key %s type %c",
1030                                 key, dbus_message_iter_get_arg_type(iter));
1031 }
1032
1033 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
1034 {
1035         struct supplicant_interface *interface = user_data;
1036         struct supplicant_network *network;
1037         struct supplicant_bss *bss;
1038         const char *path = NULL;
1039
1040         dbus_message_iter_get_basic(iter, &path);
1041         if (path == NULL)
1042                 return;
1043
1044         if (g_strcmp0(path, "/") == 0)
1045                 return;
1046
1047         network = g_hash_table_lookup(interface->bss_mapping, path);
1048         if (network != NULL) {
1049                 bss = g_hash_table_lookup(network->bss_table, path);
1050                 if (bss != NULL)
1051                         return;
1052         }
1053
1054         bss = g_try_new0(struct supplicant_bss, 1);
1055         if (bss == NULL)
1056                 return;
1057
1058         bss->interface = interface;
1059         bss->path = g_strdup(path);
1060
1061         dbus_message_iter_next(iter);
1062         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1063                 supplicant_dbus_property_foreach(iter, bss_property, bss);
1064                 bss_property(NULL, NULL, bss);
1065                 return;
1066         }
1067
1068         supplicant_dbus_property_get_all(path,
1069                                         SUPPLICANT_INTERFACE ".Interface.BSS",
1070                                                         bss_property, bss);
1071 }
1072
1073 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
1074 {
1075         struct supplicant_interface *interface = user_data;
1076         struct supplicant_network *network;
1077         const char *path = NULL;
1078
1079         dbus_message_iter_get_basic(iter, &path);
1080         if (path == NULL)
1081                 return;
1082
1083         network = g_hash_table_lookup(interface->bss_mapping, path);
1084         if (network == NULL)
1085                 return;
1086
1087         g_hash_table_remove(interface->bss_mapping, path);
1088         g_hash_table_remove(network->bss_table, path);
1089
1090         if (g_hash_table_size(network->bss_table) == 0)
1091                 g_hash_table_remove(interface->network_table, network->group);
1092 }
1093
1094 static void interface_property(const char *key, DBusMessageIter *iter,
1095                                                         void *user_data)
1096 {
1097         struct supplicant_interface *interface = user_data;
1098
1099         if (interface == NULL)
1100                 return;
1101
1102         if (key == NULL) {
1103                 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
1104                                                 interface->keymgmt_capa);
1105                 debug_strvalmap("AuthAlg capability", authalg_capa_map,
1106                                                 interface->authalg_capa);
1107                 debug_strvalmap("Protocol capability", proto_capa_map,
1108                                                 interface->proto_capa);
1109                 debug_strvalmap("Pairwise capability", pairwise_capa_map,
1110                                                 interface->pairwise_capa);
1111                 debug_strvalmap("Group capability", group_capa_map,
1112                                                 interface->group_capa);
1113                 debug_strvalmap("Scan capability", scan_capa_map,
1114                                                 interface->scan_capa);
1115                 debug_strvalmap("Mode capability", mode_capa_map,
1116                                                 interface->mode_capa);
1117
1118                 interface->ready = TRUE;
1119                 callback_interface_added(interface);
1120                 return;
1121         }
1122
1123         if (g_strcmp0(key, "Capabilities") == 0) {
1124                 supplicant_dbus_property_foreach(iter, interface_capability,
1125                                                                 interface);
1126         } else if (g_strcmp0(key, "State") == 0) {
1127                 const char *str = NULL;
1128
1129                 dbus_message_iter_get_basic(iter, &str);
1130                 if (str != NULL)
1131                         interface->state = string2state(str);
1132
1133                 DBG("state %s (%d)", str, interface->state);
1134         } else if (g_strcmp0(key, "Scanning") == 0) {
1135                 dbus_bool_t scanning = FALSE;
1136
1137                 dbus_message_iter_get_basic(iter, &scanning);
1138                 interface->scanning = scanning;
1139
1140                 if (interface->ready == TRUE) {
1141                         if (interface->scanning == TRUE)
1142                                 callback_scan_started(interface);
1143                         else
1144                                 callback_scan_finished(interface);
1145                 }
1146         } else if (g_strcmp0(key, "ApScan") == 0) {
1147                 int apscan = 1;
1148
1149                 dbus_message_iter_get_basic(iter, &apscan);
1150                 interface->apscan = apscan;
1151         } else if (g_strcmp0(key, "Ifname") == 0) {
1152                 const char *str = NULL;
1153
1154                 dbus_message_iter_get_basic(iter, &str);
1155                 if (str != NULL)
1156                         interface->ifname = g_strdup(str);
1157         } else if (g_strcmp0(key, "Driver") == 0) {
1158                 const char *str = NULL;
1159
1160                 dbus_message_iter_get_basic(iter, &str);
1161                 if (str != NULL)
1162                         interface->driver = g_strdup(str);
1163         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1164                 const char *str = NULL;
1165
1166                 dbus_message_iter_get_basic(iter, &str);
1167                 if (str != NULL)
1168                         interface->bridge = g_strdup(str);
1169         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1170                 interface_bss_added(iter, interface);
1171         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1172                 interface_network_added(iter, interface);
1173         } else if (g_strcmp0(key, "BSSs") == 0) {
1174                 supplicant_dbus_array_foreach(iter, interface_bss_added,
1175                                                                 interface);
1176         } else if (g_strcmp0(key, "Blobs") == 0) {
1177         } else if (g_strcmp0(key, "Networks") == 0) {
1178                 supplicant_dbus_array_foreach(iter, interface_network_added,
1179                                                                 interface);
1180         } else
1181                 DBG("key %s type %c",
1182                                 key, dbus_message_iter_get_arg_type(iter));
1183 }
1184
1185 static struct supplicant_interface *interface_alloc(const char *path)
1186 {
1187         struct supplicant_interface *interface;
1188
1189         interface = g_try_new0(struct supplicant_interface, 1);
1190         if (interface == NULL)
1191                 return NULL;
1192
1193         interface->path = g_strdup(path);
1194
1195         interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1196                                                         NULL, remove_network);
1197
1198         interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1199                                                                 NULL, NULL);
1200         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1201                                                                 NULL, NULL);
1202
1203         g_hash_table_replace(interface_table, interface->path, interface);
1204
1205         return interface;
1206 }
1207
1208 static void interface_added(DBusMessageIter *iter, void *user_data)
1209 {
1210         struct supplicant_interface *interface;
1211         const char *path = NULL;
1212
1213         dbus_message_iter_get_basic(iter, &path);
1214         if (path == NULL)
1215                 return;
1216
1217         if (g_strcmp0(path, "/") == 0)
1218                 return;
1219
1220         interface = g_hash_table_lookup(interface_table, path);
1221         if (interface != NULL)
1222                 return;
1223
1224         interface = interface_alloc(path);
1225         if (interface == NULL)
1226                 return;
1227
1228         dbus_message_iter_next(iter);
1229         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1230                 supplicant_dbus_property_foreach(iter, interface_property,
1231                                                                 interface);
1232                 interface_property(NULL, NULL, interface);
1233                 return;
1234         }
1235
1236         supplicant_dbus_property_get_all(path,
1237                                         SUPPLICANT_INTERFACE ".Interface",
1238                                                 interface_property, interface);
1239 }
1240
1241 static void interface_removed(DBusMessageIter *iter, void *user_data)
1242 {
1243         const char *path = NULL;
1244
1245         dbus_message_iter_get_basic(iter, &path);
1246         if (path == NULL)
1247                 return;
1248
1249         g_hash_table_remove(interface_table, path);
1250 }
1251
1252 static void eap_method(DBusMessageIter *iter, void *user_data)
1253 {
1254         const char *str = NULL;
1255         int i;
1256
1257         dbus_message_iter_get_basic(iter, &str);
1258         if (str == NULL)
1259                 return;
1260
1261         for (i = 0; eap_method_map[i].str != NULL; i++)
1262                 if (strcmp(str, eap_method_map[i].str) == 0) {
1263                         eap_methods |= eap_method_map[i].val;
1264                         break;
1265                 }
1266 }
1267
1268 static void service_property(const char *key, DBusMessageIter *iter,
1269                                                         void *user_data)
1270 {
1271         if (key == NULL) {
1272                 callback_system_ready();
1273                 return;
1274         }
1275
1276         if (g_strcmp0(key, "DebugLevel") == 0) {
1277                 const char *str = NULL;
1278                 int i;
1279
1280                 dbus_message_iter_get_basic(iter, &str);
1281                 for (i = 0; debug_strings[i] != NULL; i++)
1282                         if (g_strcmp0(debug_strings[i], str) == 0) {
1283                                 debug_level = i;
1284                                 break;
1285                         }
1286                 DBG("Debug level %d", debug_level);
1287         } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
1288                 dbus_message_iter_get_basic(iter, &debug_timestamp);
1289                 DBG("Debug timestamp %u", debug_timestamp);
1290         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1291                 dbus_message_iter_get_basic(iter, &debug_showkeys);
1292                 DBG("Debug show keys %u", debug_showkeys);
1293         } else if (g_strcmp0(key, "Interfaces") == 0) {
1294                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1295         } else if (g_strcmp0(key, "EapMethods") == 0) {
1296                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1297                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1298         } else
1299                 DBG("key %s type %c",
1300                                 key, dbus_message_iter_get_arg_type(iter));
1301 }
1302
1303 static void supplicant_bootstrap(void)
1304 {
1305         supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1306                                                 SUPPLICANT_INTERFACE,
1307                                                 service_property, NULL);
1308 }
1309
1310 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1311 {
1312         const char *name = NULL, *old = NULL, *new = NULL;
1313
1314         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1315                 return;
1316
1317         dbus_message_iter_get_basic(iter, &name);
1318         if (name == NULL)
1319                 return;
1320
1321         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1322                 return;
1323
1324         dbus_message_iter_next(iter);
1325         dbus_message_iter_get_basic(iter, &old);
1326         dbus_message_iter_next(iter);
1327         dbus_message_iter_get_basic(iter, &new);
1328
1329         if (old == NULL || new == NULL)
1330                 return;
1331
1332         if (strlen(old) > 0 && strlen(new) == 0) {
1333                 system_available = FALSE;
1334                 g_hash_table_remove_all(interface_table);
1335                 callback_system_killed();
1336         }
1337
1338         if (strlen(new) > 0 && strlen(old) == 0) {
1339                 system_available = TRUE;
1340                 supplicant_bootstrap();
1341         }
1342 }
1343
1344 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1345 {
1346         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1347                 return;
1348
1349         supplicant_dbus_property_foreach(iter, service_property, NULL);
1350 }
1351
1352 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1353 {
1354         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1355                 interface_added(iter, NULL);
1356 }
1357
1358 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1359 {
1360         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1361                 interface_removed(iter, NULL);
1362 }
1363
1364 static void signal_properties(const char *path, DBusMessageIter *iter)
1365 {
1366         struct supplicant_interface *interface;
1367
1368         interface = g_hash_table_lookup(interface_table, path);
1369         if (interface == NULL)
1370                 return;
1371
1372         supplicant_dbus_property_foreach(iter, interface_property, interface);
1373 }
1374
1375 static void signal_scan_done(const char *path, DBusMessageIter *iter)
1376 {
1377         struct supplicant_interface *interface;
1378         dbus_bool_t success = FALSE;
1379
1380         interface = g_hash_table_lookup(interface_table, path);
1381         if (interface == NULL)
1382                 return;
1383
1384         dbus_message_iter_get_basic(iter, &success);
1385
1386         if (interface->scan_callback != NULL) {
1387                 int result = 0;
1388
1389                 if (success == FALSE)
1390                         result = -EIO;
1391
1392                 interface->scan_callback(result, interface->scan_data);
1393         }
1394
1395         interface->scan_callback = NULL;
1396         interface->scan_data = NULL;
1397 }
1398
1399 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1400 {
1401         struct supplicant_interface *interface;
1402
1403         interface = g_hash_table_lookup(interface_table, path);
1404         if (interface == NULL)
1405                 return;
1406
1407         interface_bss_added(iter, interface);
1408 }
1409
1410 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1411 {
1412         struct supplicant_interface *interface;
1413
1414         interface = g_hash_table_lookup(interface_table, path);
1415         if (interface == NULL)
1416                 return;
1417
1418         interface_bss_removed(iter, interface);
1419 }
1420
1421 static void signal_network_added(const char *path, DBusMessageIter *iter)
1422 {
1423         struct supplicant_interface *interface;
1424
1425         interface = g_hash_table_lookup(interface_table, path);
1426         if (interface == NULL)
1427                 return;
1428
1429         interface_network_added(iter, interface);
1430 }
1431
1432 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1433 {
1434         struct supplicant_interface *interface;
1435
1436         interface = g_hash_table_lookup(interface_table, path);
1437         if (interface == NULL)
1438                 return;
1439
1440         interface_network_removed(iter, interface);
1441 }
1442
1443 static struct {
1444         const char *interface;
1445         const char *member;
1446         void (*function) (const char *path, DBusMessageIter *iter);
1447 } signal_map[] = {
1448         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
1449
1450         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1451         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
1452         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
1453         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
1454
1455         { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_properties      },
1456         { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done       },
1457         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added       },
1458         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed     },
1459         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added   },
1460         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed },
1461
1462         { }
1463 };
1464
1465 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1466                                         DBusMessage *message, void *data)
1467 {
1468         DBusMessageIter iter;
1469         const char *path;
1470         int i;
1471
1472         path = dbus_message_get_path(message);
1473         if (path == NULL)
1474                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1475
1476         if (dbus_message_iter_init(message, &iter) == FALSE)
1477                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1478
1479         for (i = 0; signal_map[i].interface != NULL; i++) {
1480                 if (dbus_message_has_interface(message,
1481                                         signal_map[i].interface) == FALSE)
1482                         continue;
1483
1484                 if (dbus_message_has_member(message,
1485                                         signal_map[i].member) == FALSE)
1486                         continue;
1487
1488                 signal_map[i].function(path, &iter);
1489                 break;
1490         }
1491
1492         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1493 }
1494
1495 static const char *supplicant_rule0 = "type=signal,"
1496                                         "path=" DBUS_PATH_DBUS ","
1497                                         "sender=" DBUS_SERVICE_DBUS ","
1498                                         "interface=" DBUS_INTERFACE_DBUS ","
1499                                         "member=NameOwnerChanged,"
1500                                         "arg0=" SUPPLICANT_SERVICE;
1501 static const char *supplicant_rule1 = "type=signal,"
1502                         "interface=" SUPPLICANT_INTERFACE;
1503 static const char *supplicant_rule2 = "type=signal,"
1504                         "interface=" SUPPLICANT_INTERFACE ".Interface";
1505 static const char *supplicant_rule3 = "type=signal,"
1506                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1507 static const char *supplicant_rule4 = "type=signal,"
1508                         "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1509 static const char *supplicant_rule5 = "type=signal,"
1510                         "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1511 static const char *supplicant_rule6 = "type=signal,"
1512                         "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1513
1514 int supplicant_register(const struct supplicant_callbacks *callbacks)
1515 {
1516         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1517         if (connection == NULL)
1518                 return -EIO;
1519
1520         if (dbus_connection_add_filter(connection,
1521                                 supplicant_filter, NULL, NULL) == FALSE) {
1522                 dbus_connection_unref(connection);
1523                 connection = NULL;
1524                 return -EIO;
1525         }
1526
1527         callbacks_pointer = callbacks;
1528         eap_methods = 0;
1529
1530         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1531                                                 NULL, remove_interface);
1532
1533         supplicant_dbus_setup(connection);
1534
1535         dbus_bus_add_match(connection, supplicant_rule0, NULL);
1536         dbus_bus_add_match(connection, supplicant_rule1, NULL);
1537         dbus_bus_add_match(connection, supplicant_rule2, NULL);
1538         dbus_bus_add_match(connection, supplicant_rule3, NULL);
1539         dbus_bus_add_match(connection, supplicant_rule4, NULL);
1540         dbus_bus_add_match(connection, supplicant_rule5, NULL);
1541         dbus_bus_add_match(connection, supplicant_rule6, NULL);
1542         dbus_connection_flush(connection);
1543
1544         if (dbus_bus_name_has_owner(connection,
1545                                         SUPPLICANT_SERVICE, NULL) == TRUE) {
1546                 system_available = TRUE;
1547                 supplicant_bootstrap();
1548         }
1549
1550         return 0;
1551 }
1552
1553 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1554 {
1555         if (connection != NULL) {
1556                 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1557                 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1558                 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1559                 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1560                 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1561                 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1562                 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1563                 dbus_connection_flush(connection);
1564
1565                 dbus_connection_remove_filter(connection,
1566                                                 supplicant_filter, NULL);
1567         }
1568
1569         if (interface_table != NULL) {
1570                 g_hash_table_destroy(interface_table);
1571                 interface_table = NULL;
1572         }
1573
1574         if (system_available == TRUE)
1575                 callback_system_killed();
1576
1577         if (connection != NULL) {
1578                 dbus_connection_unref(connection);
1579                 connection = NULL;
1580         }
1581
1582         callbacks_pointer = NULL;
1583         eap_methods = 0;
1584 }
1585
1586 static void debug_level_result(const char *error,
1587                                 DBusMessageIter *iter, void *user_data)
1588 {
1589         if (error != NULL)
1590                 DBG("debug level failure: %s", error);
1591 }
1592
1593 static void debug_level_params(DBusMessageIter *iter, void *user_data)
1594 {
1595         guint level = GPOINTER_TO_UINT(user_data);
1596         const char *str;
1597
1598         if (level > 4)
1599                 level = 4;
1600
1601         str = debug_strings[level];
1602
1603         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
1604 }
1605
1606 void supplicant_set_debug_level(unsigned int level)
1607 {
1608         if (system_available == FALSE)
1609                 return;
1610
1611         supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1612                                 "DebugLevel", DBUS_TYPE_STRING_AS_STRING,
1613                                 debug_level_params, debug_level_result,
1614                                                 GUINT_TO_POINTER(level));
1615 }
1616
1617 struct interface_create_data {
1618         const char *ifname;
1619         const char *driver;
1620         struct supplicant_interface *interface;
1621         supplicant_interface_create_callback callback;
1622         void *user_data;
1623 };
1624
1625 static void interface_create_property(const char *key, DBusMessageIter *iter,
1626                                                         void *user_data)
1627 {
1628         struct interface_create_data *data = user_data;
1629         struct supplicant_interface *interface = data->interface;
1630
1631         if (key == NULL) {
1632                 if (data->callback != NULL)
1633                         data->callback(0, data->interface, data->user_data);
1634
1635                 dbus_free(data);
1636         }
1637
1638         interface_property(key, iter, interface);
1639 }
1640
1641 static void interface_create_result(const char *error,
1642                                 DBusMessageIter *iter, void *user_data)
1643 {
1644         struct interface_create_data *data = user_data;
1645         const char *path = NULL;
1646         int err;
1647
1648         if (error != NULL) {
1649                 err = -EIO;
1650                 goto done;
1651         }
1652
1653         dbus_message_iter_get_basic(iter, &path);
1654         if (path == NULL) {
1655                 err = -EINVAL;
1656                 goto done;
1657         }
1658
1659         if (system_available == FALSE) {
1660                 err = -EFAULT;
1661                 goto done;
1662         }
1663
1664         data->interface = g_hash_table_lookup(interface_table, path);
1665         if (data->interface == NULL) {
1666                 data->interface = interface_alloc(path);
1667                 if (data->interface == NULL) {
1668                         err = -ENOMEM;
1669                         goto done;
1670                 }
1671         }
1672
1673         err = supplicant_dbus_property_get_all(path,
1674                                         SUPPLICANT_INTERFACE ".Interface",
1675                                         interface_create_property, data);
1676         if (err == 0)
1677                 return;
1678
1679 done:
1680         if (data->callback != NULL)
1681                 data->callback(err, NULL, data->user_data);
1682
1683         dbus_free(data);
1684 }
1685
1686 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1687 {
1688         struct interface_create_data *data = user_data;
1689         DBusMessageIter dict;
1690
1691         supplicant_dbus_dict_open(iter, &dict);
1692
1693         supplicant_dbus_dict_append_basic(&dict, "Ifname",
1694                                         DBUS_TYPE_STRING, &data->ifname);
1695
1696         if (data->driver != NULL)
1697                 supplicant_dbus_dict_append_basic(&dict, "Driver",
1698                                         DBUS_TYPE_STRING, &data->driver);
1699
1700         supplicant_dbus_dict_close(iter, &dict);
1701 }
1702
1703 static void interface_get_result(const char *error,
1704                                 DBusMessageIter *iter, void *user_data)
1705 {
1706         struct interface_create_data *data = user_data;
1707         struct supplicant_interface *interface;
1708         const char *path = NULL;
1709         int err;
1710
1711         if (error != NULL) {
1712                 err = -EIO;
1713                 goto create;
1714         }
1715
1716         dbus_message_iter_get_basic(iter, &path);
1717         if (path == NULL) {
1718                 err = -EINVAL;
1719                 goto done;
1720         }
1721
1722         interface = g_hash_table_lookup(interface_table, path);
1723         if (interface == NULL) {
1724                 err = -ENOENT;
1725                 goto done;
1726         }
1727
1728         if (data->callback != NULL)
1729                 data->callback(0, interface, data->user_data);
1730
1731         dbus_free(data);
1732
1733         return;
1734
1735 create:
1736         if (system_available == FALSE) {
1737                 err = -EFAULT;
1738                 goto done;
1739         }
1740
1741         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1742                                                 SUPPLICANT_INTERFACE,
1743                                                 "CreateInterface",
1744                                                 interface_create_params,
1745                                                 interface_create_result, data);
1746         if (err == 0)
1747                 return;
1748
1749 done:
1750         if (data->callback != NULL)
1751                 data->callback(err, NULL, data->user_data);
1752
1753         dbus_free(data);
1754 }
1755
1756 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1757 {
1758         struct interface_create_data *data = user_data;
1759
1760         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1761 }
1762
1763 int supplicant_interface_create(const char *ifname, const char *driver,
1764                         supplicant_interface_create_callback callback,
1765                                                         void *user_data)
1766 {
1767         struct interface_create_data *data;
1768
1769         if (ifname == NULL)
1770                 return -EINVAL;
1771
1772         if (system_available == FALSE)
1773                 return -EFAULT;
1774
1775         data = dbus_malloc0(sizeof(*data));
1776         if (data == NULL)
1777                 return -ENOMEM;
1778
1779         data->ifname = ifname;
1780         data->driver = driver;
1781         data->callback = callback;
1782         data->user_data = user_data;
1783
1784         return supplicant_dbus_method_call(SUPPLICANT_PATH,
1785                                                 SUPPLICANT_INTERFACE,
1786                                                 "GetInterface",
1787                                                 interface_get_params,
1788                                                 interface_get_result, data);
1789 }
1790
1791 int supplicant_interface_remove(struct supplicant_interface *interface,
1792                         supplicant_interface_remove_callback callback,
1793                                                         void *user_data)
1794 {
1795         if (interface == NULL)
1796                 return -EINVAL;
1797
1798         if (system_available == FALSE)
1799                 return -EFAULT;
1800
1801         return 0;
1802 }
1803
1804 struct interface_scan_data {
1805         struct supplicant_interface *interface;
1806         supplicant_interface_scan_callback callback;
1807         void *user_data;
1808 };
1809
1810 static void interface_scan_result(const char *error,
1811                                 DBusMessageIter *iter, void *user_data)
1812 {
1813         struct interface_scan_data *data = user_data;
1814
1815         if (error != NULL) {
1816                 if (data->callback != NULL)
1817                         data->callback(-EIO, data->user_data);
1818         } else {
1819                 data->interface->scan_callback = data->callback;
1820                 data->interface->scan_data = data->user_data;
1821         }
1822
1823         dbus_free(data);
1824 }
1825
1826 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
1827 {
1828         DBusMessageIter dict;
1829         const char *type = "passive";
1830
1831         supplicant_dbus_dict_open(iter, &dict);
1832
1833         supplicant_dbus_dict_append_basic(&dict, "Type",
1834                                                 DBUS_TYPE_STRING, &type);
1835
1836         supplicant_dbus_dict_close(iter, &dict);
1837 }
1838
1839 int supplicant_interface_scan(struct supplicant_interface *interface,
1840                         supplicant_interface_scan_callback callback,
1841                                                         void *user_data)
1842 {
1843         struct interface_scan_data *data;
1844
1845         if (interface == NULL)
1846                 return -EINVAL;
1847
1848         if (system_available == FALSE)
1849                 return -EFAULT;
1850
1851         if (interface->scanning == TRUE)
1852                 return -EALREADY;
1853
1854         data = dbus_malloc0(sizeof(*data));
1855         if (data == NULL)
1856                 return -ENOMEM;
1857
1858         data->interface = interface;
1859         data->callback = callback;
1860         data->user_data = user_data;
1861
1862         return supplicant_dbus_method_call(interface->path,
1863                         SUPPLICANT_INTERFACE ".Interface", "Scan",
1864                         interface_scan_params, interface_scan_result, data);
1865 }
1866
1867 struct interface_disconnect_data {
1868         supplicant_interface_disconnect_callback callback;
1869         void *user_data;
1870 };
1871
1872 static void interface_disconnect_result(const char *error,
1873                                 DBusMessageIter *iter, void *user_data)
1874 {
1875         struct interface_disconnect_data *data = user_data;
1876         int result = 0;
1877
1878         if (error != NULL)
1879                 result = -EIO;
1880
1881         if (data->callback != NULL)
1882                 data->callback(result, data->user_data);
1883
1884         dbus_free(data);
1885 }
1886
1887 int supplicant_interface_disconnect(struct supplicant_interface *interface,
1888                         supplicant_interface_disconnect_callback callback,
1889                                                         void *user_data)
1890 {
1891         struct interface_disconnect_data *data;
1892
1893         if (interface == NULL)
1894                 return -EINVAL;
1895
1896         if (system_available == FALSE)
1897                 return -EFAULT;
1898
1899         data = dbus_malloc0(sizeof(*data));
1900         if (data == NULL)
1901                 return -ENOMEM;
1902
1903         data->callback = callback;
1904         data->user_data = user_data;
1905
1906         return supplicant_dbus_method_call(interface->path,
1907                         SUPPLICANT_INTERFACE ".Interface", "Disconnect",
1908                                 NULL, interface_disconnect_result, data);
1909 }