DA: Skip initializing failed_bssids list when eapol failure case
[platform/upstream/connman.git] / gsupplicant / dbus.c
1 /*
2  *
3  *  WPA supplicant library with GLib integration
4  *
5  *  Copyright (C) 2012-2013  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 <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <dbus/dbus.h>
30 #include <glib.h>
31
32 #include "dbus.h"
33 #include <connman/log.h>
34
35 #define TIMEOUT 30000
36
37 static DBusConnection *connection;
38
39 static GSList *method_calls;
40
41 struct method_call_data {
42         gpointer caller;
43         DBusPendingCall *pending_call;
44         supplicant_dbus_result_function function;
45         void *user_data;
46 };
47
48 static void method_call_free(void *pointer)
49 {
50         struct method_call_data *method_call = pointer;
51         method_calls = g_slist_remove(method_calls, method_call);
52         g_free(method_call);
53 }
54
55 static int find_method_call_by_caller(gconstpointer a, gconstpointer b)
56 {
57         const struct method_call_data *method_call = a;
58         gconstpointer caller = b;
59
60         return method_call->caller != caller;
61 }
62
63 static GSList *property_calls;
64
65 struct property_call_data {
66         gpointer caller;
67         DBusPendingCall *pending_call;
68         supplicant_dbus_property_function function;
69         void *user_data;
70 };
71
72 static void property_call_free(void *pointer)
73 {
74         struct property_call_data *property_call = pointer;
75         property_calls = g_slist_remove(property_calls, property_call);
76         g_free(property_call);
77 }
78
79 static int find_property_call_by_caller(gconstpointer a, gconstpointer b)
80 {
81         const struct property_call_data *property_call = a;
82         gconstpointer caller = b;
83
84         return property_call->caller != caller;
85 }
86
87 void supplicant_dbus_setup(DBusConnection *conn)
88 {
89         connection = conn;
90         method_calls = NULL;
91         property_calls = NULL;
92 }
93
94 void supplicant_dbus_array_foreach(DBusMessageIter *iter,
95                                 supplicant_dbus_array_function function,
96                                                         void *user_data)
97 {
98         DBusMessageIter entry;
99
100         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
101                 return;
102
103         dbus_message_iter_recurse(iter, &entry);
104
105         while (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_INVALID) {
106                 if (function)
107                         function(&entry, user_data);
108
109                 dbus_message_iter_next(&entry);
110         }
111 }
112
113 void supplicant_dbus_property_foreach(DBusMessageIter *iter,
114                                 supplicant_dbus_property_function function,
115                                                         void *user_data)
116 {
117         DBusMessageIter dict;
118
119         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
120                 return;
121
122         dbus_message_iter_recurse(iter, &dict);
123
124         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
125                 DBusMessageIter entry, value;
126                 const char *key;
127
128                 dbus_message_iter_recurse(&dict, &entry);
129
130                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
131                         return;
132
133                 dbus_message_iter_get_basic(&entry, &key);
134                 dbus_message_iter_next(&entry);
135
136                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
137                         return;
138
139                 dbus_message_iter_recurse(&entry, &value);
140
141                 if (key) {
142                         if (strcmp(key, "Properties") == 0)
143                                 supplicant_dbus_property_foreach(&value,
144                                                         function, user_data);
145                         else if (function)
146                                 function(key, &value, user_data);
147                 }
148
149                 dbus_message_iter_next(&dict);
150         }
151 }
152
153 void supplicant_dbus_property_call_cancel_all(gpointer caller)
154 {
155         while (property_calls) {
156                 struct property_call_data *property_call;
157                 GSList *elem = g_slist_find_custom(property_calls, caller,
158                                                 find_property_call_by_caller);
159                 if (!elem)
160                         break;
161
162                 property_call = elem->data;
163                 property_calls = g_slist_delete_link(property_calls, elem);
164
165                 dbus_pending_call_cancel(property_call->pending_call);
166
167                 dbus_pending_call_unref(property_call->pending_call);
168         }
169 }
170
171 static void property_get_all_reply(DBusPendingCall *call, void *user_data)
172 {
173         struct property_call_data *property_call = user_data;
174         DBusMessage *reply;
175         DBusMessageIter iter;
176
177         reply = dbus_pending_call_steal_reply(call);
178
179         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
180                 goto done;
181
182         if (!dbus_message_iter_init(reply, &iter))
183                 goto done;
184
185         supplicant_dbus_property_foreach(&iter, property_call->function,
186                                                 property_call->user_data);
187
188         if (property_call->function)
189                 property_call->function(NULL, NULL, property_call->user_data);
190
191 done:
192         dbus_message_unref(reply);
193
194         dbus_pending_call_unref(call);
195 }
196
197 int supplicant_dbus_property_get_all(const char *path, const char *interface,
198                                 supplicant_dbus_property_function function,
199                                 void *user_data, gpointer caller)
200 {
201         struct property_call_data *property_call = NULL;
202         DBusMessage *message;
203         DBusPendingCall *call;
204
205         if (!connection)
206                 return -EINVAL;
207
208         if (!path || !interface)
209                 return -EINVAL;
210
211         property_call = g_try_new0(struct property_call_data, 1);
212         if (!property_call)
213                 return -ENOMEM;
214
215         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
216                                         DBUS_INTERFACE_PROPERTIES, "GetAll");
217         if (!message) {
218                 g_free(property_call);
219                 return -ENOMEM;
220         }
221
222         dbus_message_set_auto_start(message, FALSE);
223
224         dbus_message_append_args(message, DBUS_TYPE_STRING, &interface, NULL);
225
226         if (!dbus_connection_send_with_reply(connection, message,
227                                                 &call, TIMEOUT)) {
228                 dbus_message_unref(message);
229                 g_free(property_call);
230                 return -EIO;
231         }
232
233         if (!call) {
234                 dbus_message_unref(message);
235                 g_free(property_call);
236                 return -EIO;
237         }
238
239         property_call->caller = caller;
240         property_call->pending_call = call;
241         property_call->function = function;
242         property_call->user_data = user_data;
243
244         property_calls = g_slist_prepend(property_calls, property_call);
245
246         dbus_pending_call_set_notify(call, property_get_all_reply,
247                                 property_call, property_call_free);
248
249         dbus_message_unref(message);
250
251         return 0;
252 }
253
254 static void property_get_reply(DBusPendingCall *call, void *user_data)
255 {
256         struct property_call_data *property_call = user_data;
257         DBusMessage *reply;
258         DBusMessageIter iter;
259
260         reply = dbus_pending_call_steal_reply(call);
261
262         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
263                 goto done;
264
265         if (!dbus_message_iter_init(reply, &iter))
266                 goto done;
267
268         if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
269                 DBusMessageIter variant;
270
271                 dbus_message_iter_recurse(&iter, &variant);
272
273                 if (property_call->function)
274                         property_call->function(NULL, &variant,
275                                                 property_call->user_data);
276         }
277 done:
278         dbus_message_unref(reply);
279
280         dbus_pending_call_unref(call);
281 }
282
283 int supplicant_dbus_property_get(const char *path, const char *interface,
284                                 const char *method,
285                                 supplicant_dbus_property_function function,
286                                 void *user_data, gpointer caller)
287 {
288         struct property_call_data *property_call = NULL;
289         DBusMessage *message;
290         DBusPendingCall *call;
291
292         if (!connection)
293                 return -EINVAL;
294
295         if (!path || !interface || !method)
296                 return -EINVAL;
297
298         property_call = g_try_new0(struct property_call_data, 1);
299         if (!property_call)
300                 return -ENOMEM;
301
302         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
303                                         DBUS_INTERFACE_PROPERTIES, "Get");
304
305         if (!message) {
306                 g_free(property_call);
307                 return -ENOMEM;
308         }
309
310         dbus_message_set_auto_start(message, FALSE);
311
312         dbus_message_append_args(message, DBUS_TYPE_STRING, &interface,
313                                         DBUS_TYPE_STRING, &method, NULL);
314
315         if (!dbus_connection_send_with_reply(connection, message,
316                                                 &call, TIMEOUT)) {
317                 dbus_message_unref(message);
318                 g_free(property_call);
319                 return -EIO;
320         }
321
322         if (!call) {
323                 dbus_message_unref(message);
324                 g_free(property_call);
325                 return -EIO;
326         }
327
328         property_call->caller = caller;
329         property_call->pending_call = call;
330         property_call->function = function;
331         property_call->user_data = user_data;
332
333         property_calls = g_slist_prepend(property_calls, property_call);
334
335         dbus_pending_call_set_notify(call, property_get_reply,
336                                         property_call, property_call_free);
337
338         dbus_message_unref(message);
339
340         return 0;
341 }
342
343 static void property_set_reply(DBusPendingCall *call, void *user_data)
344 {
345         struct property_call_data *property_call = user_data;
346         DBusMessage *reply;
347         DBusMessageIter iter;
348         const char *error;
349
350         reply = dbus_pending_call_steal_reply(call);
351
352         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
353                 error = dbus_message_get_error_name(reply);
354         else
355                 error = NULL;
356
357         dbus_message_iter_init(reply, &iter);
358
359         if (property_call->function)
360                 property_call->function(error, &iter, property_call->user_data);
361
362         dbus_message_unref(reply);
363
364         dbus_pending_call_unref(call);
365 }
366
367 int supplicant_dbus_property_set(const char *path, const char *interface,
368                                 const char *key, const char *signature,
369                                 supplicant_dbus_setup_function setup,
370                                 supplicant_dbus_result_function function,
371                                 void *user_data, gpointer caller)
372 {
373         struct property_call_data *property_call = NULL;
374         DBusMessage *message;
375         DBusMessageIter iter, value;
376         DBusPendingCall *call;
377
378         if (!connection)
379                 return -EINVAL;
380
381         if (!path || !interface)
382                 return -EINVAL;
383
384         if (!key || !signature || !setup)
385                 return -EINVAL;
386
387         property_call = g_try_new0(struct property_call_data, 1);
388         if (!property_call)
389                 return -ENOMEM;
390
391         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
392                                         DBUS_INTERFACE_PROPERTIES, "Set");
393         if (!message) {
394                 g_free(property_call);
395                 return -ENOMEM;
396         }
397
398         dbus_message_set_auto_start(message, FALSE);
399
400         dbus_message_iter_init_append(message, &iter);
401         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface);
402         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
403
404         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
405                                                         signature, &value);
406         setup(&value, user_data);
407         dbus_message_iter_close_container(&iter, &value);
408
409         if (!dbus_connection_send_with_reply(connection, message,
410                                                 &call, TIMEOUT)) {
411                 dbus_message_unref(message);
412                 g_free(property_call);
413                 return -EIO;
414         }
415
416         if (!call) {
417                 dbus_message_unref(message);
418                 g_free(property_call);
419                 return -EIO;
420         }
421
422         property_call->caller = caller;
423         property_call->pending_call = call;
424         property_call->function = function;
425         property_call->user_data = user_data;
426
427         property_calls = g_slist_prepend(property_calls, property_call);
428
429         dbus_pending_call_set_notify(call, property_set_reply,
430                                         property_call, property_call_free);
431
432         dbus_message_unref(message);
433
434         return 0;
435 }
436
437 void supplicant_dbus_method_call_cancel_all(gpointer caller)
438 {
439         while (method_calls) {
440                 struct method_call_data *method_call;
441                 GSList *elem = g_slist_find_custom(method_calls, caller,
442                                                 find_method_call_by_caller);
443                 if (!elem)
444                         break;
445
446                 method_call = elem->data;
447                 method_calls = g_slist_delete_link(method_calls, elem);
448
449                 dbus_pending_call_cancel(method_call->pending_call);
450
451                 if (method_call->function)
452                         method_call->function("net.connman.Error.OperationAborted",
453                                         NULL, method_call->user_data);
454
455                 dbus_pending_call_unref(method_call->pending_call);
456         }
457 }
458
459 static void method_call_reply(DBusPendingCall *call, void *user_data)
460 {
461         struct method_call_data *method_call = user_data;
462         DBusMessage *reply;
463         DBusMessageIter iter;
464         const char *error;
465
466         reply = dbus_pending_call_steal_reply(call);
467
468         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
469                 error = dbus_message_get_error_name(reply);
470         else
471                 error = NULL;
472
473         dbus_message_iter_init(reply, &iter);
474
475         if (method_call && method_call->function)
476                 method_call->function(error, &iter, method_call->user_data);
477
478         dbus_message_unref(reply);
479
480         dbus_pending_call_unref(call);
481 }
482
483 int supplicant_dbus_method_call(const char *path,
484                                 const char *interface, const char *method,
485                                 supplicant_dbus_setup_function setup,
486                                 supplicant_dbus_result_function function,
487                                 void *user_data,
488                                 gpointer caller)
489 {
490         struct method_call_data *method_call = NULL;
491         DBusMessage *message;
492         DBusMessageIter iter;
493         DBusPendingCall *call;
494
495         if (!connection)
496                 return -EINVAL;
497
498         if (!path || !interface || !method)
499                 return -EINVAL;
500 #if defined TIZEN_EXT
501         if (strlen(path) == 0)
502                 return -EINVAL;
503 #endif
504         method_call = g_try_new0(struct method_call_data, 1);
505         if (!method_call)
506                 return -ENOMEM;
507
508         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
509                                                         interface, method);
510         if (!message) {
511                 g_free(method_call);
512                 return -ENOMEM;
513         }
514
515         dbus_message_set_auto_start(message, FALSE);
516
517         dbus_message_iter_init_append(message, &iter);
518         if (setup)
519                 setup(&iter, user_data);
520
521         if (!dbus_connection_send_with_reply(connection, message,
522                                                 &call, TIMEOUT)) {
523                 dbus_message_unref(message);
524                 g_free(method_call);
525                 return -EIO;
526         }
527
528         if (!call) {
529                 dbus_message_unref(message);
530                 g_free(method_call);
531                 return -EIO;
532         }
533
534         method_call->caller = caller;
535         method_call->pending_call = call;
536         method_call->function = function;
537         method_call->user_data = user_data;
538         method_calls = g_slist_prepend(method_calls, method_call);
539
540         dbus_pending_call_set_notify(call, method_call_reply, method_call,
541                                 method_call_free);
542
543         dbus_message_unref(message);
544
545         return 0;
546 }
547
548 void supplicant_dbus_property_append_basic(DBusMessageIter *iter,
549                                         const char *key, int type, void *val)
550 {
551         DBusMessageIter value;
552         const char *signature;
553
554         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
555
556         switch (type) {
557         case DBUS_TYPE_BOOLEAN:
558                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
559                 break;
560         case DBUS_TYPE_STRING:
561                 signature = DBUS_TYPE_STRING_AS_STRING;
562                 break;
563         case DBUS_TYPE_BYTE:
564                 signature = DBUS_TYPE_BYTE_AS_STRING;
565                 break;
566         case DBUS_TYPE_UINT16:
567                 signature = DBUS_TYPE_UINT16_AS_STRING;
568                 break;
569         case DBUS_TYPE_INT16:
570                 signature = DBUS_TYPE_INT16_AS_STRING;
571                 break;
572         case DBUS_TYPE_UINT32:
573                 signature = DBUS_TYPE_UINT32_AS_STRING;
574                 break;
575         case DBUS_TYPE_INT32:
576                 signature = DBUS_TYPE_INT32_AS_STRING;
577                 break;
578         case DBUS_TYPE_OBJECT_PATH:
579                 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
580                 break;
581         default:
582                 signature = DBUS_TYPE_VARIANT_AS_STRING;
583                 break;
584         }
585
586         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
587                                                         signature, &value);
588         dbus_message_iter_append_basic(&value, type, val);
589         dbus_message_iter_close_container(iter, &value);
590 }
591
592 void supplicant_dbus_property_append_fixed_array(DBusMessageIter *iter,
593                                 const char *key, int type, void *val, int len)
594 {
595         DBusMessageIter value, array;
596         const char *variant_sig, *array_sig;
597
598         switch (type) {
599         case DBUS_TYPE_BYTE:
600                 variant_sig = DBUS_TYPE_ARRAY_AS_STRING
601                                         DBUS_TYPE_BYTE_AS_STRING;
602                 array_sig = DBUS_TYPE_BYTE_AS_STRING;
603                 break;
604         default:
605                 return;
606         }
607
608         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
609
610         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
611                                                         variant_sig, &value);
612
613         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
614                                                         array_sig, &array);
615         dbus_message_iter_append_fixed_array(&array, type, val, len);
616         dbus_message_iter_close_container(&value, &array);
617
618         dbus_message_iter_close_container(iter, &value);
619 }
620
621 void supplicant_dbus_property_append_array(DBusMessageIter *iter,
622                                 const char *key, int type,
623                                 supplicant_dbus_array_function function,
624                                 void *user_data)
625 {
626         DBusMessageIter value, array;
627         const char *variant_sig, *array_sig;
628
629         switch (type) {
630         case DBUS_TYPE_STRING:
631         case DBUS_TYPE_BYTE:
632                 variant_sig = DBUS_TYPE_ARRAY_AS_STRING
633                                 DBUS_TYPE_ARRAY_AS_STRING
634                                 DBUS_TYPE_BYTE_AS_STRING;
635                 array_sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
636                 break;
637         default:
638                 return;
639         }
640
641         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
642
643         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
644                                                         variant_sig, &value);
645
646         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
647                                                         array_sig, &array);
648         if (function)
649                 function(&array, user_data);
650
651         dbus_message_iter_close_container(&value, &array);
652
653         dbus_message_iter_close_container(iter, &value);
654 }