be429586177ca8e83fb928f466ecdd4d31d5304f
[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_val;
2178                 int key_len;
2179
2180                 dbus_message_iter_recurse(iter, &array);
2181                 dbus_message_iter_get_fixed_array(&array, &key_val, &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_val,
2191                                                 sizeof(char) * key_len);
2192
2193                 SUPPLICANT_DBG("WPS key present");
2194         } else if (g_strcmp0(key, "SSID") == 0) {
2195                 DBusMessageIter array;
2196                 unsigned char *ssid;
2197                 int ssid_len;
2198
2199                 dbus_message_iter_recurse(iter, &array);
2200                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
2201
2202                 if (ssid_len > 0 && ssid_len < 33) {
2203                         memcpy(interface->wps_cred.ssid, ssid, ssid_len);
2204                         interface->wps_cred.ssid_len = ssid_len;
2205                 } else {
2206                         memset(interface->wps_cred.ssid, 0, 32);
2207                         interface->wps_cred.ssid_len = 0;
2208                 }
2209         }
2210 }
2211
2212 static void signal_wps_credentials(const char *path, DBusMessageIter *iter)
2213 {
2214         GSupplicantInterface *interface;
2215
2216         SUPPLICANT_DBG("");
2217
2218         interface = g_hash_table_lookup(interface_table, path);
2219         if (interface == NULL)
2220                 return;
2221
2222         supplicant_dbus_property_foreach(iter, wps_credentials, interface);
2223 }
2224
2225 static void wps_event_args(const char *key, DBusMessageIter *iter,
2226                         void *user_data)
2227 {
2228         GSupplicantInterface *interface = user_data;
2229
2230         if (key == NULL || interface == NULL)
2231                 return;
2232
2233         SUPPLICANT_DBG("Arg Key %s", key);
2234 }
2235
2236 static void signal_wps_event(const char *path, DBusMessageIter *iter)
2237 {
2238         GSupplicantInterface *interface;
2239         const char *name = NULL;
2240
2241         SUPPLICANT_DBG("");
2242
2243         interface = g_hash_table_lookup(interface_table, path);
2244         if (interface == NULL)
2245                 return;
2246
2247         dbus_message_iter_get_basic(iter, &name);
2248
2249         SUPPLICANT_DBG("Name: %s", name);
2250
2251         if (g_strcmp0(name, "success") == 0)
2252                 interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
2253         else if (g_strcmp0(name, "failed") == 0)
2254                 interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
2255         else
2256                 interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
2257
2258         if (!dbus_message_iter_has_next(iter))
2259                 return;
2260
2261         dbus_message_iter_next(iter);
2262
2263         supplicant_dbus_property_foreach(iter, wps_event_args, interface);
2264 }
2265
2266 static struct {
2267         const char *interface;
2268         const char *member;
2269         void (*function) (const char *path, DBusMessageIter *iter);
2270 } signal_map[] = {
2271         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
2272
2273         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
2274         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
2275         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
2276         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
2277
2278         { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
2279         { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done         },
2280         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added         },
2281         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed       },
2282         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
2283         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
2284
2285         { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed   },
2286
2287         { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
2288         { SUPPLICANT_INTERFACE ".Interface.WPS", "Event",       signal_wps_event       },
2289
2290         { }
2291 };
2292
2293 static DBusHandlerResult g_supplicant_filter(DBusConnection *conn,
2294                                         DBusMessage *message, void *data)
2295 {
2296         DBusMessageIter iter;
2297         const char *path;
2298         int i;
2299
2300         path = dbus_message_get_path(message);
2301         if (path == NULL)
2302                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2303
2304         if (dbus_message_iter_init(message, &iter) == FALSE)
2305                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2306
2307         for (i = 0; signal_map[i].interface != NULL; i++) {
2308                 if (dbus_message_has_interface(message,
2309                                         signal_map[i].interface) == FALSE)
2310                         continue;
2311
2312                 if (dbus_message_has_member(message,
2313                                         signal_map[i].member) == FALSE)
2314                         continue;
2315
2316                 signal_map[i].function(path, &iter);
2317                 break;
2318         }
2319
2320         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2321 }
2322
2323 struct supplicant_regdom {
2324         GSupplicantCountryCallback callback;
2325         const char *alpha2;
2326         const void *user_data;
2327 };
2328
2329 static void country_result(const char *error,
2330                                 DBusMessageIter *iter, void *user_data)
2331 {
2332         struct supplicant_regdom *regdom = user_data;
2333         int result = 0;
2334
2335         SUPPLICANT_DBG("Country setting result");
2336
2337         if (user_data == NULL)
2338                 return;
2339
2340         if (error != NULL) {
2341                 SUPPLICANT_DBG("Country setting failure %s", error);
2342                 result = -EINVAL;
2343         }
2344
2345         if (regdom->callback)
2346                 regdom->callback(result, regdom->alpha2,
2347                                         (void *) regdom->user_data);
2348
2349         g_free(regdom);
2350 }
2351
2352 static void country_params(DBusMessageIter *iter, void *user_data)
2353 {
2354         struct supplicant_regdom *regdom = user_data;
2355
2356         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
2357                                                         &regdom->alpha2);
2358 }
2359
2360 int g_supplicant_set_country(const char *alpha2,
2361                                 GSupplicantCountryCallback callback,
2362                                         const void *user_data)
2363 {
2364         struct supplicant_regdom *regdom;
2365
2366         SUPPLICANT_DBG("Country setting %s", alpha2);
2367
2368         if (system_available == FALSE)
2369                 return -EFAULT;
2370
2371         regdom = dbus_malloc0(sizeof(*regdom));
2372         if (regdom == NULL)
2373                 return -ENOMEM;
2374
2375         regdom->callback = callback;
2376         regdom->alpha2 = alpha2;
2377         regdom->user_data = user_data;
2378
2379         return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
2380                                         "Country", DBUS_TYPE_STRING_AS_STRING,
2381                                         country_params, country_result,
2382                                                 regdom);
2383 }
2384
2385 int g_supplicant_interface_set_country(GSupplicantInterface *interface,
2386                                         GSupplicantCountryCallback callback,
2387                                                         const char *alpha2,
2388                                                         void *user_data)
2389 {
2390         struct supplicant_regdom *regdom;
2391
2392         regdom = dbus_malloc0(sizeof(*regdom));
2393         if (regdom == NULL)
2394                 return -ENOMEM;
2395
2396         regdom->callback = callback;
2397         regdom->alpha2 = alpha2;
2398         regdom->user_data = user_data;
2399
2400         return supplicant_dbus_property_set(interface->path,
2401                                 SUPPLICANT_INTERFACE ".Interface",
2402                                 "Country", DBUS_TYPE_STRING_AS_STRING,
2403                                 country_params, country_result,
2404                                         regdom);
2405 }
2406
2407 struct interface_data {
2408         GSupplicantInterface *interface;
2409         GSupplicantInterfaceCallback callback;
2410         void *user_data;
2411 };
2412
2413 struct interface_create_data {
2414         const char *ifname;
2415         const char *driver;
2416         const char *bridge;
2417         GSupplicantInterface *interface;
2418         GSupplicantInterfaceCallback callback;
2419         void *user_data;
2420 };
2421
2422 struct interface_connect_data {
2423         GSupplicantInterface *interface;
2424         GSupplicantInterfaceCallback callback;
2425         GSupplicantSSID *ssid;
2426         void *user_data;
2427 };
2428
2429 struct interface_scan_data {
2430         GSupplicantInterface *interface;
2431         GSupplicantInterfaceCallback callback;
2432         GSupplicantScanParams *scan_params;
2433         void *user_data;
2434 };
2435
2436 struct interface_autoscan_data {
2437         GSupplicantInterface *interface;
2438         GSupplicantInterfaceCallback callback;
2439         const char *autoscan_params;
2440         void *user_data;
2441 };
2442
2443 static void interface_create_property(const char *key, DBusMessageIter *iter,
2444                                                         void *user_data)
2445 {
2446         struct interface_create_data *data = user_data;
2447         GSupplicantInterface *interface = data->interface;
2448
2449         if (key == NULL) {
2450                 if (data->callback != NULL)
2451                         data->callback(0, data->interface, data->user_data);
2452
2453                 dbus_free(data);
2454         }
2455
2456         interface_property(key, iter, interface);
2457 }
2458
2459 static void interface_create_result(const char *error,
2460                                 DBusMessageIter *iter, void *user_data)
2461 {
2462         struct interface_create_data *data = user_data;
2463         const char *path = NULL;
2464         int err;
2465
2466         SUPPLICANT_DBG("");
2467
2468         if (error != NULL) {
2469                 g_warning("error %s", error);
2470                 err = -EIO;
2471                 goto done;
2472         }
2473
2474         dbus_message_iter_get_basic(iter, &path);
2475         if (path == NULL) {
2476                 err = -EINVAL;
2477                 goto done;
2478         }
2479
2480         if (system_available == FALSE) {
2481                 err = -EFAULT;
2482                 goto done;
2483         }
2484
2485         data->interface = g_hash_table_lookup(interface_table, path);
2486         if (data->interface == NULL) {
2487                 data->interface = interface_alloc(path);
2488                 if (data->interface == NULL) {
2489                         err = -ENOMEM;
2490                         goto done;
2491                 }
2492         }
2493
2494         err = supplicant_dbus_property_get_all(path,
2495                                         SUPPLICANT_INTERFACE ".Interface",
2496                                         interface_create_property, data);
2497         if (err == 0)
2498                 return;
2499
2500 done:
2501         if (data->callback != NULL)
2502                 data->callback(err, NULL, data->user_data);
2503
2504         dbus_free(data);
2505 }
2506
2507 static void interface_create_params(DBusMessageIter *iter, void *user_data)
2508 {
2509         struct interface_create_data *data = user_data;
2510         DBusMessageIter dict;
2511
2512         SUPPLICANT_DBG("");
2513
2514         supplicant_dbus_dict_open(iter, &dict);
2515
2516         supplicant_dbus_dict_append_basic(&dict, "Ifname",
2517                                         DBUS_TYPE_STRING, &data->ifname);
2518
2519         if (data->driver != NULL)
2520                 supplicant_dbus_dict_append_basic(&dict, "Driver",
2521                                         DBUS_TYPE_STRING, &data->driver);
2522
2523         if (data->bridge != NULL)
2524                 supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
2525                                         DBUS_TYPE_STRING, &data->bridge);
2526
2527         supplicant_dbus_dict_close(iter, &dict);
2528 }
2529
2530 static void interface_get_result(const char *error,
2531                                 DBusMessageIter *iter, void *user_data)
2532 {
2533         struct interface_create_data *data = user_data;
2534         GSupplicantInterface *interface;
2535         const char *path = NULL;
2536         int err;
2537
2538         SUPPLICANT_DBG("");
2539
2540         if (error != NULL) {
2541                 SUPPLICANT_DBG("Interface not created yet");
2542                 goto create;
2543         }
2544
2545         dbus_message_iter_get_basic(iter, &path);
2546         if (path == NULL) {
2547                 err = -EINVAL;
2548                 goto done;
2549         }
2550
2551         interface = g_hash_table_lookup(interface_table, path);
2552         if (interface == NULL) {
2553                 err = -ENOENT;
2554                 goto done;
2555         }
2556
2557         if (data->callback != NULL)
2558                 data->callback(0, interface, data->user_data);
2559
2560         dbus_free(data);
2561
2562         return;
2563
2564 create:
2565         if (system_available == FALSE) {
2566                 err = -EFAULT;
2567                 goto done;
2568         }
2569
2570         SUPPLICANT_DBG("Creating interface");
2571
2572         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
2573                                                 SUPPLICANT_INTERFACE,
2574                                                 "CreateInterface",
2575                                                 interface_create_params,
2576                                                 interface_create_result, data);
2577         if (err == 0)
2578                 return;
2579
2580 done:
2581         if (data->callback != NULL)
2582                 data->callback(err, NULL, data->user_data);
2583
2584         dbus_free(data);
2585 }
2586
2587 static void interface_get_params(DBusMessageIter *iter, void *user_data)
2588 {
2589         struct interface_create_data *data = user_data;
2590
2591         SUPPLICANT_DBG("");
2592
2593         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
2594 }
2595
2596 int g_supplicant_interface_create(const char *ifname, const char *driver,
2597                                         const char *bridge,
2598                                         GSupplicantInterfaceCallback callback,
2599                                                         void *user_data)
2600 {
2601         struct interface_create_data *data;
2602
2603         SUPPLICANT_DBG("ifname %s", ifname);
2604
2605         if (ifname == NULL)
2606                 return -EINVAL;
2607
2608         if (system_available == FALSE)
2609                 return -EFAULT;
2610
2611         data = dbus_malloc0(sizeof(*data));
2612         if (data == NULL)
2613                 return -ENOMEM;
2614
2615         data->ifname = ifname;
2616         data->driver = driver;
2617         data->bridge = bridge;
2618         data->callback = callback;
2619         data->user_data = user_data;
2620
2621         return supplicant_dbus_method_call(SUPPLICANT_PATH,
2622                                                 SUPPLICANT_INTERFACE,
2623                                                 "GetInterface",
2624                                                 interface_get_params,
2625                                                 interface_get_result, data);
2626 }
2627
2628 static void interface_remove_result(const char *error,
2629                                 DBusMessageIter *iter, void *user_data)
2630 {
2631         struct interface_data *data = user_data;
2632         int err;
2633
2634         if (error != NULL) {
2635                 err = -EIO;
2636                 goto done;
2637         }
2638
2639         if (system_available == FALSE) {
2640                 err = -EFAULT;
2641                 goto done;
2642         }
2643
2644         /*
2645          * The gsupplicant interface is already freed by the InterfaceRemoved
2646          * signal callback. Simply invoke the interface_data callback.
2647          */
2648         err = 0;
2649
2650 done:
2651         if (data->callback != NULL)
2652                 data->callback(err, NULL, data->user_data);
2653
2654         dbus_free(data);
2655 }
2656
2657
2658 static void interface_remove_params(DBusMessageIter *iter, void *user_data)
2659 {
2660         struct interface_data *data = user_data;
2661
2662         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2663                                                         &data->interface->path);
2664 }
2665
2666
2667 int g_supplicant_interface_remove(GSupplicantInterface *interface,
2668                         GSupplicantInterfaceCallback callback,
2669                                                         void *user_data)
2670 {
2671         struct interface_data *data;
2672
2673         if (interface == NULL)
2674                 return -EINVAL;
2675
2676         if (system_available == FALSE)
2677                 return -EFAULT;
2678
2679         data = dbus_malloc0(sizeof(*data));
2680         if (data == NULL)
2681                 return -ENOMEM;
2682
2683         data->interface = interface;
2684         data->callback = callback;
2685         data->user_data = user_data;
2686
2687         return supplicant_dbus_method_call(SUPPLICANT_PATH,
2688                                                 SUPPLICANT_INTERFACE,
2689                                                 "RemoveInterface",
2690                                                 interface_remove_params,
2691                                                 interface_remove_result, data);
2692 }
2693
2694 static void interface_scan_result(const char *error,
2695                                 DBusMessageIter *iter, void *user_data)
2696 {
2697         struct interface_scan_data *data = user_data;
2698
2699         if (error != NULL) {
2700                 SUPPLICANT_DBG("error %s", error);
2701
2702                 if (data->callback != NULL)
2703                         data->callback(-EIO, data->interface, data->user_data);
2704         } else {
2705                 data->interface->scan_callback = data->callback;
2706                 data->interface->scan_data = data->user_data;
2707         }
2708
2709         if (data != NULL && data->scan_params != NULL)
2710                 g_supplicant_free_scan_params(data->scan_params);
2711
2712         dbus_free(data);
2713 }
2714
2715 static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq)
2716 {
2717         DBusMessageIter data;
2718         unsigned int width = 0; /* Not used by wpa_supplicant atm */
2719
2720         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data);
2721
2722         dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq);
2723         dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width);
2724
2725         dbus_message_iter_close_container(iter, &data);
2726 }
2727
2728 static void add_scan_frequencies(DBusMessageIter *iter,
2729                                                 void *user_data)
2730 {
2731         GSupplicantScanParams *scan_data = user_data;
2732         unsigned int freq;
2733         int i;
2734
2735         for (i = 0; i < scan_data->num_ssids; i++) {
2736                 freq = scan_data->freqs[i];
2737                 if (!freq)
2738                         break;
2739
2740                 add_scan_frequency(iter, freq);
2741         }
2742 }
2743
2744 static void append_ssid(DBusMessageIter *iter,
2745                         const void *ssid, unsigned int len)
2746 {
2747         DBusMessageIter array;
2748
2749         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
2750         DBUS_TYPE_BYTE_AS_STRING, &array);
2751
2752         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
2753                                                                 &ssid, len);
2754         dbus_message_iter_close_container(iter, &array);
2755 }
2756
2757 static void append_ssids(DBusMessageIter *iter, void *user_data)
2758 {
2759         GSupplicantScanParams *scan_data = user_data;
2760         GSList *list;
2761
2762         for (list = scan_data->ssids; list; list = list->next) {
2763                 struct scan_ssid *scan_ssid = list->data;
2764
2765                 append_ssid(iter, scan_ssid->ssid, scan_ssid->ssid_len);
2766         }
2767 }
2768
2769 static void supplicant_add_scan_frequency(DBusMessageIter *dict,
2770                 supplicant_dbus_array_function function,
2771                                         void *user_data)
2772 {
2773         GSupplicantScanParams *scan_params = user_data;
2774         DBusMessageIter entry, value, array;
2775         const char *key = "Channels";
2776
2777         if (scan_params->freqs && scan_params->freqs[0] != 0) {
2778                 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
2779                                                 NULL, &entry);
2780
2781                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
2782
2783                 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
2784                                         DBUS_TYPE_ARRAY_AS_STRING
2785                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2786                                         DBUS_TYPE_UINT32_AS_STRING
2787                                         DBUS_TYPE_UINT32_AS_STRING
2788                                         DBUS_STRUCT_END_CHAR_AS_STRING,
2789                                         &value);
2790
2791                 dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
2792                                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2793                                         DBUS_TYPE_UINT32_AS_STRING
2794                                         DBUS_TYPE_UINT32_AS_STRING
2795                                         DBUS_STRUCT_END_CHAR_AS_STRING,
2796                                         &array);
2797
2798                 if (function)
2799                         function(&array, user_data);
2800
2801                 dbus_message_iter_close_container(&value, &array);
2802                 dbus_message_iter_close_container(&entry, &value);
2803                 dbus_message_iter_close_container(dict, &entry);
2804         }
2805 }
2806
2807 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
2808 {
2809         DBusMessageIter dict;
2810         const char *type = "passive";
2811         struct interface_scan_data *data = user_data;
2812
2813         supplicant_dbus_dict_open(iter, &dict);
2814
2815         if (data && data->scan_params) {
2816                 type = "active";
2817
2818                 supplicant_dbus_dict_append_basic(&dict, "Type",
2819                                         DBUS_TYPE_STRING, &type);
2820
2821                 supplicant_dbus_dict_append_array(&dict, "SSIDs",
2822                                                 DBUS_TYPE_STRING,
2823                                                 append_ssids,
2824                                                 data->scan_params);
2825
2826                 supplicant_add_scan_frequency(&dict, add_scan_frequencies,
2827                                                 data->scan_params);
2828         } else
2829                 supplicant_dbus_dict_append_basic(&dict, "Type",
2830                                         DBUS_TYPE_STRING, &type);
2831
2832         supplicant_dbus_dict_close(iter, &dict);
2833 }
2834
2835 int g_supplicant_interface_scan(GSupplicantInterface *interface,
2836                                 GSupplicantScanParams *scan_data,
2837                                 GSupplicantInterfaceCallback callback,
2838                                                         void *user_data)
2839 {
2840         struct interface_scan_data *data;
2841         int ret;
2842
2843         if (interface == NULL)
2844                 return -EINVAL;
2845
2846         if (system_available == FALSE)
2847                 return -EFAULT;
2848
2849         if (interface->scanning == TRUE)
2850                 return -EALREADY;
2851
2852         switch (interface->state) {
2853         case G_SUPPLICANT_STATE_AUTHENTICATING:
2854         case G_SUPPLICANT_STATE_ASSOCIATING:
2855         case G_SUPPLICANT_STATE_ASSOCIATED:
2856         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2857         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2858                 return -EBUSY;
2859         case G_SUPPLICANT_STATE_UNKNOWN:
2860         case G_SUPPLICANT_STATE_DISCONNECTED:
2861         case G_SUPPLICANT_STATE_INACTIVE:
2862         case G_SUPPLICANT_STATE_SCANNING:
2863         case G_SUPPLICANT_STATE_COMPLETED:
2864                 break;
2865         }
2866
2867         data = dbus_malloc0(sizeof(*data));
2868         if (data == NULL)
2869                 return -ENOMEM;
2870
2871         data->interface = interface;
2872         data->callback = callback;
2873         data->user_data = user_data;
2874         data->scan_params = scan_data;
2875
2876         ret = supplicant_dbus_method_call(interface->path,
2877                         SUPPLICANT_INTERFACE ".Interface", "Scan",
2878                         interface_scan_params, interface_scan_result, data);
2879
2880         if (ret < 0)
2881                 dbus_free(data);
2882
2883         return ret;
2884 }
2885
2886 static void interface_autoscan_result(const char *error,
2887                                 DBusMessageIter *iter, void *user_data)
2888 {
2889         struct interface_autoscan_data *data = user_data;
2890         int err = 0;
2891
2892         if (error != NULL) {
2893                 SUPPLICANT_DBG("error %s", error);
2894                 err = -EIO;
2895         }
2896
2897         if (data != NULL && data->callback != NULL)
2898                 data->callback(err, data->interface, data->user_data);
2899
2900         dbus_free(data);
2901 }
2902
2903 static void interface_autoscan_params(DBusMessageIter *iter, void *user_data)
2904 {
2905         struct interface_autoscan_data *data = user_data;
2906
2907         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
2908                                                  &data->autoscan_params);
2909 }
2910
2911 int g_supplicant_interface_autoscan(GSupplicantInterface *interface,
2912                                         const char *autoscan_data,
2913                                         GSupplicantInterfaceCallback callback,
2914                                                         void *user_data)
2915 {
2916         struct interface_autoscan_data *data;
2917         int ret;
2918
2919         data = dbus_malloc0(sizeof(*data));
2920         if (data == NULL)
2921                 return -ENOMEM;
2922
2923         data->interface = interface;
2924         data->callback = callback;
2925         data->autoscan_params = autoscan_data;
2926         data->user_data = user_data;
2927
2928         ret = supplicant_dbus_method_call(interface->path,
2929                         SUPPLICANT_INTERFACE ".Interface", "AutoScan",
2930                         interface_autoscan_params,
2931                         interface_autoscan_result, data);
2932         if (ret < 0)
2933                 dbus_free(data);
2934
2935         return ret;
2936 }
2937
2938 static int parse_supplicant_error(DBusMessageIter *iter)
2939 {
2940         int err = -ECANCELED;
2941         char *key;
2942
2943         /* If the given passphrase is malformed wpa_s returns
2944          * "invalid message format" but this error should be interpreted as
2945          * invalid-key.
2946          */
2947         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
2948                 dbus_message_iter_get_basic(iter, &key);
2949                 if (strncmp(key, "psk", 3) == 0 ||
2950                                 strncmp(key, "wep_key", 7) == 0 ||
2951                                 strcmp(key, "invalid message format") == 0) {
2952                         err = -ENOKEY;
2953                         break;
2954                 }
2955                 dbus_message_iter_next(iter);
2956         }
2957
2958         return err;
2959 }
2960
2961 static void interface_select_network_result(const char *error,
2962                                 DBusMessageIter *iter, void *user_data)
2963 {
2964         struct interface_connect_data *data = user_data;
2965         int err;
2966
2967         SUPPLICANT_DBG("");
2968
2969         err = 0;
2970         if (error != NULL) {
2971                 SUPPLICANT_DBG("SelectNetwork error %s", error);
2972                 err = parse_supplicant_error(iter);
2973         }
2974
2975         if (data->callback != NULL)
2976                 data->callback(err, data->interface, data->user_data);
2977
2978         g_free(data->ssid);
2979         dbus_free(data);
2980 }
2981
2982 static void interface_select_network_params(DBusMessageIter *iter,
2983                                                         void *user_data)
2984 {
2985         struct interface_connect_data *data = user_data;
2986         GSupplicantInterface *interface = data->interface;
2987
2988         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2989                                         &interface->network_path);
2990 }
2991
2992 static void interface_add_network_result(const char *error,
2993                                 DBusMessageIter *iter, void *user_data)
2994 {
2995         struct interface_connect_data *data = user_data;
2996         GSupplicantInterface *interface = data->interface;
2997         const char *path;
2998         int err;
2999
3000         if (error != NULL)
3001                 goto error;
3002
3003         dbus_message_iter_get_basic(iter, &path);
3004         if (path == NULL)
3005                 goto error;
3006
3007         SUPPLICANT_DBG("PATH: %s", path);
3008
3009         g_free(interface->network_path);
3010         interface->network_path = g_strdup(path);
3011
3012         supplicant_dbus_method_call(data->interface->path,
3013                         SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
3014                         interface_select_network_params,
3015                         interface_select_network_result, data);
3016
3017         return;
3018
3019 error:
3020         SUPPLICANT_DBG("AddNetwork error %s", error);
3021         err = parse_supplicant_error(iter);
3022         if (data->callback != NULL)
3023                 data->callback(err, data->interface, data->user_data);
3024
3025         g_free(interface->network_path);
3026         interface->network_path = NULL;
3027         g_free(data->ssid);
3028         g_free(data);
3029 }
3030
3031 static void add_network_security_wep(DBusMessageIter *dict,
3032                                         GSupplicantSSID *ssid)
3033 {
3034         const char *auth_alg = "OPEN SHARED";
3035         const char *key_index = "0";
3036
3037         supplicant_dbus_dict_append_basic(dict, "auth_alg",
3038                                         DBUS_TYPE_STRING, &auth_alg);
3039
3040         if (ssid->passphrase) {
3041                 int size = strlen(ssid->passphrase);
3042                 if (size == 10 || size == 26) {
3043                         unsigned char *key = g_try_malloc(13);
3044                         char tmp[3];
3045                         int i;
3046
3047                         memset(tmp, 0, sizeof(tmp));
3048                         if (key == NULL)
3049                                 size = 0;
3050
3051                         for (i = 0; i < size / 2; i++) {
3052                                 memcpy(tmp, ssid->passphrase + (i * 2), 2);
3053                                 key[i] = (unsigned char) strtol(tmp, NULL, 16);
3054                         }
3055
3056                         supplicant_dbus_dict_append_fixed_array(dict,
3057                                                         "wep_key0",
3058                                                         DBUS_TYPE_BYTE,
3059                                                         &key, size / 2);
3060                         g_free(key);
3061                 } else if (size == 5 || size == 13) {
3062                         unsigned char *key = g_try_malloc(13);
3063                         int i;
3064
3065                         if (key == NULL)
3066                                 size = 0;
3067
3068                         for (i = 0; i < size; i++)
3069                                 key[i] = (unsigned char) ssid->passphrase[i];
3070
3071                         supplicant_dbus_dict_append_fixed_array(dict,
3072                                                                 "wep_key0",
3073                                                                 DBUS_TYPE_BYTE,
3074                                                                 &key, size);
3075                         g_free(key);
3076                 } else
3077                         supplicant_dbus_dict_append_basic(dict,
3078                                                         "wep_key0",
3079                                                         DBUS_TYPE_STRING,
3080                                                         &ssid->passphrase);
3081
3082                 supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx",
3083                                         DBUS_TYPE_STRING, &key_index);
3084         }
3085 }
3086
3087 static dbus_bool_t is_psk_raw_key(const char *psk)
3088 {
3089         int i;
3090
3091         /* A raw key is always 64 bytes length... */
3092         if (strlen(psk) != 64)
3093                 return FALSE;
3094
3095         /* ... and its content is in hex representation */
3096         for (i = 0; i < 64; i++)
3097                 if (!isxdigit((unsigned char) psk[i]))
3098                         return FALSE;
3099
3100         return TRUE;
3101 }
3102
3103 static unsigned char hexchar2bin(char c)
3104 {
3105         if ((c >= '0') && (c <= '9'))
3106                 return c - '0';
3107         else if ((c >= 'A') && (c <= 'F'))
3108                 return c - 'A' + 10;
3109         else if ((c >= 'a') && (c <= 'f'))
3110                 return c - 'a' + 10;
3111         else
3112                 return c;
3113 }
3114
3115 static void hexstring2bin(const char *string, unsigned char *data, size_t data_len)
3116 {
3117         size_t i;
3118
3119         for (i = 0; i < data_len; i++)
3120                 data[i] = (hexchar2bin(string[i * 2 + 0]) << 4 |
3121                            hexchar2bin(string[i * 2 + 1]) << 0);
3122 }
3123
3124 static void add_network_security_psk(DBusMessageIter *dict,
3125                                         GSupplicantSSID *ssid)
3126 {
3127         if (ssid->passphrase && strlen(ssid->passphrase) > 0) {
3128                 const char *key = "psk";
3129
3130                 if (is_psk_raw_key(ssid->passphrase) == TRUE) {
3131                         unsigned char data[32];
3132                         unsigned char *datap = data;
3133
3134                         /* The above pointer alias is required by D-Bus because
3135                          * with D-Bus and GCC, non-heap-allocated arrays cannot
3136                          * be passed directly by their base pointer. */
3137
3138                         hexstring2bin(ssid->passphrase, datap, sizeof(data));
3139
3140                         supplicant_dbus_dict_append_fixed_array(dict,
3141                                                         key, DBUS_TYPE_BYTE,
3142                                                         &datap, sizeof(data));
3143                 } else
3144                         supplicant_dbus_dict_append_basic(dict,
3145                                                         key, DBUS_TYPE_STRING,
3146                                                         &ssid->passphrase);
3147         }
3148 }
3149
3150 static void add_network_security_tls(DBusMessageIter *dict,
3151                                         GSupplicantSSID *ssid)
3152 {
3153         /*
3154          * For TLS, we at least need:
3155          *              The client certificate
3156          *              The client private key file
3157          *              The client private key file password
3158          *
3159          * The Authority certificate is optional.
3160          */
3161         if (ssid->client_cert_path == NULL)
3162                 return;
3163
3164         if (ssid->private_key_path == NULL)
3165                 return;
3166
3167         if (ssid->private_key_passphrase == NULL)
3168                 return;
3169
3170         if (ssid->ca_cert_path)
3171                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
3172                                         DBUS_TYPE_STRING, &ssid->ca_cert_path);
3173
3174         supplicant_dbus_dict_append_basic(dict, "private_key",
3175                                                 DBUS_TYPE_STRING,
3176                                                 &ssid->private_key_path);
3177         supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
3178                                                 DBUS_TYPE_STRING,
3179                                                 &ssid->private_key_passphrase);
3180         supplicant_dbus_dict_append_basic(dict, "client_cert",
3181                                                 DBUS_TYPE_STRING,
3182                                                 &ssid->client_cert_path);
3183 }
3184
3185 static void add_network_security_peap(DBusMessageIter *dict,
3186                                         GSupplicantSSID *ssid)
3187 {
3188         char *phase2_auth;
3189
3190         /*
3191          * For PEAP/TTLS, we at least need
3192          *              The authority certificate
3193          *              The 2nd phase authentication method
3194          *              The 2nd phase passphrase
3195          *
3196          * The Client certificate is optional although strongly recommended
3197          * When setting it, we need in addition
3198          *              The Client private key file
3199          *              The Client private key file password
3200          */
3201         if (ssid->passphrase == NULL)
3202                 return;
3203
3204         if (ssid->phase2_auth == NULL)
3205                 return;
3206
3207         if (ssid->client_cert_path) {
3208                 if (ssid->private_key_path == NULL)
3209                         return;
3210
3211                 if (ssid->private_key_passphrase == NULL)
3212                         return;
3213
3214                 supplicant_dbus_dict_append_basic(dict, "client_cert",
3215                                                 DBUS_TYPE_STRING,
3216                                                 &ssid->client_cert_path);
3217
3218                 supplicant_dbus_dict_append_basic(dict, "private_key",
3219                                                 DBUS_TYPE_STRING,
3220                                                 &ssid->private_key_path);
3221
3222                 supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
3223                                                 DBUS_TYPE_STRING,
3224                                                 &ssid->private_key_passphrase);
3225
3226         }
3227
3228         if (g_str_has_prefix(ssid->phase2_auth, "EAP-") == TRUE) {
3229                 phase2_auth = g_strdup_printf("autheap=%s",
3230                                         ssid->phase2_auth + strlen("EAP-"));
3231         } else
3232                 phase2_auth = g_strdup_printf("auth=%s", ssid->phase2_auth);
3233
3234         supplicant_dbus_dict_append_basic(dict, "password",
3235                                                 DBUS_TYPE_STRING,
3236                                                 &ssid->passphrase);
3237
3238         if (ssid->ca_cert_path)
3239                 supplicant_dbus_dict_append_basic(dict, "ca_cert",
3240                                                 DBUS_TYPE_STRING,
3241                                                 &ssid->ca_cert_path);
3242
3243         supplicant_dbus_dict_append_basic(dict, "phase2",
3244                                                 DBUS_TYPE_STRING,
3245                                                 &phase2_auth);
3246
3247         g_free(phase2_auth);
3248 }
3249
3250 static void add_network_security_eap(DBusMessageIter *dict,
3251                                         GSupplicantSSID *ssid)
3252 {
3253         char *eap_value;
3254
3255         if (ssid->eap == NULL || ssid->identity == NULL)
3256                 return;
3257
3258         if (g_strcmp0(ssid->eap, "tls") == 0) {
3259                 add_network_security_tls(dict, ssid);
3260         } else if (g_strcmp0(ssid->eap, "peap") == 0 ||
3261                                 g_strcmp0(ssid->eap, "ttls") == 0) {
3262                 add_network_security_peap(dict, ssid);
3263         } else
3264                 return;
3265
3266         eap_value = g_ascii_strup(ssid->eap, -1);
3267
3268         supplicant_dbus_dict_append_basic(dict, "eap",
3269                                                 DBUS_TYPE_STRING,
3270                                                 &eap_value);
3271         supplicant_dbus_dict_append_basic(dict, "identity",
3272                                                 DBUS_TYPE_STRING,
3273                                                 &ssid->identity);
3274
3275         g_free(eap_value);
3276 }
3277
3278 static void add_network_security_ciphers(DBusMessageIter *dict,
3279                                                 GSupplicantSSID *ssid)
3280 {
3281         unsigned int p_cipher, g_cipher, i;
3282         char *pairwise, *group;
3283         char *pair_ciphers[4];
3284         char *group_ciphers[5];
3285
3286         p_cipher = ssid->pairwise_cipher;
3287         g_cipher = ssid->group_cipher;
3288
3289         if (p_cipher == 0 && g_cipher == 0)
3290                 return;
3291
3292         i = 0;
3293
3294         if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP)
3295                 pair_ciphers[i++] = "CCMP";
3296
3297         if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP)
3298                 pair_ciphers[i++] = "TKIP";
3299
3300         if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE)
3301                 pair_ciphers[i++] = "NONE";
3302
3303         pair_ciphers[i] = NULL;
3304
3305         i = 0;
3306
3307         if (g_cipher & G_SUPPLICANT_GROUP_CCMP)
3308                 group_ciphers[i++] = "CCMP";
3309
3310         if (g_cipher & G_SUPPLICANT_GROUP_TKIP)
3311                 group_ciphers[i++] = "TKIP";
3312
3313         if (g_cipher & G_SUPPLICANT_GROUP_WEP104)
3314                 group_ciphers[i++] = "WEP104";
3315
3316         if (g_cipher & G_SUPPLICANT_GROUP_WEP40)
3317                 group_ciphers[i++] = "WEP40";
3318
3319         group_ciphers[i] = NULL;
3320
3321         pairwise = g_strjoinv(" ", pair_ciphers);
3322         group = g_strjoinv(" ", group_ciphers);
3323
3324         SUPPLICANT_DBG("cipher %s %s", pairwise, group);
3325
3326         supplicant_dbus_dict_append_basic(dict, "pairwise",
3327                                                 DBUS_TYPE_STRING,
3328                                                 &pairwise);
3329         supplicant_dbus_dict_append_basic(dict, "group",
3330                                                 DBUS_TYPE_STRING,
3331                                                 &group);
3332
3333         g_free(pairwise);
3334         g_free(group);
3335 }
3336
3337 static void add_network_security_proto(DBusMessageIter *dict,
3338                                                 GSupplicantSSID *ssid)
3339 {
3340         unsigned int protocol, i;
3341         char *proto;
3342         char *protos[3];
3343
3344         protocol = ssid->protocol;
3345
3346         if (protocol == 0)
3347                 return;
3348
3349         i = 0;
3350
3351         if (protocol & G_SUPPLICANT_PROTO_RSN)
3352                 protos[i++] = "RSN";
3353
3354         if (protocol & G_SUPPLICANT_PROTO_WPA)
3355                 protos[i++] = "WPA";
3356
3357         protos[i] = NULL;
3358
3359         proto = g_strjoinv(" ", protos);
3360
3361         SUPPLICANT_DBG("proto %s", proto);
3362
3363         supplicant_dbus_dict_append_basic(dict, "proto",
3364                                                 DBUS_TYPE_STRING,
3365                                                 &proto);
3366
3367         g_free(proto);
3368 }
3369
3370 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
3371 {
3372         char *key_mgmt;
3373
3374         switch (ssid->security) {
3375         case G_SUPPLICANT_SECURITY_UNKNOWN:
3376         case G_SUPPLICANT_SECURITY_NONE:
3377         case G_SUPPLICANT_SECURITY_WEP:
3378                 key_mgmt = "NONE";
3379                 add_network_security_wep(dict, ssid);
3380                 add_network_security_ciphers(dict, ssid);
3381                 break;
3382         case G_SUPPLICANT_SECURITY_PSK:
3383                 key_mgmt = "WPA-PSK";
3384                 add_network_security_psk(dict, ssid);
3385                 add_network_security_ciphers(dict, ssid);
3386                 add_network_security_proto(dict, ssid);
3387                 break;
3388         case G_SUPPLICANT_SECURITY_IEEE8021X:
3389                 key_mgmt = "WPA-EAP";
3390                 add_network_security_eap(dict, ssid);
3391                 add_network_security_ciphers(dict, ssid);
3392                 add_network_security_proto(dict, ssid);
3393                 break;
3394         }
3395
3396         supplicant_dbus_dict_append_basic(dict, "key_mgmt",
3397                                 DBUS_TYPE_STRING, &key_mgmt);
3398 }
3399
3400 static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid)
3401 {
3402         dbus_uint32_t mode;
3403
3404         switch (ssid->mode) {
3405         case G_SUPPLICANT_MODE_UNKNOWN:
3406         case G_SUPPLICANT_MODE_INFRA:
3407                 mode = 0;
3408                 break;
3409         case G_SUPPLICANT_MODE_IBSS:
3410                 mode = 1;
3411                 break;
3412         case G_SUPPLICANT_MODE_MASTER:
3413                 mode = 2;
3414                 break;
3415         }
3416
3417         supplicant_dbus_dict_append_basic(dict, "mode",
3418                                 DBUS_TYPE_UINT32, &mode);
3419 }
3420
3421 static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
3422 {
3423         DBusMessageIter dict;
3424         struct interface_connect_data *data = user_data;
3425         GSupplicantSSID *ssid = data->ssid;
3426
3427         supplicant_dbus_dict_open(iter, &dict);
3428
3429         if (ssid->scan_ssid)
3430                 supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
3431                                          DBUS_TYPE_UINT32, &ssid->scan_ssid);
3432
3433         if (ssid->freq)
3434                 supplicant_dbus_dict_append_basic(&dict, "frequency",
3435                                          DBUS_TYPE_UINT32, &ssid->freq);
3436
3437         if (ssid->bgscan != NULL)
3438                 supplicant_dbus_dict_append_basic(&dict, "bgscan",
3439                                         DBUS_TYPE_STRING, &ssid->bgscan);
3440
3441         add_network_mode(&dict, ssid);
3442
3443         add_network_security(&dict, ssid);
3444
3445         supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
3446                                         DBUS_TYPE_BYTE, &ssid->ssid,
3447                                                 ssid->ssid_len);
3448
3449         supplicant_dbus_dict_close(iter, &dict);
3450 }
3451
3452 static void interface_wps_start_result(const char *error,
3453                                 DBusMessageIter *iter, void *user_data)
3454 {
3455         struct interface_connect_data *data = user_data;
3456
3457         SUPPLICANT_DBG("");
3458         if (error != NULL)
3459                 SUPPLICANT_DBG("error: %s", error);
3460
3461         g_free(data->ssid);
3462         dbus_free(data);
3463 }
3464
3465 static void interface_add_wps_params(DBusMessageIter *iter, void *user_data)
3466 {
3467         struct interface_connect_data *data = user_data;
3468         GSupplicantSSID *ssid = data->ssid;
3469         const char *role = "enrollee", *type;
3470         DBusMessageIter dict;
3471
3472         SUPPLICANT_DBG("");
3473
3474         supplicant_dbus_dict_open(iter, &dict);
3475
3476         supplicant_dbus_dict_append_basic(&dict, "Role",
3477                                                 DBUS_TYPE_STRING, &role);
3478
3479         type = "pbc";
3480         if (ssid->pin_wps != NULL) {
3481                 type = "pin";
3482                 supplicant_dbus_dict_append_basic(&dict, "Pin",
3483                                         DBUS_TYPE_STRING, &ssid->pin_wps);
3484         }
3485
3486         supplicant_dbus_dict_append_basic(&dict, "Type",
3487                                         DBUS_TYPE_STRING, &type);
3488
3489         supplicant_dbus_dict_close(iter, &dict);
3490 }
3491
3492 static void wps_start(const char *error, DBusMessageIter *iter, void *user_data)
3493 {
3494         struct interface_connect_data *data = user_data;
3495
3496         SUPPLICANT_DBG("");
3497
3498         if (error != NULL) {
3499                 SUPPLICANT_DBG("error: %s", error);
3500                 g_free(data->ssid);
3501                 dbus_free(data);
3502                 return;
3503         }
3504
3505         supplicant_dbus_method_call(data->interface->path,
3506                         SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
3507                         interface_add_wps_params,
3508                         interface_wps_start_result, data);
3509 }
3510
3511 static void wps_process_credentials(DBusMessageIter *iter, void *user_data)
3512 {
3513         dbus_bool_t credentials = TRUE;
3514
3515         SUPPLICANT_DBG("");
3516
3517         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials);
3518 }
3519
3520
3521 int g_supplicant_interface_connect(GSupplicantInterface *interface,
3522                                 GSupplicantSSID *ssid,
3523                                 GSupplicantInterfaceCallback callback,
3524                                                         void *user_data)
3525 {
3526         struct interface_connect_data *data;
3527         int ret;
3528
3529         if (interface == NULL)
3530                 return -EINVAL;
3531
3532         if (system_available == FALSE)
3533                 return -EFAULT;
3534
3535         /* TODO: Check if we're already connected and switch */
3536
3537         data = dbus_malloc0(sizeof(*data));
3538         if (data == NULL)
3539                 return -ENOMEM;
3540
3541         data->interface = interface;
3542         data->callback = callback;
3543         data->ssid = ssid;
3544         data->user_data = user_data;
3545
3546         if (ssid->use_wps == TRUE) {
3547                 g_free(interface->wps_cred.key);
3548                 memset(&interface->wps_cred, 0,
3549                                 sizeof(struct _GSupplicantWpsCredentials));
3550
3551                 ret = supplicant_dbus_property_set(interface->path,
3552                         SUPPLICANT_INTERFACE ".Interface.WPS",
3553                         "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
3554                         wps_process_credentials, wps_start, data);
3555         } else
3556                 ret = supplicant_dbus_method_call(interface->path,
3557                         SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
3558                         interface_add_network_params,
3559                         interface_add_network_result, data);
3560
3561         if (ret < 0)
3562                 return ret;
3563
3564         return -EINPROGRESS;
3565 }
3566
3567 static void network_remove_result(const char *error,
3568                                 DBusMessageIter *iter, void *user_data)
3569 {
3570         struct interface_data *data = user_data;
3571         int result = 0;
3572
3573         SUPPLICANT_DBG("");
3574
3575         if (error != NULL)
3576                 result = -EIO;
3577
3578         if (data->callback != NULL)
3579                 data->callback(result, data->interface, data->user_data);
3580
3581         dbus_free(data);
3582 }
3583
3584 static void network_remove_params(DBusMessageIter *iter, void *user_data)
3585 {
3586         struct interface_data *data = user_data;
3587         const char *path = data->interface->network_path;
3588
3589         SUPPLICANT_DBG("path %s", path);
3590
3591         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
3592 }
3593
3594 static int network_remove(struct interface_data *data)
3595 {
3596         GSupplicantInterface *interface = data->interface;
3597
3598         SUPPLICANT_DBG("");
3599
3600         return supplicant_dbus_method_call(interface->path,
3601                         SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
3602                         network_remove_params, network_remove_result, data);
3603 }
3604
3605 static void interface_disconnect_result(const char *error,
3606                                 DBusMessageIter *iter, void *user_data)
3607 {
3608         struct interface_data *data = user_data;
3609
3610         SUPPLICANT_DBG("");
3611
3612         if (error != NULL && data->callback != NULL)
3613                 data->callback(-EIO, data->interface, data->user_data);
3614
3615         /* If we are disconnecting from previous WPS successful
3616          * association. i.e.: it did not went through AddNetwork,
3617          * and interface->network_path was never set. */
3618         if (data->interface->network_path == NULL) {
3619                 dbus_free(data);
3620                 return;
3621         }
3622
3623         network_remove(data);
3624 }
3625
3626 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
3627                                         GSupplicantInterfaceCallback callback,
3628                                                         void *user_data)
3629 {
3630         struct interface_data *data;
3631
3632         SUPPLICANT_DBG("");
3633
3634         if (interface == NULL)
3635                 return -EINVAL;
3636
3637         if (system_available == FALSE)
3638                 return -EFAULT;
3639
3640         data = dbus_malloc0(sizeof(*data));
3641         if (data == NULL)
3642                 return -ENOMEM;
3643
3644         data->interface = interface;
3645         data->callback = callback;
3646         data->user_data = user_data;
3647
3648         return supplicant_dbus_method_call(interface->path,
3649                         SUPPLICANT_INTERFACE ".Interface", "Disconnect",
3650                                 NULL, interface_disconnect_result, data);
3651 }
3652
3653
3654 static const char *g_supplicant_rule0 = "type=signal,"
3655                                         "path=" DBUS_PATH_DBUS ","
3656                                         "sender=" DBUS_SERVICE_DBUS ","
3657                                         "interface=" DBUS_INTERFACE_DBUS ","
3658                                         "member=NameOwnerChanged,"
3659                                         "arg0=" SUPPLICANT_SERVICE;
3660 static const char *g_supplicant_rule1 = "type=signal,"
3661                         "interface=" SUPPLICANT_INTERFACE;
3662 static const char *g_supplicant_rule2 = "type=signal,"
3663                         "interface=" SUPPLICANT_INTERFACE ".Interface";
3664 static const char *g_supplicant_rule3 = "type=signal,"
3665                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
3666 static const char *g_supplicant_rule4 = "type=signal,"
3667                         "interface=" SUPPLICANT_INTERFACE ".BSS";
3668 static const char *g_supplicant_rule5 = "type=signal,"
3669                         "interface=" SUPPLICANT_INTERFACE ".Network";
3670
3671 static void invoke_introspect_method(void)
3672 {
3673         DBusMessage *message;
3674
3675         message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
3676                                         SUPPLICANT_PATH,
3677                                         DBUS_INTERFACE_INTROSPECTABLE,
3678                                         "Introspect");
3679
3680         if (message == NULL)
3681                 return;
3682
3683         dbus_message_set_no_reply(message, TRUE);
3684         dbus_connection_send(connection, message, NULL);
3685         dbus_message_unref(message);
3686 }
3687
3688 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
3689 {
3690         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
3691         if (connection == NULL)
3692                 return -EIO;
3693
3694         if (dbus_connection_add_filter(connection,
3695                                 g_supplicant_filter, NULL, NULL) == FALSE) {
3696                 dbus_connection_unref(connection);
3697                 connection = NULL;
3698                 return -EIO;
3699         }
3700
3701         callbacks_pointer = callbacks;
3702         eap_methods = 0;
3703
3704         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
3705                                                 NULL, remove_interface);
3706
3707         bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
3708                                                                 NULL, NULL);
3709
3710         supplicant_dbus_setup(connection);
3711
3712         dbus_bus_add_match(connection, g_supplicant_rule0, NULL);
3713         dbus_bus_add_match(connection, g_supplicant_rule1, NULL);
3714         dbus_bus_add_match(connection, g_supplicant_rule2, NULL);
3715         dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
3716         dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
3717         dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
3718         dbus_connection_flush(connection);
3719
3720         if (dbus_bus_name_has_owner(connection,
3721                                         SUPPLICANT_SERVICE, NULL) == TRUE) {
3722                 system_available = TRUE;
3723                 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
3724                                                 SUPPLICANT_INTERFACE,
3725                                                 service_property, NULL);
3726         } else
3727                 invoke_introspect_method();
3728
3729         return 0;
3730 }
3731
3732 static void unregister_interface_remove_params(DBusMessageIter *iter,
3733                                                 void *user_data)
3734 {
3735         const char *path = user_data;
3736
3737         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
3738                                                         &path);
3739 }
3740
3741
3742 static void unregister_remove_interface(gpointer key, gpointer value,
3743                                                 gpointer user_data)
3744 {
3745         GSupplicantInterface *interface = value;
3746
3747         supplicant_dbus_method_call(SUPPLICANT_PATH,
3748                                         SUPPLICANT_INTERFACE,
3749                                         "RemoveInterface",
3750                                         unregister_interface_remove_params,
3751                                                 NULL, interface->path);
3752 }
3753
3754 void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
3755 {
3756         SUPPLICANT_DBG("");
3757
3758         if (connection != NULL) {
3759                 dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
3760                 dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
3761                 dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);
3762                 dbus_bus_remove_match(connection, g_supplicant_rule2, NULL);
3763                 dbus_bus_remove_match(connection, g_supplicant_rule1, NULL);
3764                 dbus_bus_remove_match(connection, g_supplicant_rule0, NULL);
3765                 dbus_connection_flush(connection);
3766
3767                 dbus_connection_remove_filter(connection,
3768                                                 g_supplicant_filter, NULL);
3769         }
3770
3771         if (bss_mapping != NULL) {
3772                 g_hash_table_destroy(bss_mapping);
3773                 bss_mapping = NULL;
3774         }
3775
3776         if (system_available == TRUE)
3777                 callback_system_killed();
3778
3779         if (interface_table != NULL) {
3780                 g_hash_table_foreach(interface_table,
3781                                         unregister_remove_interface, NULL);
3782                 g_hash_table_destroy(interface_table);
3783                 interface_table = NULL;
3784         }
3785
3786         if (connection != NULL) {
3787                 dbus_connection_unref(connection);
3788                 connection = NULL;
3789         }
3790
3791         callbacks_pointer = NULL;
3792         eap_methods = 0;
3793 }