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