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