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