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