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