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