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