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