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