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