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