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