Rename D-Bus helper for basic dictionary types
[framework/connectivity/connman.git] / plugins / supplicant.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <stdio.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <linux/if_arp.h>
34 #include <linux/wireless.h>
35 #include <net/ethernet.h>
36
37 #include <gdbus.h>
38
39 #define CONNMAN_API_SUBJECT_TO_CHANGE
40 #include <connman/device.h>
41 #include <connman/option.h>
42 #include <connman/inet.h>
43 #include <connman/dbus.h>
44 #include <connman/log.h>
45
46 #include "supplicant.h"
47
48 #define TIMEOUT 5000
49
50 #define IEEE80211_CAP_ESS       0x0001
51 #define IEEE80211_CAP_IBSS      0x0002
52 #define IEEE80211_CAP_PRIVACY   0x0010
53
54 #define SUPPLICANT_NAME  "fi.epitest.hostap.WPASupplicant"
55 #define SUPPLICANT_INTF  "fi.epitest.hostap.WPASupplicant"
56 #define SUPPLICANT_PATH  "/fi/epitest/hostap/WPASupplicant"
57
58 /* Taken from "WPA Supplicant - Common definitions" */
59 enum supplicant_state {
60         /**
61          * WPA_DISCONNECTED - Disconnected state
62          *
63          * This state indicates that client is not associated, but is likely to
64          * start looking for an access point. This state is entered when a
65          * connection is lost.
66          */
67         WPA_DISCONNECTED,
68
69         /**
70          * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
71          *
72          * This state is entered if there are no enabled networks in the
73          * configuration. wpa_supplicant is not trying to associate with a new
74          * network and external interaction (e.g., ctrl_iface call to add or
75          * enable a network) is needed to start association.
76          */
77         WPA_INACTIVE,
78
79         /**
80          * WPA_SCANNING - Scanning for a network
81          *
82          * This state is entered when wpa_supplicant starts scanning for a
83          * network.
84          */
85         WPA_SCANNING,
86
87         /**
88          * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
89          *
90          * This state is entered when wpa_supplicant has found a suitable BSS
91          * to associate with and the driver is configured to try to associate
92          * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
93          * state is entered when the driver is configured to try to associate
94          * with a network using the configured SSID and security policy.
95          */
96         WPA_ASSOCIATING,
97
98         /**
99          * WPA_ASSOCIATED - Association completed
100          *
101          * This state is entered when the driver reports that association has
102          * been successfully completed with an AP. If IEEE 802.1X is used
103          * (with or without WPA/WPA2), wpa_supplicant remains in this state
104          * until the IEEE 802.1X/EAPOL authentication has been completed.
105          */
106         WPA_ASSOCIATED,
107
108         /**
109          * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
110          *
111          * This state is entered when WPA/WPA2 4-Way Handshake is started. In
112          * case of WPA-PSK, this happens when receiving the first EAPOL-Key
113          * frame after association. In case of WPA-EAP, this state is entered
114          * when the IEEE 802.1X/EAPOL authentication has been completed.
115          */
116         WPA_4WAY_HANDSHAKE,
117
118         /**
119          * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
120          *
121          * This state is entered when 4-Way Key Handshake has been completed
122          * (i.e., when the supplicant sends out message 4/4) and when Group
123          * Key rekeying is started by the AP (i.e., when supplicant receives
124          * message 1/2).
125          */
126         WPA_GROUP_HANDSHAKE,
127
128         /**
129          * WPA_COMPLETED - All authentication completed
130          *
131          * This state is entered when the full authentication process is
132          * completed. In case of WPA2, this happens when the 4-Way Handshake is
133          * successfully completed. With WPA, this state is entered after the
134          * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
135          * completed after dynamic keys are received (or if not used, after
136          * the EAP authentication has been completed). With static WEP keys and
137          * plaintext connections, this state is entered when an association
138          * has been completed.
139          *
140          * This state indicates that the supplicant has completed its
141          * processing for the association phase and that data connection is
142          * fully configured.
143          */
144         WPA_COMPLETED,
145
146         /**
147          * WPA_INVALID - Invalid state (parsing error)
148          *
149          * This state is returned if the string input is invalid. It is not
150          * an official wpa_supplicant state.
151          */
152         WPA_INVALID,
153 };
154
155 struct supplicant_result {
156         char *path;
157         char *name;
158         unsigned char *addr;
159         unsigned int addr_len;
160         unsigned char *ssid;
161         unsigned int ssid_len;
162         dbus_uint16_t capabilities;
163         gboolean adhoc;
164         gboolean has_wep;
165         gboolean has_psk;
166         gboolean has_8021x;
167         gboolean has_wpa;
168         gboolean has_rsn;
169         gboolean has_wps;
170         dbus_int32_t frequency;
171         dbus_int32_t quality;
172         dbus_int32_t noise;
173         dbus_int32_t level;
174         dbus_int32_t maxrate;
175 };
176
177 struct supplicant_task {
178         int ifindex;
179         char *ifname;
180         gboolean mac80211;
181         struct connman_device *device;
182         struct connman_network *network;
183         struct connman_network *pending_network;
184         char *path;
185         char *netpath;
186         gboolean created;
187         enum supplicant_state state;
188         gboolean scanning;
189         GSList *scan_results;
190         DBusPendingCall *scan_call;
191         DBusPendingCall *result_call;
192         struct iw_range *range;
193         gboolean disconnecting;
194 };
195
196 static GSList *task_list = NULL;
197
198 static DBusConnection *connection;
199
200 static void free_task(struct supplicant_task *task)
201 {
202         DBG("task %p", task);
203
204         g_free(task->ifname);
205         g_free(task->path);
206         g_free(task);
207 }
208
209 static struct supplicant_task *find_task_by_index(int index)
210 {
211         GSList *list;
212
213         for (list = task_list; list; list = list->next) {
214                 struct supplicant_task *task = list->data;
215
216                 if (task->ifindex == index)
217                         return task;
218         }
219
220         return NULL;
221 }
222
223 static struct supplicant_task *find_task_by_path(const char *path)
224 {
225         GSList *list;
226
227         for (list = task_list; list; list = list->next) {
228                 struct supplicant_task *task = list->data;
229
230                 if (g_strcmp0(task->path, path) == 0)
231                         return task;
232         }
233
234         return NULL;
235 }
236
237 static int get_range(struct supplicant_task *task)
238 {
239         struct iwreq wrq;
240         int fd, err;
241
242         fd = socket(PF_INET, SOCK_DGRAM, 0);
243         if (fd < 0)
244                 return -1;
245
246         memset(&wrq, 0, sizeof(struct iwreq));
247         strncpy(wrq.ifr_name, task->ifname, IFNAMSIZ);
248         wrq.u.data.pointer = task->range;
249         wrq.u.data.length = sizeof(struct iw_range);
250
251         err = ioctl(fd, SIOCGIWRANGE, &wrq);
252
253         close(fd);
254
255         if (err < 0)
256                 task->range->max_qual.updated |= IW_QUAL_ALL_INVALID;
257
258         connman_info("%s {scan} capabilities 0x%02x", task->ifname,
259                                                 task->range->scan_capa);
260
261         connman_info("%s {quality} flags 0x%02x", task->ifname,
262                                         task->range->max_qual.updated);
263
264         return err;
265 }
266
267 static int get_bssid(struct connman_device *device,
268                                 unsigned char *bssid, unsigned int *bssid_len)
269 {
270         struct iwreq wrq;
271         char *ifname;
272         int ifindex;
273         int fd, err;
274
275         ifindex = connman_device_get_index(device);
276         if (ifindex < 0)
277                 return -EINVAL;
278
279         ifname = connman_inet_ifname(ifindex);
280         if (ifname == NULL)
281                 return -EINVAL;
282
283         fd = socket(PF_INET, SOCK_DGRAM, 0);
284         if (fd < 0) {
285                 g_free(ifname);
286                 return -EINVAL;
287         }
288
289         memset(&wrq, 0, sizeof(wrq));
290         strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
291
292         err = ioctl(fd, SIOCGIWAP, &wrq);
293
294         g_free(ifname);
295         close(fd);
296
297         if (err < 0)
298                 return -EIO;
299
300         memcpy(bssid, wrq.u.ap_addr.sa_data, ETH_ALEN);
301         *bssid_len = ETH_ALEN;
302
303         return 0;
304 }
305
306 static void add_interface_reply(DBusPendingCall *call, void *user_data)
307 {
308         struct supplicant_task *task = user_data;
309         DBusMessage *reply;
310         DBusError error;
311         const char *path;
312
313         DBG("task %p", task);
314
315         reply = dbus_pending_call_steal_reply(call);
316         if (reply == NULL)
317                 return;
318
319         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
320                 goto failed;
321
322         dbus_error_init(&error);
323
324         if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
325                                                 DBUS_TYPE_INVALID) == FALSE) {
326                 if (dbus_error_is_set(&error) == TRUE) {
327                         connman_error("%s", error.message);
328                         dbus_error_free(&error);
329                 } else
330                         connman_error("Wrong arguments for add interface");
331                 goto failed;
332         }
333
334         DBG("path %s", path);
335
336         task->path = g_strdup(path);
337         task->created = TRUE;
338
339         connman_device_set_powered(task->device, TRUE);
340
341         dbus_message_unref(reply);
342
343         return;
344
345 failed:
346         dbus_message_unref(reply);
347
348         task_list = g_slist_remove(task_list, task);
349
350         connman_device_unref(task->device);
351
352         free_task(task);
353 }
354
355 static int add_interface(struct supplicant_task *task)
356 {
357         const char *driver = connman_option_get_string("wifi");
358         DBusMessage *message;
359         DBusMessageIter array, dict;
360         DBusPendingCall *call;
361
362         DBG("task %p", task);
363
364         message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
365                                         SUPPLICANT_INTF, "addInterface");
366         if (message == NULL)
367                 return -ENOMEM;
368
369         dbus_message_set_auto_start(message, FALSE);
370
371         dbus_message_iter_init_append(message, &array);
372
373         dbus_message_iter_append_basic(&array,
374                                         DBUS_TYPE_STRING, &task->ifname);
375
376         connman_dbus_dict_open(&array, &dict);
377
378         connman_dbus_dict_append_basic(&dict, "driver",
379                                                 DBUS_TYPE_STRING, &driver);
380
381         connman_dbus_dict_close(&array, &dict);
382
383         if (dbus_connection_send_with_reply(connection, message,
384                                                 &call, TIMEOUT) == FALSE) {
385                 connman_error("Failed to add interface");
386                 dbus_message_unref(message);
387                 return -EIO;
388         }
389
390         if (call == NULL) {
391                 connman_error("D-Bus connection not available");
392                 dbus_message_unref(message);
393                 return -EIO;
394         }
395
396         dbus_pending_call_set_notify(call, add_interface_reply, task, NULL);
397
398         dbus_message_unref(message);
399
400         return -EINPROGRESS;
401 }
402
403 static void get_interface_reply(DBusPendingCall *call, void *user_data)
404 {
405         struct supplicant_task *task = user_data;
406         DBusMessage *reply;
407         DBusError error;
408         const char *path;
409
410         DBG("task %p", task);
411
412         reply = dbus_pending_call_steal_reply(call);
413         if (reply == NULL)
414                 return;
415
416         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
417                 add_interface(task);
418                 goto done;
419         }
420
421         dbus_error_init(&error);
422
423         if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
424                                                 DBUS_TYPE_INVALID) == FALSE) {
425                 if (dbus_error_is_set(&error) == TRUE) {
426                         connman_error("%s", error.message);
427                         dbus_error_free(&error);
428                 } else
429                         connman_error("Wrong arguments for get interface");
430                 goto done;
431         }
432
433         DBG("path %s", path);
434
435         task->path = g_strdup(path);
436         task->created = FALSE;
437
438         connman_device_set_powered(task->device, TRUE);
439
440 done:
441         dbus_message_unref(reply);
442 }
443
444 static int create_interface(struct supplicant_task *task)
445 {
446         DBusMessage *message;
447         DBusPendingCall *call;
448
449         DBG("task %p", task);
450
451         message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
452                                         SUPPLICANT_INTF, "getInterface");
453         if (message == NULL)
454                 return -ENOMEM;
455
456         dbus_message_set_auto_start(message, FALSE);
457
458         dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
459                                                         DBUS_TYPE_INVALID);
460
461         if (dbus_connection_send_with_reply(connection, message,
462                                                 &call, TIMEOUT) == FALSE) {
463                 connman_error("Failed to get interface");
464                 dbus_message_unref(message);
465                 return -EIO;
466         }
467
468         if (call == NULL) {
469                 connman_error("D-Bus connection not available");
470                 dbus_message_unref(message);
471                 return -EIO;
472         }
473
474         dbus_pending_call_set_notify(call, get_interface_reply, task, NULL);
475
476         dbus_message_unref(message);
477
478         return -EINPROGRESS;
479 }
480
481 static void remove_interface_reply(DBusPendingCall *call, void *user_data)
482 {
483         struct supplicant_task *task = user_data;
484         DBusMessage *reply;
485
486         DBG("task %p", task);
487
488         reply = dbus_pending_call_steal_reply(call);
489
490         connman_device_set_powered(task->device, FALSE);
491
492         connman_device_unref(task->device);
493
494         connman_inet_ifdown(task->ifindex);
495
496         free_task(task);
497
498         dbus_message_unref(reply);
499 }
500
501 static int remove_interface(struct supplicant_task *task)
502 {
503         DBusMessage *message;
504         DBusPendingCall *call;
505
506         DBG("task %p", task);
507
508 #if 0
509         if (task->created == FALSE) {
510                 connman_device_set_powered(task->device, FALSE);
511                 return 0;
512         }
513 #endif
514
515         message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
516                                         SUPPLICANT_INTF, "removeInterface");
517         if (message == NULL)
518                 return -ENOMEM;
519
520         dbus_message_set_auto_start(message, FALSE);
521
522         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->path,
523                                                         DBUS_TYPE_INVALID);
524
525         if (dbus_connection_send_with_reply(connection, message,
526                                                 &call, TIMEOUT) == FALSE) {
527                 connman_error("Failed to remove interface");
528                 dbus_message_unref(message);
529                 return -EIO;
530         }
531
532         if (call == NULL) {
533                 connman_error("D-Bus connection not available");
534                 dbus_message_unref(message);
535                 return -EIO;
536         }
537
538         dbus_pending_call_set_notify(call, remove_interface_reply, task, NULL);
539
540         dbus_message_unref(message);
541
542         return -EINPROGRESS;
543 }
544
545 static int set_ap_scan(struct supplicant_task *task)
546 {
547         DBusMessage *message, *reply;
548         DBusError error;
549         guint32 ap_scan = 1;
550
551         DBG("task %p", task);
552
553         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
554                                 SUPPLICANT_INTF ".Interface", "setAPScan");
555         if (message == NULL)
556                 return -ENOMEM;
557
558         dbus_message_set_auto_start(message, FALSE);
559
560         dbus_message_append_args(message, DBUS_TYPE_UINT32, &ap_scan,
561                                                         DBUS_TYPE_INVALID);
562
563         dbus_error_init(&error);
564
565         reply = dbus_connection_send_with_reply_and_block(connection,
566                                                         message, -1, &error);
567         if (reply == NULL) {
568                 if (dbus_error_is_set(&error) == TRUE) {
569                         connman_error("%s", error.message);
570                         dbus_error_free(&error);
571                 } else
572                         connman_error("Failed to set AP scan");
573                 dbus_message_unref(message);
574                 return -EIO;
575         }
576
577         dbus_message_unref(message);
578
579         dbus_message_unref(reply);
580
581         return 0;
582 }
583
584 static int add_network(struct supplicant_task *task)
585 {
586         DBusMessage *message, *reply;
587         DBusError error;
588         const char *path;
589
590         DBG("task %p", task);
591
592         if (task->netpath != NULL)
593                 return -EALREADY;
594
595         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
596                                 SUPPLICANT_INTF ".Interface", "addNetwork");
597         if (message == NULL)
598                 return -ENOMEM;
599
600         dbus_message_set_auto_start(message, FALSE);
601
602         dbus_error_init(&error);
603
604         reply = dbus_connection_send_with_reply_and_block(connection,
605                                                         message, -1, &error);
606         if (reply == NULL) {
607                 if (dbus_error_is_set(&error) == TRUE) {
608                         connman_error("%s", error.message);
609                         dbus_error_free(&error);
610                 } else
611                         connman_error("Failed to add network");
612                 dbus_message_unref(message);
613                 return -EIO;
614         }
615
616         dbus_message_unref(message);
617
618         dbus_error_init(&error);
619
620         if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
621                                                 DBUS_TYPE_INVALID) == FALSE) {
622                 if (dbus_error_is_set(&error) == TRUE) {
623                         connman_error("%s", error.message);
624                         dbus_error_free(&error);
625                 } else
626                         connman_error("Wrong arguments for network");
627                 dbus_message_unref(reply);
628                 return -EIO;
629         }
630
631         DBG("path %s", path);
632
633         task->netpath = g_strdup(path);
634
635         dbus_message_unref(reply);
636
637         return 0;
638 }
639
640 static int remove_network(struct supplicant_task *task)
641 {
642         DBusMessage *message, *reply;
643         DBusError error;
644
645         DBG("task %p", task);
646
647         if (task->netpath == NULL)
648                 return -EINVAL;
649
650         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
651                                 SUPPLICANT_INTF ".Interface", "removeNetwork");
652         if (message == NULL)
653                 return -ENOMEM;
654
655         dbus_message_set_auto_start(message, FALSE);
656
657         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath,
658                                                         DBUS_TYPE_INVALID);
659
660         dbus_error_init(&error);
661
662         reply = dbus_connection_send_with_reply_and_block(connection,
663                                                         message, -1, &error);
664         if (reply == NULL) {
665                 if (dbus_error_is_set(&error) == TRUE) {
666                         connman_error("%s", error.message);
667                         dbus_error_free(&error);
668                 } else
669                         connman_error("Failed to remove network");
670                 dbus_message_unref(message);
671                 return -EIO;
672         }
673
674         dbus_message_unref(message);
675
676         dbus_message_unref(reply);
677
678         g_free(task->netpath);
679         task->netpath = NULL;
680
681         return 0;
682 }
683
684 static int select_network(struct supplicant_task *task)
685 {
686         DBusMessage *message, *reply;
687         DBusError error;
688
689         DBG("task %p", task);
690
691         if (task->netpath == NULL)
692                 return -EINVAL;
693
694         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
695                                 SUPPLICANT_INTF ".Interface", "selectNetwork");
696         if (message == NULL)
697                 return -ENOMEM;
698
699         dbus_message_set_auto_start(message, FALSE);
700
701         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath,
702                                                         DBUS_TYPE_INVALID);
703
704         dbus_error_init(&error);
705
706         reply = dbus_connection_send_with_reply_and_block(connection,
707                                                         message, -1, &error);
708         if (reply == NULL) {
709                 if (dbus_error_is_set(&error) == TRUE) {
710                         connman_error("%s", error.message);
711                         dbus_error_free(&error);
712                 } else
713                         connman_error("Failed to select network");
714                 dbus_message_unref(message);
715                 return -EIO;
716         }
717
718         dbus_message_unref(message);
719
720         dbus_message_unref(reply);
721
722         return 0;
723 }
724
725 static int disconnect_network(struct supplicant_task *task)
726 {
727         DBusMessage *message, *reply;
728         DBusError error;
729
730         DBG("task %p", task);
731
732         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
733                                 SUPPLICANT_INTF ".Interface", "disconnect");
734         if (message == NULL)
735                 return -ENOMEM;
736
737         dbus_message_set_auto_start(message, FALSE);
738
739         dbus_error_init(&error);
740
741         reply = dbus_connection_send_with_reply_and_block(connection,
742                                                         message, -1, &error);
743         if (reply == NULL) {
744                 if (dbus_error_is_set(&error) == TRUE) {
745                         connman_error("%s", error.message);
746                         dbus_error_free(&error);
747                 } else
748                         connman_error("Failed to disconnect network");
749                 dbus_message_unref(message);
750                 return -EIO;
751         }
752
753         dbus_message_unref(message);
754
755         dbus_message_unref(reply);
756
757         return 0;
758 }
759
760 static int set_network(struct supplicant_task *task,
761                                 const unsigned char *network, int len,
762                                 const char *address, const char *security,
763                                                         const char *passphrase)
764 {
765         DBusMessage *message, *reply;
766         DBusMessageIter array, dict;
767         DBusError error;
768         dbus_uint32_t scan_ssid = 1;
769
770         DBG("task %p", task);
771
772         if (task->netpath == NULL)
773                 return -EINVAL;
774
775         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
776                                         SUPPLICANT_INTF ".Network", "set");
777         if (message == NULL)
778                 return -ENOMEM;
779
780         dbus_message_set_auto_start(message, FALSE);
781
782         dbus_message_iter_init_append(message, &array);
783
784         connman_dbus_dict_open(&array, &dict);
785
786         connman_dbus_dict_append_basic(&dict, "scan_ssid",
787                                          DBUS_TYPE_UINT32, &scan_ssid);
788
789         if (network)
790                 connman_dbus_dict_append_fixed_array(&dict, "ssid",
791                                                 DBUS_TYPE_BYTE, &network, len);
792         else if (address)
793                 connman_dbus_dict_append_basic(&dict, "bssid",
794                                                 DBUS_TYPE_STRING, &address);
795
796         if (g_ascii_strcasecmp(security, "psk") == 0 ||
797                                 g_ascii_strcasecmp(security, "wpa") == 0 ||
798                                 g_ascii_strcasecmp(security, "rsn") == 0) {
799                 const char *key_mgmt = "WPA-PSK";
800                 connman_dbus_dict_append_basic(&dict, "key_mgmt",
801                                                 DBUS_TYPE_STRING, &key_mgmt);
802
803                 if (passphrase && strlen(passphrase) > 0)
804                         connman_dbus_dict_append_basic(&dict, "psk",
805                                                 DBUS_TYPE_STRING, &passphrase);
806         } else if (g_ascii_strcasecmp(security, "wep") == 0) {
807                 const char *key_mgmt = "NONE";
808                 const char *auth_alg = "OPEN";
809                 const char *key_index = "0";
810
811                 if (task->mac80211 == TRUE)
812                         auth_alg = "OPEN SHARED";
813
814                 connman_dbus_dict_append_basic(&dict, "auth_alg",
815                                                 DBUS_TYPE_STRING, &auth_alg);
816
817                 connman_dbus_dict_append_basic(&dict, "key_mgmt",
818                                                 DBUS_TYPE_STRING, &key_mgmt);
819
820                 if (passphrase) {
821                         int size = strlen(passphrase);
822                         if (size == 10 || size == 26) {
823                                 unsigned char *key = malloc(13);
824                                 char tmp[3];
825                                 int i;
826                                 memset(tmp, 0, sizeof(tmp));
827                                 if (key == NULL)
828                                         size = 0;
829                                 for (i = 0; i < size / 2; i++) {
830                                         memcpy(tmp, passphrase + (i * 2), 2);
831                                         key[i] = (unsigned char) strtol(tmp,
832                                                                 NULL, 16);
833                                 }
834                                 connman_dbus_dict_append_fixed_array(&dict,
835                                                 "wep_key0", DBUS_TYPE_BYTE,
836                                                         &key, size / 2);
837                                 free(key);
838                         } else
839                                 connman_dbus_dict_append_basic(&dict,
840                                                 "wep_key0", DBUS_TYPE_STRING,
841                                                                 &passphrase);
842
843                         connman_dbus_dict_append_basic(&dict, "wep_tx_keyidx",
844                                                 DBUS_TYPE_STRING, &key_index);
845                 }
846         } else {
847                 const char *key_mgmt = "NONE";
848                 connman_dbus_dict_append_basic(&dict, "key_mgmt",
849                                                 DBUS_TYPE_STRING, &key_mgmt);
850         }
851
852         connman_dbus_dict_close(&array, &dict);
853
854         dbus_error_init(&error);
855
856         reply = dbus_connection_send_with_reply_and_block(connection,
857                                                         message, -1, &error);
858         if (reply == NULL) {
859                 if (dbus_error_is_set(&error) == TRUE) {
860                         connman_error("%s", error.message);
861                         dbus_error_free(&error);
862                 } else
863                         connman_error("Failed to set network options");
864                 dbus_message_unref(message);
865                 return -EIO;
866         }
867
868         dbus_message_unref(message);
869
870         dbus_message_unref(reply);
871
872         return 0;
873 }
874
875 static void scan_reply(DBusPendingCall *call, void *user_data)
876 {
877         struct supplicant_task *task = user_data;
878         DBusMessage *reply;
879
880         DBG("task %p", task);
881
882         task->scan_call = NULL;
883
884         reply = dbus_pending_call_steal_reply(call);
885         if (reply == NULL)
886                 return;
887
888         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
889                 connman_device_set_scanning(task->device, FALSE);
890                 goto done;
891         }
892
893         if (task->scanning == TRUE)
894                 connman_device_set_scanning(task->device, TRUE);
895
896 done:
897         dbus_message_unref(reply);
898 }
899
900
901 static int initiate_scan(struct supplicant_task *task)
902 {
903         DBusMessage *message;
904
905         DBG("task %p", task);
906
907         if (task->path == NULL)
908                 return -EINVAL;
909
910         if (task->scan_call != NULL)
911                 return -EALREADY;
912
913         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
914                                         SUPPLICANT_INTF ".Interface", "scan");
915         if (message == NULL)
916                 return -ENOMEM;
917
918         dbus_message_set_auto_start(message, FALSE);
919
920         if (dbus_connection_send_with_reply(connection, message,
921                                         &task->scan_call, TIMEOUT) == FALSE) {
922                 connman_error("Failed to initiate scan");
923                 dbus_message_unref(message);
924                 return -EIO;
925         }
926
927         if (task->scan_call == NULL) {
928                 connman_error("D-Bus connection not available");
929                 dbus_message_unref(message);
930                 return -EIO;
931         }
932
933         dbus_pending_call_set_notify(task->scan_call, scan_reply, task, NULL);
934
935         dbus_message_unref(message);
936
937         return -EINPROGRESS;
938 }
939
940 static struct {
941         char *name;
942         char *value;
943 } special_ssid[] = {
944         { "<hidden>", "hidden"  },
945         { "default",  "linksys" },
946         { "wireless"  },
947         { "linksys"   },
948         { "netgear"   },
949         { "dlink"     },
950         { "2wire"     },
951         { "compaq"    },
952         { "tsunami"   },
953         { "comcomcom", "3com"     },
954         { "3Com",      "3com"     },
955         { "Symbol",    "symbol"   },
956         { "Motorola",  "motorola" },
957         { "Wireless" , "wireless" },
958         { "WLAN",      "wlan"     },
959         { }
960 };
961
962 static char *build_group(const char *addr, const char *name,
963                         const unsigned char *ssid, unsigned int ssid_len,
964                                         const char *mode, const char *security)
965 {
966         GString *str;
967         unsigned int i;
968
969         if (addr == NULL)
970                 return NULL;
971
972         str = g_string_sized_new((ssid_len * 2) + 24);
973         if (str == NULL)
974                 return NULL;
975
976         if (ssid == NULL) {
977                 g_string_append_printf(str, "hidden_%s", addr);
978                 goto done;
979         }
980
981         for (i = 0; special_ssid[i].name; i++) {
982                 if (g_strcmp0(special_ssid[i].name, name) == 0) {
983                         if (special_ssid[i].value == NULL)
984                                 g_string_append_printf(str, "%s_%s",
985                                                                 name, addr);
986                         else
987                                 g_string_append_printf(str, "%s_%s",
988                                                 special_ssid[i].value, addr);
989                         goto done;
990                 }
991         }
992
993         if (ssid_len > 0 && ssid[0] != '\0') {
994                 for (i = 0; i < ssid_len; i++)
995                         g_string_append_printf(str, "%02x", ssid[i]);
996         } else
997                 g_string_append_printf(str, "hidden_%s", addr);
998
999 done:
1000         g_string_append_printf(str, "_%s_%s", mode, security);
1001
1002         return g_string_free(str, FALSE);
1003 }
1004
1005 static void extract_addr(DBusMessageIter *value,
1006                                         struct supplicant_result *result)
1007 {
1008         DBusMessageIter array;
1009         struct ether_addr eth;
1010         unsigned char *addr;
1011         int addr_len;
1012
1013         dbus_message_iter_recurse(value, &array);
1014         dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
1015
1016         if (addr_len != 6)
1017                 return;
1018
1019         result->addr = g_try_malloc(addr_len);
1020         if (result->addr == NULL)
1021                 return;
1022
1023         memcpy(result->addr, addr, addr_len);
1024         result->addr_len = addr_len;
1025
1026         result->path = g_try_malloc0(13);
1027         if (result->path == NULL)
1028                 return;
1029
1030         memcpy(&eth, addr, sizeof(eth));
1031         snprintf(result->path, 13, "%02x%02x%02x%02x%02x%02x",
1032                                                 eth.ether_addr_octet[0],
1033                                                 eth.ether_addr_octet[1],
1034                                                 eth.ether_addr_octet[2],
1035                                                 eth.ether_addr_octet[3],
1036                                                 eth.ether_addr_octet[4],
1037                                                 eth.ether_addr_octet[5]);
1038 }
1039
1040 static void extract_ssid(DBusMessageIter *value,
1041                                         struct supplicant_result *result)
1042 {
1043         DBusMessageIter array;
1044         unsigned char *ssid;
1045         int ssid_len, i;
1046
1047         dbus_message_iter_recurse(value, &array);
1048         dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
1049
1050         if (ssid_len < 1)
1051                 return;
1052
1053         if (ssid[0] == '\0')
1054                 return;
1055
1056         result->ssid = g_try_malloc(ssid_len);
1057         if (result->ssid == NULL)
1058                 return;
1059
1060         memcpy(result->ssid, ssid, ssid_len);
1061         result->ssid_len = ssid_len;
1062
1063         result->name = g_try_malloc0(ssid_len + 1);
1064         if (result->name == NULL)
1065                 return;
1066
1067         for (i = 0; i < ssid_len; i++) {
1068                 if (g_ascii_isprint(ssid[i]))
1069                         result->name[i] = ssid[i];
1070                 else
1071                         result->name[i] = ' ';
1072         }
1073 }
1074
1075 static unsigned char wifi_oui[3]      = { 0x00, 0x50, 0xf2 };
1076 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
1077
1078 static void extract_rsn(struct supplicant_result *result,
1079                                         const unsigned char *buf, int len)
1080 {
1081         uint16_t count;
1082         int i;
1083
1084         /* Version */
1085         if (len < 2)
1086                 return;
1087
1088         buf += 2;
1089         len -= 2;
1090
1091         /* Group cipher */
1092         if (len < 4)
1093                 return;
1094
1095         buf += 4;
1096         len -= 4;
1097
1098         /* Pairwise cipher */
1099         if (len < 2)
1100                 return;
1101
1102         count = buf[0] | (buf[1] << 8);
1103         if (2 + (count * 4) > len)
1104                 return;
1105
1106         buf += 2 + (count * 4);
1107         len -= 2 + (count * 4);
1108
1109         /* Authentication */
1110         if (len < 2)
1111                 return;
1112
1113         count = buf[0] | (buf[1] << 8);
1114         if (2 + (count * 4) > len)
1115                 return;
1116
1117         for (i = 0; i < count; i++) {
1118                 const unsigned char *ptr = buf + 2 + (i * 4);
1119
1120                 if (memcmp(ptr, wifi_oui, 3) == 0) {
1121                         switch (ptr[3]) {
1122                         case 1:
1123                                 result->has_8021x = TRUE;
1124                                 break;
1125                         case 2:
1126                                 result->has_psk = TRUE;
1127                                 break;
1128                         }
1129                 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
1130                         switch (ptr[3]) {
1131                         case 1:
1132                                 result->has_8021x = TRUE;
1133                                 break;
1134                         case 2:
1135                                 result->has_psk = TRUE;
1136                                 break;
1137                         }
1138                 }
1139         }
1140
1141         buf += 2 + (count * 4);
1142         len -= 2 + (count * 4);
1143 }
1144
1145 static void extract_wpaie(DBusMessageIter *value,
1146                                         struct supplicant_result *result)
1147 {
1148         DBusMessageIter array;
1149         unsigned char *ie;
1150         int ie_len;
1151
1152         dbus_message_iter_recurse(value, &array);
1153         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1154
1155         if (ie_len > 0) {
1156                 result->has_wpa = TRUE;
1157                 extract_rsn(result, ie + 6, ie_len - 6);
1158         }
1159 }
1160
1161 static void extract_rsnie(DBusMessageIter *value,
1162                                         struct supplicant_result *result)
1163 {
1164         DBusMessageIter array;
1165         unsigned char *ie;
1166         int ie_len;
1167
1168         dbus_message_iter_recurse(value, &array);
1169         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1170
1171         if (ie_len > 0) {
1172                 result->has_rsn = TRUE;
1173                 extract_rsn(result, ie + 2, ie_len - 2);
1174         }
1175 }
1176
1177 static void extract_wpsie(DBusMessageIter *value,
1178                                         struct supplicant_result *result)
1179 {
1180         DBusMessageIter array;
1181         unsigned char *ie;
1182         int ie_len;
1183
1184         dbus_message_iter_recurse(value, &array);
1185         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1186
1187         if (ie_len > 0)
1188                 result->has_wps = TRUE;
1189 }
1190
1191 static void extract_capabilites(DBusMessageIter *value,
1192                                         struct supplicant_result *result)
1193 {
1194         dbus_message_iter_get_basic(value, &result->capabilities);
1195
1196         if (result->capabilities & IEEE80211_CAP_ESS)
1197                 result->adhoc = FALSE;
1198         else if (result->capabilities & IEEE80211_CAP_IBSS)
1199                 result->adhoc = TRUE;
1200
1201         if (result->capabilities & IEEE80211_CAP_PRIVACY)
1202                 result->has_wep = TRUE;
1203 }
1204
1205 static unsigned char calculate_strength(struct supplicant_task *task,
1206                                         struct supplicant_result *result)
1207 {
1208         if (result->quality == -1 || task->range->max_qual.qual == 0) {
1209                 unsigned char strength;
1210
1211                 if (result->level > 0)
1212                         strength = 100 - result->level;
1213                 else
1214                         strength = 120 + result->level;
1215
1216                 if (strength > 100)
1217                         strength = 100;
1218
1219                 return strength;
1220         }
1221
1222         return (result->quality * 100) / task->range->max_qual.qual;
1223 }
1224
1225 static unsigned short calculate_channel(struct supplicant_result *result)
1226 {
1227         if (result->frequency < 0)
1228                 return 0;
1229
1230         return (result->frequency - 2407) / 5;
1231 }
1232
1233 static void get_properties(struct supplicant_task *task);
1234
1235 static void properties_reply(DBusPendingCall *call, void *user_data)
1236 {
1237         struct supplicant_task *task = user_data;
1238         struct supplicant_result result;
1239         struct connman_network *network;
1240         DBusMessage *reply;
1241         DBusMessageIter array, dict;
1242         unsigned char strength;
1243         unsigned short channel, frequency;
1244         const char *mode, *security;
1245         char *group = NULL;
1246
1247         DBG("task %p", task);
1248
1249         reply = dbus_pending_call_steal_reply(call);
1250         if (reply == NULL) {
1251                 get_properties(task);
1252                 return;
1253         }
1254
1255         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1256                 dbus_message_unref(reply);
1257                 get_properties(task);
1258                 return;
1259         }
1260
1261         memset(&result, 0, sizeof(result));
1262         result.frequency = -1;
1263         result.quality = -1;
1264         result.level = 0;
1265         result.noise = 0;
1266
1267         dbus_message_iter_init(reply, &array);
1268
1269         dbus_message_iter_recurse(&array, &dict);
1270
1271         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1272                 DBusMessageIter entry, value;
1273                 const char *key;
1274
1275                 dbus_message_iter_recurse(&dict, &entry);
1276                 dbus_message_iter_get_basic(&entry, &key);
1277
1278                 dbus_message_iter_next(&entry);
1279
1280                 dbus_message_iter_recurse(&entry, &value);
1281
1282                 //type = dbus_message_iter_get_arg_type(&value);
1283                 //dbus_message_iter_get_basic(&value, &val);
1284
1285                 /* 
1286                  * bssid        : a (97)
1287                  * ssid         : a (97)
1288                  * wpaie        : a (97)
1289                  * rsnie        : a (97)
1290                  * wpsie        : a (97)
1291                  * frequency    : i (105)
1292                  * capabilities : q (113)
1293                  * quality      : i (105)
1294                  * noise        : i (105)
1295                  * level        : i (105)
1296                  * maxrate      : i (105)
1297                  */
1298
1299                 if (g_str_equal(key, "bssid") == TRUE)
1300                         extract_addr(&value, &result);
1301                 else if (g_str_equal(key, "ssid") == TRUE)
1302                         extract_ssid(&value, &result);
1303                 else if (g_str_equal(key, "wpaie") == TRUE)
1304                         extract_wpaie(&value, &result);
1305                 else if (g_str_equal(key, "rsnie") == TRUE)
1306                         extract_rsnie(&value, &result);
1307                 else if (g_str_equal(key, "wpsie") == TRUE)
1308                         extract_wpsie(&value, &result);
1309                 else if (g_str_equal(key, "capabilities") == TRUE)
1310                         extract_capabilites(&value, &result);
1311                 else if (g_str_equal(key, "frequency") == TRUE)
1312                         dbus_message_iter_get_basic(&value, &result.frequency);
1313                 else if (g_str_equal(key, "quality") == TRUE)
1314                         dbus_message_iter_get_basic(&value, &result.quality);
1315                 else if (g_str_equal(key, "noise") == TRUE)
1316                         dbus_message_iter_get_basic(&value, &result.noise);
1317                 else if (g_str_equal(key, "level") == TRUE)
1318                         dbus_message_iter_get_basic(&value, &result.level);
1319                 else if (g_str_equal(key, "maxrate") == TRUE)
1320                         dbus_message_iter_get_basic(&value, &result.maxrate);
1321
1322                 dbus_message_iter_next(&dict);
1323         }
1324
1325         DBG("capabilties %u frequency %d "
1326                         "quality %d noise %d level %d maxrate %d",
1327                                         result.capabilities, result.frequency,
1328                                                 result.quality, result.noise,
1329                                                 result.level, result.maxrate);
1330
1331         if (result.path == NULL)
1332                 goto done;
1333
1334         if (result.path[0] == '\0')
1335                 goto done;
1336
1337         if (result.frequency > 0 && result.frequency < 14)
1338                 result.frequency = 2407 + (5 * result.frequency);
1339         else if (result.frequency == 14)
1340                 result.frequency = 2484;
1341
1342         strength = calculate_strength(task, &result);
1343         channel  = calculate_channel(&result);
1344
1345         frequency = (result.frequency < 0) ? 0 : result.frequency;
1346
1347         if (result.has_8021x == TRUE)
1348                 security = "ieee8021x";
1349         else if (result.has_psk == TRUE)
1350                 security = "psk";
1351         else if (result.has_wep == TRUE)
1352                 security = "wep";
1353         else
1354                 security = "none";
1355
1356         mode = (result.adhoc == TRUE) ? "adhoc" : "managed";
1357
1358         group = build_group(result.path, result.name,
1359                                         result.ssid, result.ssid_len,
1360                                                         mode, security);
1361
1362         if (result.has_psk == TRUE) {
1363                 if (result.has_rsn == TRUE)
1364                         security = "rsn";
1365                 else if (result.has_wpa == TRUE)
1366                         security = "wpa";
1367         }
1368
1369         network = connman_device_get_network(task->device, result.path);
1370         if (network == NULL) {
1371                 int index;
1372
1373                 network = connman_network_create(result.path,
1374                                                 CONNMAN_NETWORK_TYPE_WIFI);
1375                 if (network == NULL)
1376                         goto done;
1377
1378                 index = connman_device_get_index(task->device);
1379                 connman_network_set_index(network, index);
1380
1381                 connman_network_set_protocol(network,
1382                                                 CONNMAN_NETWORK_PROTOCOL_IP);
1383
1384                 connman_network_set_address(network, result.addr,
1385                                                         result.addr_len);
1386
1387                 if (connman_device_add_network(task->device, network) < 0) {
1388                         connman_network_unref(network);
1389                         goto done;
1390                 }
1391         }
1392
1393         if (result.name != NULL && result.name[0] != '\0')
1394                 connman_network_set_name(network, result.name);
1395
1396         connman_network_set_blob(network, "WiFi.SSID",
1397                                                 result.ssid, result.ssid_len);
1398
1399         connman_network_set_string(network, "WiFi.Mode", mode);
1400
1401         DBG("%s (%s %s) strength %d (%s)",
1402                                 result.name, mode, security, strength,
1403                                 (result.has_wps == TRUE) ? "WPS" : "no WPS");
1404
1405         connman_network_set_available(network, TRUE);
1406         connman_network_set_strength(network, strength);
1407
1408         connman_network_set_uint16(network, "Frequency", frequency);
1409         connman_network_set_uint16(network, "WiFi.Channel", channel);
1410         connman_network_set_string(network, "WiFi.Security", security);
1411
1412         if (result.ssid != NULL)
1413                 connman_network_set_group(network, group);
1414
1415 done:
1416         g_free(group);
1417
1418         g_free(result.path);
1419         g_free(result.addr);
1420         g_free(result.name);
1421         g_free(result.ssid);
1422
1423         dbus_message_unref(reply);
1424
1425         get_properties(task);
1426 }
1427
1428 static void get_properties(struct supplicant_task *task)
1429 {
1430         DBusMessage *message;
1431         char *path;
1432
1433         path = g_slist_nth_data(task->scan_results, 0);
1434         if (path == NULL)
1435                 goto noscan;
1436
1437         message = dbus_message_new_method_call(SUPPLICANT_NAME, path,
1438                                                 SUPPLICANT_INTF ".BSSID",
1439                                                                 "properties");
1440
1441         task->scan_results = g_slist_remove(task->scan_results, path);
1442         g_free(path);
1443
1444         if (message == NULL)
1445                 goto noscan;
1446
1447         dbus_message_set_auto_start(message, FALSE);
1448
1449         if (dbus_connection_send_with_reply(connection, message,
1450                                 &task->result_call, TIMEOUT) == FALSE) {
1451                 connman_error("Failed to get network properties");
1452                 dbus_message_unref(message);
1453                 goto noscan;
1454         }
1455
1456         if (task->result_call == NULL) {
1457                 connman_error("D-Bus connection not available");
1458                 dbus_message_unref(message);
1459                 goto noscan;
1460         }
1461
1462         dbus_pending_call_set_notify(task->result_call,
1463                                         properties_reply, task, NULL);
1464
1465         dbus_message_unref(message);
1466
1467         return;
1468
1469 noscan:
1470         task->result_call = NULL;
1471
1472         if (task->scanning == TRUE) {
1473                 connman_device_set_scanning(task->device, FALSE);
1474                 task->scanning = FALSE;
1475         }
1476 }
1477
1478 static void scan_results_reply(DBusPendingCall *call, void *user_data)
1479 {
1480         struct supplicant_task *task = user_data;
1481         DBusMessage *reply;
1482         DBusError error;
1483         char **results;
1484         int i, num_results;
1485
1486         DBG("task %p", task);
1487
1488         reply = dbus_pending_call_steal_reply(call);
1489         if (reply == NULL)
1490                 goto noscan;
1491
1492         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
1493                 goto done;
1494
1495         dbus_error_init(&error);
1496
1497         if (dbus_message_get_args(reply, &error,
1498                                 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
1499                                                 &results, &num_results,
1500                                                 DBUS_TYPE_INVALID) == FALSE) {
1501                 if (dbus_error_is_set(&error) == TRUE) {
1502                         connman_error("%s", error.message);
1503                         dbus_error_free(&error);
1504                 } else
1505                         connman_error("Wrong arguments for scan result");
1506                 goto done;
1507         }
1508
1509         if (num_results == 0)
1510                 goto done;
1511
1512         for (i = 0; i < num_results; i++) {
1513                 char *path = g_strdup(results[i]);
1514                 if (path == NULL)
1515                         continue;
1516
1517                 task->scan_results = g_slist_append(task->scan_results, path);
1518         }
1519
1520         g_strfreev(results);
1521
1522         dbus_message_unref(reply);
1523
1524         get_properties(task);
1525
1526         return;
1527
1528 done:
1529         dbus_message_unref(reply);
1530
1531 noscan:
1532         task->result_call = NULL;
1533
1534         if (task->scanning == TRUE) {
1535                 connman_device_set_scanning(task->device, FALSE);
1536                 task->scanning = FALSE;
1537         }
1538 }
1539
1540 static void scan_results_available(struct supplicant_task *task)
1541 {
1542         DBusMessage *message;
1543
1544         DBG("task %p", task);
1545
1546         if (task->result_call != NULL)
1547                 return;
1548
1549         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
1550                                                 SUPPLICANT_INTF ".Interface",
1551                                                         "scanResults");
1552         if (message == NULL)
1553                 return;
1554
1555         dbus_message_set_auto_start(message, FALSE);
1556
1557         if (dbus_connection_send_with_reply(connection, message,
1558                                 &task->result_call, TIMEOUT) == FALSE) {
1559                 connman_error("Failed to request scan result");
1560                 goto done;
1561         }
1562
1563         if (task->result_call == NULL) {
1564                 connman_error("D-Bus connection not available");
1565                 goto done;
1566         }
1567
1568         if (task->scanning == TRUE)
1569                 connman_device_set_scanning(task->device, TRUE);
1570
1571         dbus_pending_call_set_notify(task->result_call,
1572                                         scan_results_reply, task, NULL);
1573
1574 done:
1575         dbus_message_unref(message);
1576 }
1577
1578 static enum supplicant_state string2state(const char *state)
1579 {
1580         if (g_str_equal(state, "INACTIVE") == TRUE)
1581                 return WPA_INACTIVE;
1582         else if (g_str_equal(state, "SCANNING") == TRUE)
1583                 return WPA_SCANNING;
1584         else if (g_str_equal(state, "ASSOCIATING") == TRUE)
1585                 return WPA_ASSOCIATING;
1586         else if (g_str_equal(state, "ASSOCIATED") == TRUE)
1587                 return WPA_ASSOCIATED;
1588         else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE)
1589                 return WPA_GROUP_HANDSHAKE;
1590         else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE)
1591                 return WPA_4WAY_HANDSHAKE;
1592         else if (g_str_equal(state, "COMPLETED") == TRUE)
1593                 return WPA_COMPLETED;
1594         else if (g_str_equal(state, "DISCONNECTED") == TRUE)
1595                 return WPA_DISCONNECTED;
1596         else
1597                 return WPA_INVALID;
1598 }
1599
1600 static int task_connect(struct supplicant_task *task)
1601 {
1602         const char *address, *security, *passphrase;
1603         const void *ssid;
1604         unsigned int ssid_len;
1605         int err;
1606
1607         connman_inet_ifup(task->ifindex);
1608
1609         address = connman_network_get_string(task->network, "Address");
1610         security = connman_network_get_string(task->network, "WiFi.Security");
1611         passphrase = connman_network_get_string(task->network, "WiFi.Passphrase");
1612
1613         ssid = connman_network_get_blob(task->network, "WiFi.SSID", &ssid_len);
1614
1615         DBG("address %s security %s", address, security);
1616
1617         if (security == NULL && passphrase == NULL)
1618                 return -EINVAL;
1619
1620         if (g_str_equal(security, "none") == FALSE && passphrase == NULL)
1621                 return -EINVAL;
1622
1623         remove_network(task);
1624
1625         set_ap_scan(task);
1626
1627         add_network(task);
1628
1629         set_network(task, ssid, ssid_len, address, security, passphrase);
1630
1631         err = select_network(task);
1632         if (err < 0)
1633                 return err;
1634
1635         return -EINPROGRESS;
1636 }
1637
1638 static void scanning(struct supplicant_task *task, DBusMessage *msg)
1639 {
1640         DBusError error;
1641         dbus_bool_t scanning;
1642
1643         dbus_error_init(&error);
1644
1645         if (dbus_message_get_args(msg, &error, DBUS_TYPE_BOOLEAN, &scanning,
1646                                                 DBUS_TYPE_INVALID) == FALSE) {
1647                 if (dbus_error_is_set(&error) == TRUE) {
1648                         connman_error("%s", error.message);
1649                         dbus_error_free(&error);
1650                 } else
1651                         connman_error("Wrong arguments for scanning");
1652                 return;
1653         }
1654
1655         connman_info("%s scanning %s", task->ifname,
1656                                 scanning == TRUE ? "started" : "finished");
1657 }
1658
1659 static void state_change(struct supplicant_task *task, DBusMessage *msg)
1660 {
1661         DBusError error;
1662         const char *newstate, *oldstate;
1663         unsigned char bssid[ETH_ALEN];
1664         unsigned int bssid_len;
1665         enum supplicant_state state, prevstate;
1666
1667         dbus_error_init(&error);
1668
1669         if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &newstate,
1670                                                 DBUS_TYPE_STRING, &oldstate,
1671                                                 DBUS_TYPE_INVALID) == FALSE) {
1672                 if (dbus_error_is_set(&error) == TRUE) {
1673                         connman_error("%s", error.message);
1674                         dbus_error_free(&error);
1675                 } else
1676                         connman_error("Wrong arguments for state change");
1677                 return;
1678         }
1679
1680         DBG("state %s ==> %s", oldstate, newstate);
1681
1682         connman_info("%s %s%s", task->ifname, newstate,
1683                                 task->scanning == TRUE ? " (scanning)" : "");
1684
1685         state = string2state(newstate);
1686         if (state == WPA_INVALID)
1687                 return;
1688
1689         if (task->scanning == TRUE && state != WPA_SCANNING) {
1690                 connman_device_cleanup_scanning(task->device);
1691                 task->scanning = FALSE;
1692         }
1693
1694         prevstate = task->state;
1695         task->state = state;
1696
1697         if (task->network == NULL)
1698                 return;
1699
1700         switch (task->state) {
1701         case WPA_COMPLETED:
1702                 switch (prevstate) {
1703                 case WPA_ASSOCIATED:
1704                 case WPA_GROUP_HANDSHAKE:
1705                         break;
1706                 default:
1707                         goto badstate;
1708                 }
1709
1710                 /* reset scan trigger and schedule background scan */
1711                 connman_device_schedule_scan(task->device);
1712
1713                 if (get_bssid(task->device, bssid, &bssid_len) == 0)
1714                         connman_network_set_address(task->network,
1715                                                         bssid, bssid_len);
1716
1717                 /* carrier on */
1718                 connman_network_set_connected(task->network, TRUE);
1719                 break;
1720
1721         case WPA_ASSOCIATING:
1722                 switch (prevstate) {
1723                 case WPA_COMPLETED:
1724                         break;
1725                 case WPA_SCANNING:
1726                         connman_network_set_associating(task->network, TRUE);
1727                         break;
1728                 default:
1729                         goto badstate;
1730                 }
1731                 break;
1732
1733         case WPA_INACTIVE:
1734                 switch (prevstate) {
1735                 case WPA_SCANNING:
1736                 case WPA_DISCONNECTED:
1737                         break;
1738                 default:
1739                         goto badstate;
1740                 }
1741                 /* fall through */
1742
1743         case WPA_DISCONNECTED:
1744                 /* carrier off */
1745                 connman_network_set_connected(task->network, FALSE);
1746
1747                 if (task->disconnecting == TRUE) {
1748                         connman_network_unref(task->network);
1749                         task->disconnecting = FALSE;
1750
1751                         if (task->pending_network != NULL) {
1752                                 task->network = task->pending_network;
1753                                 task->pending_network = NULL;
1754                                 task_connect(task);
1755                         } else
1756                                 task->network = NULL;
1757                 }
1758                 break;
1759
1760         default:
1761                 connman_network_set_associating(task->network, FALSE);
1762                 break;
1763         }
1764
1765         return;
1766
1767 badstate:
1768         connman_error("%s invalid state change %s -> %s", task->ifname,
1769                                                         oldstate, newstate);
1770 }
1771
1772 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1773                                                 DBusMessage *msg, void *data)
1774 {
1775         struct supplicant_task *task;
1776         const char *member, *path;
1777
1778         if (dbus_message_has_interface(msg,
1779                                 SUPPLICANT_INTF ".Interface") == FALSE)
1780                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1781
1782         member = dbus_message_get_member(msg);
1783         if (member == NULL)
1784                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1785
1786         path = dbus_message_get_path(msg);
1787         if (path == NULL)
1788                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1789
1790         task = find_task_by_path(path);
1791         if (task == NULL)
1792                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1793
1794         DBG("task %p member %s", task, member);
1795
1796         if (g_str_equal(member, "ScanResultsAvailable") == TRUE)
1797                 scan_results_available(task);
1798         else if (g_str_equal(member, "Scanning") == TRUE)
1799                 scanning(task, msg);
1800         else if (g_str_equal(member, "StateChange") == TRUE)
1801                 state_change(task, msg);
1802
1803         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1804 }
1805
1806 int supplicant_start(struct connman_device *device)
1807 {
1808         struct supplicant_task *task;
1809         int err;
1810
1811         DBG("device %p", device);
1812
1813         task = g_try_new0(struct supplicant_task, 1);
1814         if (task == NULL)
1815                 return -ENOMEM;
1816
1817         task->ifindex = connman_device_get_index(device);
1818         task->ifname = connman_inet_ifname(task->ifindex);
1819
1820         if (task->ifname == NULL) {
1821                 err = -ENOMEM;
1822                 goto failed;
1823         }
1824
1825         task->mac80211 = connman_inet_is_mac80211(task->ifindex);
1826         if (task->mac80211 == FALSE)
1827                 connman_warn("Enabling quirks for unsupported driver");
1828
1829         task->range = g_try_malloc0(sizeof(struct iw_range));
1830         if (task->range == NULL) {
1831                 err = -ENOMEM;
1832                 goto failed;
1833         }
1834
1835         err = get_range(task);
1836         if (err < 0)
1837                 goto failed;
1838
1839         task->device = connman_device_ref(device);
1840
1841         task->created = FALSE;
1842         task->scanning = FALSE;
1843         task->state = WPA_INVALID;
1844         task->disconnecting = FALSE;
1845         task->pending_network = NULL;
1846
1847         task_list = g_slist_append(task_list, task);
1848
1849         return create_interface(task);
1850
1851 failed:
1852         g_free(task->range);
1853         g_free(task->ifname);
1854         g_free(task);
1855
1856         return err;
1857 }
1858
1859 int supplicant_stop(struct connman_device *device)
1860 {
1861         int index = connman_device_get_index(device);
1862         struct supplicant_task *task;
1863
1864         DBG("device %p", device);
1865
1866         task = find_task_by_index(index);
1867         if (task == NULL)
1868                 return -ENODEV;
1869
1870         g_free(task->range);
1871
1872         task_list = g_slist_remove(task_list, task);
1873
1874         if (task->scan_call != NULL) {
1875                 dbus_pending_call_cancel(task->scan_call);
1876                 task->scan_call = NULL;
1877         }
1878
1879         if (task->result_call != NULL) {
1880                 dbus_pending_call_cancel(task->result_call);
1881                 task->result_call = NULL;
1882         }
1883
1884         if (task->scanning == TRUE)
1885                 connman_device_set_scanning(task->device, FALSE);
1886
1887         remove_network(task);
1888
1889         disconnect_network(task);
1890
1891         return remove_interface(task);
1892 }
1893
1894 int supplicant_scan(struct connman_device *device)
1895 {
1896         int index = connman_device_get_index(device);
1897         struct supplicant_task *task;
1898         int err;
1899
1900         DBG("device %p", device);
1901
1902         task = find_task_by_index(index);
1903         if (task == NULL)
1904                 return -ENODEV;
1905
1906         switch (task->state) {
1907         case WPA_SCANNING:
1908                 return -EALREADY;
1909         case WPA_ASSOCIATING:
1910         case WPA_ASSOCIATED:
1911         case WPA_4WAY_HANDSHAKE:
1912         case WPA_GROUP_HANDSHAKE:
1913                 return -EBUSY;
1914         default:
1915                 break;
1916         }
1917
1918         task->scanning = TRUE;
1919
1920         err = initiate_scan(task);
1921         if (err < 0) {
1922                 if (err == -EINPROGRESS)
1923                         return 0;
1924
1925                 task->scanning = FALSE;
1926                 return err;
1927         }
1928
1929         connman_device_set_scanning(task->device, TRUE);
1930
1931         return 0;
1932 }
1933
1934 int supplicant_connect(struct connman_network *network)
1935 {
1936         struct supplicant_task *task;
1937         int index;
1938
1939         DBG("network %p", network);
1940
1941         index = connman_network_get_index(network);
1942
1943         task = find_task_by_index(index);
1944         if (task == NULL)
1945                 return -ENODEV;
1946
1947         if (task->disconnecting == TRUE)
1948                 task->pending_network = connman_network_ref(network);
1949         else {
1950                 task->network = connman_network_ref(network);
1951                 return task_connect(task);
1952         }
1953
1954         return -EINPROGRESS;
1955 }
1956
1957 int supplicant_disconnect(struct connman_network *network)
1958 {
1959         struct supplicant_task *task;
1960         int index;
1961
1962         DBG("network %p", network);
1963
1964         index = connman_network_get_index(network);
1965
1966         task = find_task_by_index(index);
1967         if (task == NULL)
1968                 return -ENODEV;
1969
1970         if (task->disconnecting == TRUE)
1971                 return -EALREADY;
1972
1973         remove_network(task);
1974
1975         disconnect_network(task);
1976
1977         task->disconnecting = TRUE;
1978
1979         return 0;
1980 }
1981
1982 static void supplicant_activate(DBusConnection *conn)
1983 {
1984         DBusMessage *message;
1985
1986         DBG("conn %p", conn);
1987
1988         message = dbus_message_new_method_call(SUPPLICANT_NAME, "/",
1989                                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect");
1990         if (message == NULL)
1991                 return;
1992
1993         dbus_message_set_no_reply(message, TRUE);
1994
1995         dbus_connection_send(conn, message, NULL);
1996
1997         dbus_message_unref(message);
1998 }
1999
2000 static GSList *driver_list = NULL;
2001
2002 static void supplicant_probe(DBusConnection *conn, void *user_data)
2003 {
2004         GSList *list;
2005
2006         DBG("conn %p", conn);
2007
2008         for (list = driver_list; list; list = list->next) {
2009                 struct supplicant_driver *driver = list->data;
2010
2011                 DBG("driver %p name %s", driver, driver->name);
2012
2013                 if (driver->probe)
2014                         driver->probe();
2015         }
2016 }
2017
2018 static void supplicant_remove(DBusConnection *conn, void *user_data)
2019 {
2020         GSList *list;
2021
2022         DBG("conn %p", conn);
2023
2024         for (list = driver_list; list; list = list->next) {
2025                 struct supplicant_driver *driver = list->data;
2026
2027                 DBG("driver %p name %s", driver, driver->name);
2028
2029                 if (driver->remove)
2030                         driver->remove();
2031         }
2032 }
2033
2034 static const char *supplicant_rule = "type=signal,"
2035                                 "interface=" SUPPLICANT_INTF ".Interface";
2036 static guint watch;
2037
2038 static int supplicant_create(void)
2039 {
2040         if (g_slist_length(driver_list) > 0)
2041                 return 0;
2042
2043         connection = connman_dbus_get_connection();
2044         if (connection == NULL)
2045                 return -EIO;
2046
2047         DBG("connection %p", connection);
2048
2049         if (dbus_connection_add_filter(connection,
2050                                 supplicant_filter, NULL, NULL) == FALSE) {
2051                 connection = connman_dbus_get_connection();
2052                 return -EIO;
2053         }
2054
2055         dbus_bus_add_match(connection, supplicant_rule, NULL);
2056         dbus_connection_flush(connection);
2057
2058         watch = g_dbus_add_service_watch(connection, SUPPLICANT_NAME,
2059                         supplicant_probe, supplicant_remove, NULL, NULL);
2060
2061         return 0;
2062 }
2063
2064 static void supplicant_destroy(void)
2065 {
2066         if (g_slist_length(driver_list) > 0)
2067                 return;
2068
2069         DBG("connection %p", connection);
2070
2071         if (watch > 0)
2072                 g_dbus_remove_watch(connection, watch);
2073
2074         dbus_bus_remove_match(connection, supplicant_rule, NULL);
2075         dbus_connection_flush(connection);
2076
2077         dbus_connection_remove_filter(connection, supplicant_filter, NULL);
2078
2079         dbus_connection_unref(connection);
2080         connection = NULL;
2081 }
2082
2083 int supplicant_register(struct supplicant_driver *driver)
2084 {
2085         int err;
2086
2087         DBG("driver %p name %s", driver, driver->name);
2088
2089         err = supplicant_create();
2090         if (err < 0)
2091                 return err;
2092
2093         driver_list = g_slist_append(driver_list, driver);
2094
2095         supplicant_activate(connection);
2096
2097         return 0;
2098 }
2099
2100 void supplicant_unregister(struct supplicant_driver *driver)
2101 {
2102         DBG("driver %p name %s", driver, driver->name);
2103
2104         supplicant_remove(connection, NULL);
2105
2106         driver_list = g_slist_remove(driver_list, driver);
2107
2108         supplicant_destroy();
2109 }