Add not supported error and use it
[connman] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <gdbus.h>
28
29 #include "connman.h"
30
31 struct connman_device {
32         struct connman_element element;
33         enum connman_device_type type;
34         enum connman_device_policy policy;
35         gboolean powered;
36         gboolean carrier;
37         gboolean scanning;
38         char *path;
39         char *interface;
40
41         struct connman_device_driver *driver;
42         void *driver_data;
43
44         GSList *networks;
45 };
46
47 static const char *type2description(enum connman_device_type type)
48 {
49         switch (type) {
50         case CONNMAN_DEVICE_TYPE_ETHERNET:
51                 return "Ethernet";
52         case CONNMAN_DEVICE_TYPE_WIFI:
53                 return "Wireless";
54         case CONNMAN_DEVICE_TYPE_WIMAX:
55                 return "WiMAX";
56         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
57                 return "Bluetooth";
58         default:
59                 return NULL;
60         }
61 }
62
63 static const char *type2string(enum connman_device_type type)
64 {
65         switch (type) {
66         case CONNMAN_DEVICE_TYPE_ETHERNET:
67                 return "ethernet";
68         case CONNMAN_DEVICE_TYPE_WIFI:
69                 return "wifi";
70         case CONNMAN_DEVICE_TYPE_WIMAX:
71                 return "wimax";
72         case CONNMAN_DEVICE_TYPE_MODEM:
73                 return "modem";
74         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
75                 return "bluetooth";
76         default:
77                 return NULL;
78         }
79 }
80
81 static const char *policy2string(enum connman_device_policy policy)
82 {
83         switch (policy) {
84         case CONNMAN_DEVICE_POLICY_IGNORE:
85                 return "ignore";
86         case CONNMAN_DEVICE_POLICY_AUTO:
87                 return "auto";
88         case CONNMAN_DEVICE_POLICY_OFF:
89                 return "off";
90         default:
91                 return NULL;
92         }
93 }
94
95 static int set_powered(struct connman_device *device, gboolean powered)
96 {
97         struct connman_device_driver *driver = device->driver;
98         int err;
99
100         DBG("device %p powered %d", device, powered);
101
102         if (!driver)
103                 return -EINVAL;
104
105         if (powered == TRUE) {
106                 if (driver->enable)
107                         err = driver->enable(device);
108                 else
109                         err = -EINVAL;
110         } else {
111                 if (driver->disable)
112                         err = driver->disable(device);
113                 else
114                         err = -EINVAL;
115         }
116
117         return err;
118 }
119
120 static DBusMessage *get_properties(DBusConnection *conn,
121                                         DBusMessage *msg, void *data)
122 {
123         struct connman_device *device = data;
124         DBusMessage *reply;
125         DBusMessageIter array, dict;
126         const char *str;
127
128         DBG("conn %p", conn);
129
130         reply = dbus_message_new_method_return(msg);
131         if (reply == NULL)
132                 return NULL;
133
134         dbus_message_iter_init_append(reply, &array);
135
136         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
137                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
138                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
139                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
140
141         str = type2description(device->type);
142         if (str != NULL && device->interface != NULL) {
143                 char *name = g_strdup_printf("%s (%s)", str, device->interface);
144                 if (name != NULL)
145                         connman_dbus_dict_append_variant(&dict, "Name",
146                                                 DBUS_TYPE_STRING, &name);
147                 g_free(name);
148         }
149
150         str = type2string(device->type);
151         if (str != NULL)
152                 connman_dbus_dict_append_variant(&dict, "Type",
153                                                 DBUS_TYPE_STRING, &str);
154
155         if (device->interface != NULL)
156                 connman_dbus_dict_append_variant(&dict, "Interface",
157                                         DBUS_TYPE_STRING, &device->interface);
158
159         str = policy2string(device->policy);
160         if (str != NULL)
161                 connman_dbus_dict_append_variant(&dict, "Policy",
162                                                 DBUS_TYPE_STRING, &str);
163
164         connman_dbus_dict_append_variant(&dict, "Powered",
165                                         DBUS_TYPE_BOOLEAN, &device->powered);
166
167         if (device->driver && device->driver->scan)
168                 connman_dbus_dict_append_variant(&dict, "Scanning",
169                                         DBUS_TYPE_BOOLEAN, &device->scanning);
170
171         dbus_message_iter_close_container(&array, &dict);
172
173         return reply;
174 }
175
176 static DBusMessage *set_property(DBusConnection *conn,
177                                         DBusMessage *msg, void *data)
178 {
179         struct connman_device *device = data;
180         DBusMessageIter iter, value;
181         const char *name;
182
183         DBG("conn %p", conn);
184
185         if (dbus_message_iter_init(msg, &iter) == FALSE)
186                 return __connman_error_invalid_arguments(msg);
187
188         dbus_message_iter_get_basic(&iter, &name);
189         dbus_message_iter_next(&iter);
190         dbus_message_iter_recurse(&iter, &value);
191
192         if (__connman_security_check_privileges(msg) < 0)
193                 return __connman_error_permission_denied(msg);
194
195         if (g_str_equal(name, "Powered") == TRUE) {
196                 gboolean powered;
197                 int err;
198
199                 dbus_message_iter_get_basic(&value, &powered);
200
201                 if (device->powered == powered)
202                         return __connman_error_invalid_arguments(msg);
203
204                 err = set_powered(device, powered);
205                 if (err < 0 && err != -EINPROGRESS)
206                         return __connman_error_failed(msg);
207         }
208
209         __connman_element_store(&device->element);
210
211         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
212 }
213
214 static DBusMessage *create_network(DBusConnection *conn,
215                                         DBusMessage *msg, void *data)
216 {
217         DBG("conn %p", conn);
218
219         if (__connman_security_check_privileges(msg) < 0)
220                 return __connman_error_permission_denied(msg);
221
222         return __connman_error_invalid_arguments(msg);
223 }
224
225 static DBusMessage *remove_network(DBusConnection *conn,
226                                         DBusMessage *msg, void *data)
227 {
228         DBG("conn %p", conn);
229
230         if (__connman_security_check_privileges(msg) < 0)
231                 return __connman_error_permission_denied(msg);
232
233         return __connman_error_invalid_arguments(msg);
234 }
235
236 static DBusMessage *propose_scan(DBusConnection *conn,
237                                         DBusMessage *msg, void *data)
238 {
239         DBG("conn %p", conn);
240
241         return __connman_error_not_supported(msg);
242 }
243
244 static GDBusMethodTable device_methods[] = {
245         { "GetProperties", "",      "a{sv}", get_properties },
246         { "SetProperty",   "sv",    "",      set_property   },
247         { "CreateNetwork", "a{sv}", "o",     create_network },
248         { "RemoveNetwork", "o",     "",      remove_network },
249         { "ProposeScan",   "",      "",      propose_scan   },
250         { },
251 };
252
253 static GDBusSignalTable device_signals[] = {
254         { "PropertyChanged", "sv" },
255         { },
256 };
257
258 static DBusConnection *connection;
259
260 static int register_interface(struct connman_element *element)
261 {
262         struct connman_device *device = element->device;
263
264         g_dbus_unregister_interface(connection, element->path,
265                                                 CONNMAN_DEVICE_INTERFACE);
266
267         if (g_dbus_register_interface(connection, element->path,
268                                         CONNMAN_DEVICE_INTERFACE,
269                                         device_methods, device_signals,
270                                         NULL, device, NULL) == FALSE) {
271                 connman_error("Failed to register %s device", element->path);
272                 return -EIO;
273         }
274
275         return 0;
276 }
277
278 static void unregister_interface(struct connman_element *element)
279 {
280         g_dbus_unregister_interface(connection, element->path,
281                                                 CONNMAN_DEVICE_INTERFACE);
282 }
283
284 static GSList *driver_list = NULL;
285
286 static gint compare_priority(gconstpointer a, gconstpointer b)
287 {
288         const struct connman_device_driver *driver1 = a;
289         const struct connman_device_driver *driver2 = b;
290
291         return driver2->priority - driver1->priority;
292 }
293
294 /**
295  * connman_device_driver_register:
296  * @driver: device driver definition
297  *
298  * Register a new device driver
299  *
300  * Returns: %0 on success
301  */
302 int connman_device_driver_register(struct connman_device_driver *driver)
303 {
304         DBG("driver %p name %s", driver, driver->name);
305
306         driver_list = g_slist_insert_sorted(driver_list, driver,
307                                                         compare_priority);
308
309         //__connman_driver_rescan(&device_driver);
310
311         return 0;
312 }
313
314 /**
315  * connman_device_driver_unregister:
316  * @driver: device driver definition
317  *
318  * Remove a previously registered device driver
319  */
320 void connman_device_driver_unregister(struct connman_device_driver *driver)
321 {
322         DBG("driver %p name %s", driver, driver->name);
323
324         driver_list = g_slist_remove(driver_list, driver);
325 }
326
327 static void device_destruct(struct connman_element *element)
328 {
329         struct connman_device *device = element->device;
330
331         DBG("element %p name %s", element, element->name);
332
333         g_free(device->interface);
334 }
335
336 /**
337  * connman_device_create:
338  * @node: device node name (for example an address)
339  * @type: device type
340  *
341  * Allocate a new device of given #type and assign the #node name to it.
342  *
343  * Returns: a newly-allocated #connman_device structure
344  */
345 struct connman_device *connman_device_create(const char *node,
346                                                 enum connman_device_type type)
347 {
348         struct connman_device *device;
349
350         DBG("node %s type %d", node, type);
351
352         device = g_try_new0(struct connman_device, 1);
353         if (device == NULL)
354                 return NULL;
355
356         DBG("device %p", device);
357
358         device->element.name = g_strdup(node);
359         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
360         device->element.index = -1;
361
362         device->element.device = device;
363         device->element.destruct = device_destruct;
364
365         device->type = type;
366         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
367
368         return device;
369 }
370
371 /**
372  * connman_device_ref:
373  * @device: device structure
374  *
375  * Increase reference counter of device
376  */
377 struct connman_device *connman_device_ref(struct connman_device *device)
378 {
379         if (connman_element_ref(&device->element) == NULL)
380                 return NULL;
381
382         return device;
383 }
384
385 /**
386  * connman_device_unref:
387  * @device: device structure
388  *
389  * Decrease reference counter of device
390  */
391 void connman_device_unref(struct connman_device *device)
392 {
393         connman_element_unref(&device->element);
394 }
395
396 /**
397  * connman_device_set_path:
398  * @device: device structure
399  * @path: path name
400  *
401  * Set path name of device
402  */
403 void connman_device_set_path(struct connman_device *device, const char *path)
404 {
405         g_free(device->element.devpath);
406         device->element.devpath = g_strdup(path);
407
408         g_free(device->path);
409         device->path = g_strdup(path);
410 }
411
412 /**
413  * connman_device_get_path:
414  * @device: device structure
415  *
416  * Get path name of device
417  */
418 const char *connman_device_get_path(struct connman_device *device)
419 {
420         return device->path;
421 }
422
423 /**
424  * connman_device_set_index:
425  * @device: device structure
426  * @index: index number
427  *
428  * Set index number of device
429  */
430 void connman_device_set_index(struct connman_device *device, int index)
431 {
432         device->element.index = index;
433 }
434
435 /**
436  * connman_device_get_index:
437  * @device: device structure
438  *
439  * Get index number of device
440  */
441 int connman_device_get_index(struct connman_device *device)
442 {
443         return device->element.index;
444 }
445
446 /**
447  * connman_device_set_interface:
448  * @device: device structure
449  * @interface: interface name
450  *
451  * Set interface name of device
452  */
453 void connman_device_set_interface(struct connman_device *device,
454                                                         const char *interface)
455 {
456         g_free(device->element.devname);
457         device->element.devname = g_strdup(interface);
458
459         g_free(device->interface);
460         device->interface = g_strdup(interface);
461 }
462
463 /**
464  * connman_device_get_interface:
465  * @device: device structure
466  *
467  * Get interface name of device
468  */
469 const char *connman_device_get_interface(struct connman_device *device)
470 {
471         return device->interface;
472 }
473
474 /**
475  * connman_device_set_powered:
476  * @device: device structure
477  * @powered: powered state
478  *
479  * Change power state of device
480  */
481 int connman_device_set_powered(struct connman_device *device,
482                                                         gboolean powered)
483 {
484         DBusMessage *signal;
485         DBusMessageIter entry, value;
486         const char *key = "Powered";
487
488         DBG("driver %p powered %d", device, powered);
489
490         if (device->powered == powered)
491                 return -EALREADY;
492
493         device->powered = powered;
494
495         signal = dbus_message_new_signal(device->element.path,
496                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
497         if (signal == NULL)
498                 return 0;
499
500         dbus_message_iter_init_append(signal, &entry);
501
502         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
503
504         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
505                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
506         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
507         dbus_message_iter_close_container(&entry, &value);
508
509         g_dbus_send_message(connection, signal);
510
511         return 0;
512 }
513
514 /**
515  * connman_device_set_carrier:
516  * @device: device structure
517  * @carrier: carrier state
518  *
519  * Change carrier state of device (only for device without scanning)
520  */
521 int connman_device_set_carrier(struct connman_device *device,
522                                                         gboolean carrier)
523 {
524         DBG("driver %p carrier %d", device, carrier);
525
526         if (!device->driver)
527                 return -EINVAL;
528
529         if (device->driver->scan)
530                 return -EINVAL;
531
532         if (device->carrier == carrier)
533                 return -EALREADY;
534
535         device->carrier = carrier;
536
537         if (carrier == TRUE) {
538                 struct connman_element *element;
539
540                 element = connman_element_create(NULL);
541                 if (element != NULL) {
542                         element->type    = CONNMAN_ELEMENT_TYPE_DEVICE;
543                         element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK;
544                         element->index   = device->element.index;
545
546                         if (connman_element_register(element,
547                                                         &device->element) < 0)
548                                 connman_element_unref(element);
549                 }
550         } else
551                 connman_element_unregister_children(&device->element);
552
553         return 0;
554 }
555
556 /**
557  * connman_device_set_scanning:
558  * @device: device structure
559  * @scanning: scanning state
560  *
561  * Change scanning state of device
562  */
563 int connman_device_set_scanning(struct connman_device *device,
564                                                         gboolean scanning)
565 {
566         DBusMessage *signal;
567         DBusMessageIter entry, value;
568         const char *key = "Scanning";
569
570         DBG("driver %p scanning %d", device, scanning);
571
572         if (!device->driver)
573                 return -EINVAL;
574
575         if (!device->driver->scan)
576                 return -EINVAL;
577
578         if (device->scanning == scanning)
579                 return -EALREADY;
580
581         device->scanning = scanning;
582
583         signal = dbus_message_new_signal(device->element.path,
584                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
585         if (signal == NULL)
586                 return 0;
587
588         dbus_message_iter_init_append(signal, &entry);
589
590         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
591
592         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
593                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
594         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
595         dbus_message_iter_close_container(&entry, &value);
596
597         g_dbus_send_message(connection, signal);
598
599         return 0;
600 }
601
602 /**
603  * connman_device_register:
604  * @device: device structure
605  *
606  * Register device with the system
607  */
608 int connman_device_register(struct connman_device *device)
609 {
610         return connman_element_register(&device->element, NULL);
611 }
612
613 /**
614  * connman_device_unregister:
615  * @device: device structure
616  *
617  * Unregister device with the system
618  */
619 void connman_device_unregister(struct connman_device *device)
620 {
621         connman_element_unregister(&device->element);
622 }
623
624 /**
625  * connman_device_get_data:
626  * @device: device structure
627  *
628  * Get private device data pointer
629  */
630 void *connman_device_get_data(struct connman_device *device)
631 {
632         return device->driver_data;
633 }
634
635 /**
636  * connman_device_set_data:
637  * @device: device structure
638  * @data: data pointer
639  *
640  * Set private device data pointer
641  */
642 void connman_device_set_data(struct connman_device *device, void *data)
643 {
644         device->driver_data = data;
645 }
646
647 static void device_enable(struct connman_device *device)
648 {
649         DBG("device %p", device);
650
651         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
652                 return;
653
654         if (device->powered == TRUE)
655                 return;
656
657         if (device->driver->enable)
658                 device->driver->enable(device);
659 }
660
661 static void device_disable(struct connman_device *device)
662 {
663         DBG("device %p", device);
664
665         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
666                 return;
667
668         if (device->powered == FALSE)
669                 return;
670
671         if (device->driver->disable)
672                 device->driver->disable(device);
673 }
674
675 static gboolean match_driver(struct connman_device *device,
676                                         struct connman_device_driver *driver)
677 {
678         if (device->type == driver->type ||
679                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
680                 return TRUE;
681
682         return FALSE;
683 }
684
685 static int device_probe(struct connman_element *element)
686 {
687         struct connman_device *device = element->device;
688         GSList *list;
689         int err;
690
691         DBG("element %p name %s", element, element->name);
692
693         if (device == NULL)
694                 return -ENODEV;
695
696         err = register_interface(element);
697         if (err < 0)
698                 return err;
699
700         for (list = driver_list; list; list = list->next) {
701                 struct connman_device_driver *driver = list->data;
702
703                 if (match_driver(device, driver) == FALSE)
704                         continue;
705
706                 DBG("driver %p name %s", driver, driver->name);
707
708                 if (driver->probe(device) == 0) {
709                         device->driver = driver;
710                         device_enable(device);
711                         break;
712                 }
713         }
714
715         return 0;
716 }
717
718 static void device_remove(struct connman_element *element)
719 {
720         struct connman_device *device = element->device;
721
722         DBG("element %p name %s", element, element->name);
723
724         if (device == NULL)
725                 return;
726
727         unregister_interface(element);
728
729         if (device->driver) {
730                 device_disable(device);
731
732                 if (device->driver->remove)
733                         device->driver->remove(device);
734         }
735 }
736
737 static struct connman_driver device_driver = {
738         .name           = "device",
739         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
740         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
741         .probe          = device_probe,
742         .remove         = device_remove,
743 };
744
745 int __connman_device_init(void)
746 {
747         DBG("");
748
749         connection = connman_dbus_get_connection();
750
751         return connman_driver_register(&device_driver);
752 }
753
754 void __connman_device_cleanup(void)
755 {
756         DBG("");
757
758         connman_driver_unregister(&device_driver);
759
760         dbus_connection_unref(connection);
761 }