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