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