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