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