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