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