Add more HSO implementation details
[framework/connectivity/connman.git] / plugins / supplicant.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  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 <stdlib.h>
27 #include <string.h>
28 #include <dbus/dbus.h>
29
30 #include <glib.h>
31
32 #define CONNMAN_API_SUBJECT_TO_CHANGE
33 #include <connman/log.h>
34 #include <connman/dbus.h>
35
36 #include "inet.h"
37 #include "supplicant.h"
38
39 #define TIMEOUT 5000
40
41 #define IEEE80211_CAP_ESS       0x0001
42 #define IEEE80211_CAP_IBSS      0x0002
43 #define IEEE80211_CAP_PRIVACY   0x0010
44
45 struct supplicant_task {
46         int ifindex;
47         gchar *ifname;
48         struct connman_device *device;
49         struct supplicant_callback *callback;
50         gchar *path;
51         gboolean created;
52         gchar *network;
53         enum supplicant_state state;
54 };
55
56 static GSList *task_list = NULL;
57
58 static DBusConnection *connection;
59
60 static struct supplicant_task *find_task_by_index(int index)
61 {
62         GSList *list;
63
64         for (list = task_list; list; list = list->next) {
65                 struct supplicant_task *task = list->data;
66
67                 if (task->ifindex == index)
68                         return task;
69         }
70
71         return NULL;
72 }
73
74 static struct supplicant_task *find_task_by_path(const char *path)
75 {
76         GSList *list;
77
78         for (list = task_list; list; list = list->next) {
79                 struct supplicant_task *task = list->data;
80
81                 if (g_str_equal(task->path, path) == TRUE)
82                         return task;
83         }
84
85         return NULL;
86 }
87
88 static int get_interface(struct supplicant_task *task)
89 {
90         DBusMessage *message, *reply;
91         DBusError error;
92         const char *path;
93
94         DBG("task %p", task);
95
96         message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
97                                         SUPPLICANT_INTF, "getInterface");
98         if (message == NULL)
99                 return -ENOMEM;
100
101         dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
102                                                         DBUS_TYPE_INVALID);
103
104         dbus_error_init(&error);
105
106         reply = dbus_connection_send_with_reply_and_block(connection,
107                                                         message, -1, &error);
108         if (reply == NULL) {
109                 if (dbus_error_is_set(&error) == TRUE) {
110                         connman_error("%s", error.message);
111                         dbus_error_free(&error);
112                 } else
113                         connman_error("Failed to get interface");
114                 dbus_message_unref(message);
115                 return -EIO;
116         }
117
118         dbus_message_unref(message);
119
120         dbus_error_init(&error);
121
122         if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
123                                                 DBUS_TYPE_INVALID) == FALSE) {
124                 if (dbus_error_is_set(&error) == TRUE) {
125                         connman_error("%s", error.message);
126                         dbus_error_free(&error);
127                 } else
128                         connman_error("Wrong arguments for interface");
129                 dbus_message_unref(reply);
130                 return -EIO;
131         }
132
133         DBG("path %s", path);
134
135         task->path = g_strdup(path);
136         task->created = FALSE;
137
138         dbus_message_unref(reply);
139
140         return 0;
141 }
142
143 static int add_interface(struct supplicant_task *task)
144 {
145         DBusMessage *message, *reply;
146         DBusError error;
147         const char *path;
148
149         DBG("task %p", task);
150
151         message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
152                                         SUPPLICANT_INTF, "addInterface");
153         if (message == NULL)
154                 return -ENOMEM;
155
156         dbus_error_init(&error);
157
158         dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
159                                                         DBUS_TYPE_INVALID);
160
161         reply = dbus_connection_send_with_reply_and_block(connection,
162                                                         message, -1, &error);
163         if (reply == NULL) {
164                 if (dbus_error_is_set(&error) == TRUE) {
165                         connman_error("%s", error.message);
166                         dbus_error_free(&error);
167                 } else
168                         connman_error("Failed to add interface");
169                 dbus_message_unref(message);
170                 return -EIO;
171         }
172
173         dbus_message_unref(message);
174
175         dbus_error_init(&error);
176
177         if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
178                                                 DBUS_TYPE_INVALID) == FALSE) {
179                 if (dbus_error_is_set(&error) == TRUE) {
180                         connman_error("%s", error.message);
181                         dbus_error_free(&error);
182                 } else
183                         connman_error("Wrong arguments for interface");
184                 dbus_message_unref(reply);
185                 return -EIO;
186         }
187
188         DBG("path %s", path);
189
190         task->path = g_strdup(path);
191         task->created = TRUE;
192
193         dbus_message_unref(reply);
194
195         return 0;
196 }
197
198 static int remove_interface(struct supplicant_task *task)
199 {
200         DBusMessage *message, *reply;
201         DBusError error;
202
203         DBG("task %p", task);
204
205         if (task->created == FALSE)
206                 return -EINVAL;
207
208         message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
209                                         SUPPLICANT_INTF, "removeInterface");
210         if (message == NULL)
211                 return -ENOMEM;
212
213         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->path,
214                                                         DBUS_TYPE_INVALID);
215
216         dbus_error_init(&error);
217
218         reply = dbus_connection_send_with_reply_and_block(connection,
219                                                         message, -1, &error);
220         if (reply == NULL) {
221                 if (dbus_error_is_set(&error) == TRUE) {
222                         connman_error("%s", error.message);
223                         dbus_error_free(&error);
224                 } else
225                         connman_error("Failed to remove interface");
226                 dbus_message_unref(message);
227                 return -EIO;
228         }
229
230         dbus_message_unref(message);
231
232         dbus_message_unref(reply);
233
234         return 0;
235 }
236
237 static int set_ap_scan(struct supplicant_task *task)
238 {
239         DBusMessage *message, *reply;
240         DBusError error;
241         guint32 ap_scan = 1;
242
243         DBG("task %p", task);
244
245         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
246                                 SUPPLICANT_INTF ".Interface", "setAPScan");
247         if (message == NULL)
248                 return -ENOMEM;
249
250         dbus_message_append_args(message, DBUS_TYPE_UINT32, &ap_scan,
251                                                         DBUS_TYPE_INVALID);
252
253         dbus_error_init(&error);
254
255         reply = dbus_connection_send_with_reply_and_block(connection,
256                                                         message, -1, &error);
257         if (reply == NULL) {
258                 if (dbus_error_is_set(&error) == TRUE) {
259                         connman_error("%s", error.message);
260                         dbus_error_free(&error);
261                 } else
262                         connman_error("Failed to set AP scan");
263                 dbus_message_unref(message);
264                 return -EIO;
265         }
266
267         dbus_message_unref(message);
268
269         dbus_message_unref(reply);
270
271         return 0;
272 }
273
274 static int add_network(struct supplicant_task *task)
275 {
276         DBusMessage *message, *reply;
277         DBusError error;
278         const char *path;
279
280         DBG("task %p", task);
281
282         if (task->network != NULL)
283                 return -EALREADY;
284
285         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
286                                 SUPPLICANT_INTF ".Interface", "addNetwork");
287         if (message == NULL)
288                 return -ENOMEM;
289
290         dbus_error_init(&error);
291
292         reply = dbus_connection_send_with_reply_and_block(connection,
293                                                         message, -1, &error);
294         if (reply == NULL) {
295                 if (dbus_error_is_set(&error) == TRUE) {
296                         connman_error("%s", error.message);
297                         dbus_error_free(&error);
298                 } else
299                         connman_error("Failed to add network");
300                 dbus_message_unref(message);
301                 return -EIO;
302         }
303
304         dbus_message_unref(message);
305
306         dbus_error_init(&error);
307
308         if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
309                                                 DBUS_TYPE_INVALID) == FALSE) {
310                 if (dbus_error_is_set(&error) == TRUE) {
311                         connman_error("%s", error.message);
312                         dbus_error_free(&error);
313                 } else
314                         connman_error("Wrong arguments for network");
315                 dbus_message_unref(reply);
316                 return -EIO;
317         }
318
319         DBG("path %s", path);
320
321         task->network = g_strdup(path);
322
323         dbus_message_unref(reply);
324
325         return 0;
326 }
327
328 static int remove_network(struct supplicant_task *task)
329 {
330         DBusMessage *message, *reply;
331         DBusError error;
332
333         DBG("task %p", task);
334
335         if (task->network == NULL)
336                 return -EINVAL;
337
338         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
339                                 SUPPLICANT_INTF ".Interface", "removeNetwork");
340         if (message == NULL)
341                 return -ENOMEM;
342
343         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network,
344                                                         DBUS_TYPE_INVALID);
345
346         dbus_error_init(&error);
347
348         reply = dbus_connection_send_with_reply_and_block(connection,
349                                                         message, -1, &error);
350         if (reply == NULL) {
351                 if (dbus_error_is_set(&error) == TRUE) {
352                         connman_error("%s", error.message);
353                         dbus_error_free(&error);
354                 } else
355                         connman_error("Failed to remove network");
356                 dbus_message_unref(message);
357                 return -EIO;
358         }
359
360         dbus_message_unref(message);
361
362         dbus_message_unref(reply);
363
364         g_free(task->network);
365         task->network = NULL;
366
367         return 0;
368 }
369
370 static int select_network(struct supplicant_task *task)
371 {
372         DBusMessage *message, *reply;
373         DBusError error;
374
375         DBG("task %p", task);
376
377         if (task->network == NULL)
378                 return -EINVAL;
379
380         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
381                                 SUPPLICANT_INTF ".Interface", "selectNetwork");
382         if (message == NULL)
383                 return -ENOMEM;
384
385         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network,
386                                                         DBUS_TYPE_INVALID);
387
388         dbus_error_init(&error);
389
390         reply = dbus_connection_send_with_reply_and_block(connection,
391                                                         message, -1, &error);
392         if (reply == NULL) {
393                 if (dbus_error_is_set(&error) == TRUE) {
394                         connman_error("%s", error.message);
395                         dbus_error_free(&error);
396                 } else
397                         connman_error("Failed to select network");
398                 dbus_message_unref(message);
399                 return -EIO;
400         }
401
402         dbus_message_unref(message);
403
404         dbus_message_unref(reply);
405
406         return 0;
407 }
408
409 static int enable_network(struct supplicant_task *task)
410 {
411         DBusMessage *message, *reply;
412         DBusError error;
413
414         DBG("task %p", task);
415
416         if (task->network == NULL)
417                 return -EINVAL;
418
419         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
420                                         SUPPLICANT_INTF ".Network", "enable");
421         if (message == NULL)
422                 return -ENOMEM;
423
424         dbus_error_init(&error);
425
426         reply = dbus_connection_send_with_reply_and_block(connection,
427                                                         message, -1, &error);
428         if (reply == NULL) {
429                 if (dbus_error_is_set(&error) == TRUE) {
430                         connman_error("%s", error.message);
431                         dbus_error_free(&error);
432                 } else
433                         connman_error("Failed to enable network");
434                 dbus_message_unref(message);
435                 return -EIO;
436         }
437
438         dbus_message_unref(message);
439
440         dbus_message_unref(reply);
441
442         return 0;
443 }
444
445 static int disable_network(struct supplicant_task *task)
446 {
447         DBusMessage *message, *reply;
448         DBusError error;
449
450         DBG("task %p", task);
451
452         if (task->network == NULL)
453                 return -EINVAL;
454
455         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
456                                         SUPPLICANT_INTF ".Network", "disable");
457         if (message == NULL)
458                 return -ENOMEM;
459
460         dbus_error_init(&error);
461
462         reply = dbus_connection_send_with_reply_and_block(connection,
463                                                         message, -1, &error);
464         if (reply == NULL) {
465                 if (dbus_error_is_set(&error) == TRUE) {
466                         connman_error("%s", error.message);
467                         dbus_error_free(&error);
468                 } else
469                         connman_error("Failed to disable network");
470                 dbus_message_unref(message);
471                 return -EIO;
472         }
473
474         dbus_message_unref(message);
475
476         dbus_message_unref(reply);
477
478         return 0;
479 }
480
481 static int set_network(struct supplicant_task *task,
482                                 const unsigned char *network, int len,
483                                 const char *security, const char *passphrase)
484 {
485         DBusMessage *message, *reply;
486         DBusMessageIter array, dict;
487         DBusError error;
488
489         DBG("task %p", task);
490
491         if (task->network == NULL)
492                 return -EINVAL;
493
494         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
495                                         SUPPLICANT_INTF ".Network", "set");
496         if (message == NULL)
497                 return -ENOMEM;
498
499         dbus_message_iter_init_append(message, &array);
500
501         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
502                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
503                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
504                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
505
506         connman_dbus_dict_append_array(&dict, "ssid",
507                                         DBUS_TYPE_BYTE, &network, len);
508
509         if (g_ascii_strcasecmp(security, "wpa") == 0 ||
510                                 g_ascii_strcasecmp(security, "wpa2") == 0) {
511                 const char *key_mgmt = "WPA-PSK";
512                 connman_dbus_dict_append_variant(&dict, "key_mgmt",
513                                                 DBUS_TYPE_STRING, &key_mgmt);
514
515                 if (passphrase && strlen(passphrase) > 0)
516                         connman_dbus_dict_append_variant(&dict, "psk",
517                                                 DBUS_TYPE_STRING, &passphrase);
518         } else if (g_ascii_strcasecmp(security, "wep") == 0) {
519                 const char *key_mgmt = "NONE", *index = "0";
520                 connman_dbus_dict_append_variant(&dict, "key_mgmt",
521                                                 DBUS_TYPE_STRING, &key_mgmt);
522
523                 if (passphrase) {
524                         int size = strlen(passphrase);
525                         if (size == 10 || size == 26) {
526                                 unsigned char *key = malloc(13);
527                                 char tmp[3];
528                                 int i;
529                                 memset(tmp, 0, sizeof(tmp));
530                                 if (key == NULL)
531                                         size = 0;
532                                 for (i = 0; i < size / 2; i++) {
533                                         memcpy(tmp, passphrase + (i * 2), 2);
534                                         key[i] = (unsigned char) strtol(tmp,
535                                                                 NULL, 16);
536                                 }
537                                 connman_dbus_dict_append_array(&dict,
538                                                 "wep_key0", DBUS_TYPE_BYTE,
539                                                         &key, size / 2);
540                                 free(key);
541                         } else
542                                 connman_dbus_dict_append_variant(&dict,
543                                                 "wep_key0", DBUS_TYPE_STRING,
544                                                                 &passphrase);
545                         connman_dbus_dict_append_variant(&dict, "wep_tx_keyidx",
546                                                 DBUS_TYPE_STRING, &index);
547                 }
548         } else {
549                 const char *key_mgmt = "NONE";
550                 connman_dbus_dict_append_variant(&dict, "key_mgmt",
551                                                 DBUS_TYPE_STRING, &key_mgmt);
552         }
553
554         dbus_message_iter_close_container(&array, &dict);
555
556         dbus_error_init(&error);
557
558         reply = dbus_connection_send_with_reply_and_block(connection,
559                                                         message, -1, &error);
560         if (reply == NULL) {
561                 if (dbus_error_is_set(&error) == TRUE) {
562                         connman_error("%s", error.message);
563                         dbus_error_free(&error);
564                 } else
565                         connman_error("Failed to set network options");
566                 dbus_message_unref(message);
567                 return -EIO;
568         }
569
570         dbus_message_unref(message);
571
572         dbus_message_unref(reply);
573
574         return 0;
575 }
576
577 static int initiate_scan(struct supplicant_task *task)
578 {
579         DBusMessage *message;
580         DBusPendingCall *call;
581
582         DBG("task %p", task);
583
584         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
585                                         SUPPLICANT_INTF ".Interface", "scan");
586         if (message == NULL)
587                 return -ENOMEM;
588
589         if (dbus_connection_send_with_reply(connection, message,
590                                                 &call, TIMEOUT) == FALSE) {
591                 connman_error("Failed to initiate scan");
592                 dbus_message_unref(message);
593                 return -EIO;
594         }
595
596         dbus_message_unref(message);
597
598         return 0;
599 }
600
601 static void extract_ssid(struct supplicant_network *network,
602                                                 DBusMessageIter *value)
603 {
604         DBusMessageIter array;
605         unsigned char *ssid;
606         int ssid_len;
607
608         dbus_message_iter_recurse(value, &array);
609         dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
610
611         if (ssid_len < 1)
612                 return;
613
614         network->ssid = g_try_malloc(ssid_len);
615         if (network->ssid == NULL)
616                 return;
617
618         memcpy(network->ssid, ssid, ssid_len);
619         network->ssid_len = ssid_len;
620
621         network->identifier = g_try_malloc0(ssid_len + 1);
622         if (network->identifier == NULL)
623                 return;
624
625         memcpy(network->identifier, ssid, ssid_len);
626 }
627
628 static void extract_wpaie(struct supplicant_network *network,
629                                                 DBusMessageIter *value)
630 {
631         DBusMessageIter array;
632         unsigned char *ie;
633         int ie_len;
634
635         dbus_message_iter_recurse(value, &array);
636         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
637
638         if (ie_len > 0)
639                 network->has_wpa = TRUE;
640 }
641
642 static void extract_rsnie(struct supplicant_network *network,
643                                                 DBusMessageIter *value)
644 {
645         DBusMessageIter array;
646         unsigned char *ie;
647         int ie_len;
648
649         dbus_message_iter_recurse(value, &array);
650         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
651
652         if (ie_len > 0)
653                 network->has_rsn = TRUE;
654 }
655
656 static void extract_capabilites(struct supplicant_network *network,
657                                                 DBusMessageIter *value)
658 {
659         dbus_message_iter_get_basic(value, &network->capabilities);
660
661         if (network->capabilities & IEEE80211_CAP_ESS)
662                 network->adhoc = FALSE;
663         else if (network->capabilities & IEEE80211_CAP_IBSS)
664                 network->adhoc = TRUE;
665
666         if (network->capabilities & IEEE80211_CAP_PRIVACY)
667                 network->has_wep = TRUE;
668 }
669
670 static void properties_reply(DBusPendingCall *call, void *user_data)
671 {
672         struct supplicant_task *task = user_data;
673         struct supplicant_network *network;
674         DBusMessage *reply;
675         DBusMessageIter array, dict;
676
677         DBG("task %p", task);
678
679         reply = dbus_pending_call_steal_reply(call);
680
681         network = g_try_new0(struct supplicant_network, 1);
682         if (network == NULL)
683                 goto done;
684
685         dbus_message_iter_init(reply, &array);
686
687         dbus_message_iter_recurse(&array, &dict);
688
689         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
690                 DBusMessageIter entry, value;
691                 const char *key;
692
693                 dbus_message_iter_recurse(&dict, &entry);
694                 dbus_message_iter_get_basic(&entry, &key);
695
696                 dbus_message_iter_next(&entry);
697
698                 dbus_message_iter_recurse(&entry, &value);
699
700                 //type = dbus_message_iter_get_arg_type(&value);
701                 //dbus_message_iter_get_basic(&value, &val);
702
703                 /* 
704                  * bssid        : a (97)
705                  * ssid         : a (97)
706                  * wpaie        : a (97)
707                  * rsnie        : a (97)
708                  * frequency    : i (105)
709                  * capabilities : q (113)
710                  * quality      : i (105)
711                  * noise        : i (105)
712                  * level        : i (105)
713                  * maxrate      : i (105)
714                  */
715
716                 if (g_str_equal(key, "ssid") == TRUE)
717                         extract_ssid(network, &value);
718                 else if (g_str_equal(key, "wpaie") == TRUE)
719                         extract_wpaie(network, &value);
720                 else if (g_str_equal(key, "rsnie") == TRUE)
721                         extract_rsnie(network, &value);
722                 else if (g_str_equal(key, "capabilities") == TRUE)
723                         extract_capabilites(network, &value);
724                 else if (g_str_equal(key, "quality") == TRUE)
725                         dbus_message_iter_get_basic(&value, &network->quality);
726                 else if (g_str_equal(key, "noise") == TRUE)
727                         dbus_message_iter_get_basic(&value, &network->noise);
728                 else if (g_str_equal(key, "level") == TRUE)
729                         dbus_message_iter_get_basic(&value, &network->level);
730                 else if (g_str_equal(key, "maxrate") == TRUE)
731                         dbus_message_iter_get_basic(&value, &network->maxrate);
732
733
734                 dbus_message_iter_next(&dict);
735         }
736
737         if (task->callback && task->callback->scan_result)
738                 task->callback->scan_result(task->device, network);
739
740         g_free(network->identifier);
741         g_free(network->ssid);
742         g_free(network);
743
744 done:
745         dbus_message_unref(reply);
746 }
747
748 static int get_network_properties(struct supplicant_task *task,
749                                                         const char *path)
750 {
751         DBusMessage *message;
752         DBusPendingCall *call;
753
754         message = dbus_message_new_method_call(SUPPLICANT_NAME, path,
755                                                 SUPPLICANT_INTF ".BSSID",
756                                                                 "properties");
757         if (message == NULL)
758                 return -ENOMEM;
759
760         if (dbus_connection_send_with_reply(connection, message,
761                                                 &call, TIMEOUT) == FALSE) {
762                 connman_error("Failed to get network properties");
763                 dbus_message_unref(message);
764                 return -EIO;
765         }
766
767         dbus_pending_call_set_notify(call, properties_reply, task, NULL);
768
769         dbus_message_unref(message);
770
771         return 0;
772 }
773
774 static void scan_results_reply(DBusPendingCall *call, void *user_data)
775 {
776         struct supplicant_task *task = user_data;
777         DBusMessage *reply;
778         DBusError error;
779         char **results;
780         int i, num_results;
781
782         DBG("task %p", task);
783
784         reply = dbus_pending_call_steal_reply(call);
785
786         dbus_error_init(&error);
787
788         if (dbus_message_get_args(reply, &error,
789                                 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
790                                                 &results, &num_results,
791                                                 DBUS_TYPE_INVALID) == FALSE) {
792                 if (dbus_error_is_set(&error) == TRUE) {
793                         connman_error("%s", error.message);
794                         dbus_error_free(&error);
795                 } else
796                         connman_error("Wrong arguments for scan result");
797                 goto done;
798         }
799
800         if (task->callback && task->callback->clear_results)
801                         task->callback->clear_results(task->device);
802
803         for (i = 0; i < num_results; i++)
804                 get_network_properties(task, results[i]);
805
806         g_strfreev(results);
807
808 done:
809         dbus_message_unref(reply);
810 }
811
812 static int scan_results_available(struct supplicant_task *task)
813 {
814         DBusMessage *message;
815         DBusPendingCall *call;
816
817         DBG("task %p", task);
818
819         message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
820                                                 SUPPLICANT_INTF ".Interface",
821                                                         "scanResults");
822         if (message == NULL)
823                 return -ENOMEM;
824
825         if (dbus_connection_send_with_reply(connection, message,
826                                                 &call, TIMEOUT) == FALSE) {
827                 connman_error("Failed to request scan result");
828                 dbus_message_unref(message);
829                 return -EIO;
830         }
831
832         dbus_pending_call_set_notify(call, scan_results_reply, task, NULL);
833
834         dbus_message_unref(message);
835
836         return 0;
837 }
838
839 static void state_change(struct supplicant_task *task, DBusMessage *msg)
840 {
841         DBusError error;
842         const char *state, *previous;
843
844         dbus_error_init(&error);
845
846         if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &state,
847                                                 DBUS_TYPE_STRING, &previous,
848                                                 DBUS_TYPE_INVALID) == FALSE) {
849                 if (dbus_error_is_set(&error) == TRUE) {
850                         connman_error("%s", error.message);
851                         dbus_error_free(&error);
852                 } else
853                         connman_error("Wrong arguments for state change");
854                 return;
855         }
856
857         DBG("state %s ==> %s", previous, state);
858
859         if (g_str_equal(state, "INACTIVE") == TRUE)
860                 task->state = STATE_INACTIVE;
861         else if (g_str_equal(state, "SCANNING") == TRUE)
862                 task->state = STATE_SCANNING;
863         else if (g_str_equal(state, "ASSOCIATING") == TRUE)
864                 task->state = STATE_ASSOCIATING;
865         else if (g_str_equal(state, "ASSOCIATED") == TRUE)
866                 task->state = STATE_ASSOCIATED;
867         else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE)
868                 task->state = STATE_4WAY_HANDSHAKE;
869         else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE)
870                 task->state = STATE_4WAY_HANDSHAKE;
871         else if (g_str_equal(state, "COMPLETED") == TRUE)
872                 task->state = STATE_COMPLETED;
873         else if (g_str_equal(state, "DISCONNECTED") == TRUE)
874                 task->state = STATE_DISCONNECTED;
875
876         if (task->callback && task->callback->state_change)
877                 task->callback->state_change(task->device, task->state);
878
879         switch (task->state) {
880         case STATE_COMPLETED:
881                 /* carrier on */
882                 break;
883         case STATE_DISCONNECTED:
884                 /* carrier off */
885                 break;
886         default:
887                 break;
888         }
889 }
890
891 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
892                                                 DBusMessage *msg, void *data)
893 {
894         struct supplicant_task *task;
895         const char *member, *path;
896
897         if (dbus_message_has_interface(msg,
898                                 SUPPLICANT_INTF ".Interface") == FALSE)
899                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
900
901         member = dbus_message_get_member(msg);
902         if (member == NULL)
903                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
904
905         path = dbus_message_get_path(msg);
906         if (path == NULL)
907                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
908
909         task = find_task_by_path(path);
910         if (task == NULL)
911                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
912
913         DBG("task %p member %s", task, member);
914
915         if (g_str_equal(member, "ScanResultsAvailable") == TRUE)
916                 scan_results_available(task);
917         else if (g_str_equal(member, "StateChange") == TRUE)
918                 state_change(task, msg);
919
920         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
921 }
922
923 static int add_filter(struct supplicant_task *task)
924 {
925         DBusError error;
926         gchar *filter;
927
928         filter = g_strdup_printf("type=signal,interface=%s.Interface,path=%s",
929                                                 SUPPLICANT_INTF, task->path);
930
931         DBG("filter %s", filter);
932
933         dbus_error_init(&error);
934
935         dbus_bus_add_match(connection, filter, &error);
936
937         g_free(filter);
938
939         if (dbus_error_is_set(&error) == TRUE) {
940                 connman_error("Can't add match: %s", error.message);
941                 dbus_error_free(&error);
942         }
943
944         return 0;
945 }
946
947 static int remove_filter(struct supplicant_task *task)
948 {
949         DBusError error;
950         gchar *filter;
951
952         filter = g_strdup_printf("type=signal,interface=%s.Interface,path=%s",
953                                                 SUPPLICANT_INTF, task->path);
954
955         DBG("filter %s", filter);
956
957         dbus_error_init(&error);
958
959         dbus_bus_remove_match(connection, filter, &error);
960
961         g_free(filter);
962
963         if (dbus_error_is_set(&error) == TRUE) {
964                 connman_error("Can't add match: %s", error.message);
965                 dbus_error_free(&error);
966         }
967
968         return 0;
969 }
970
971 int __supplicant_start(struct connman_device *device,
972                                         struct supplicant_callback *callback)
973 {
974         struct supplicant_task *task;
975         int err;
976
977         DBG("device %p", device);
978
979         task = g_try_new0(struct supplicant_task, 1);
980         if (task == NULL)
981                 return -ENOMEM;
982
983         task->ifindex = connman_device_get_index(device);
984         task->ifname = inet_index2name(task->ifindex);
985         task->device = device;
986         task->callback = callback;
987
988         if (task->ifname == NULL) {
989                 g_free(task);
990                 return -ENOMEM;
991         }
992
993         task->created = FALSE;
994         task->state = STATE_INACTIVE;
995
996         task_list = g_slist_append(task_list, task);
997
998         err = get_interface(task);
999         if (err < 0) {
1000                 err = add_interface(task);
1001                 if (err < 0) {
1002                         g_free(task);
1003                         return err;
1004                 }
1005         }
1006
1007         add_filter(task);
1008
1009         set_ap_scan(task);
1010
1011         return 0;
1012 }
1013
1014 int __supplicant_stop(struct connman_device *device)
1015 {
1016         int index = connman_device_get_index(device);
1017         struct supplicant_task *task;
1018
1019         DBG("device %p", device);
1020
1021         task = find_task_by_index(index);
1022         if (task == NULL)
1023                 return -ENODEV;
1024
1025         task_list = g_slist_remove(task_list, task);
1026
1027         disable_network(task);
1028
1029         remove_network(task);
1030
1031         remove_filter(task);
1032
1033         remove_interface(task);
1034
1035         g_free(task->ifname);
1036         g_free(task->path);
1037         g_free(task);
1038
1039         return 0;
1040 }
1041
1042 int __supplicant_scan(struct connman_device *device)
1043 {
1044         int index = connman_device_get_index(device);
1045         struct supplicant_task *task;
1046         int err;
1047
1048         DBG("device %p", device);
1049
1050         task = find_task_by_index(index);
1051         if (task == NULL)
1052                 return -ENODEV;
1053
1054         switch (task->state) {
1055         case STATE_SCANNING:
1056                 return -EALREADY;
1057         case STATE_ASSOCIATING:
1058         case STATE_ASSOCIATED:
1059         case STATE_4WAY_HANDSHAKE:
1060         case STATE_GROUP_HANDSHAKE:
1061                 return -EBUSY;
1062         default:
1063                 break;
1064         }
1065
1066         err = initiate_scan(task);
1067
1068         return 0;
1069 }
1070
1071 int __supplicant_connect(struct connman_element *element,
1072                                 const unsigned char *ssid, int ssid_len,
1073                                 const char *security, const char *passphrase)
1074 {
1075         struct supplicant_task *task;
1076
1077         DBG("element %p", element);
1078
1079         task = find_task_by_index(element->index);
1080         if (task == NULL)
1081                 return -ENODEV;
1082
1083         add_network(task);
1084
1085         select_network(task);
1086         disable_network(task);
1087
1088         set_network(task, ssid, ssid_len, security, passphrase);
1089
1090         enable_network(task);
1091
1092         return 0;
1093 }
1094
1095 int __supplicant_disconnect(struct connman_element *element)
1096 {
1097         struct supplicant_task *task;
1098
1099         DBG("element %p", element);
1100
1101         task = find_task_by_index(element->index);
1102         if (task == NULL)
1103                 return -ENODEV;
1104
1105         disable_network(task);
1106
1107         remove_network(task);
1108
1109         return 0;
1110 }
1111
1112 void __supplicant_activate(DBusConnection *conn)
1113 {
1114         DBusMessage *message;
1115
1116         DBG("conn %p", conn);
1117
1118         message = dbus_message_new_method_call(SUPPLICANT_NAME, "/",
1119                                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect");
1120         if (message == NULL)
1121                 return;
1122
1123         dbus_message_set_no_reply(message, TRUE);
1124
1125         dbus_connection_send(conn, message, NULL);
1126
1127         dbus_message_unref(message);
1128 }
1129
1130 int __supplicant_init(DBusConnection *conn)
1131 {
1132         DBG("conn %p", conn);
1133
1134         connection = conn;
1135
1136         if (dbus_connection_add_filter(connection,
1137                                 supplicant_filter, NULL, NULL) == FALSE) {
1138                 dbus_connection_unref(connection);
1139                 return -EIO;
1140         }
1141
1142         return 0;
1143 }
1144
1145 void __supplicant_exit(void)
1146 {
1147         DBG("conn %p", connection);
1148
1149         dbus_connection_remove_filter(connection, supplicant_filter, NULL);
1150 }