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