Add support for more device and network properties
[connman] / src / network.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <string.h>
27
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 struct connman_network {
33         struct connman_element element;
34         enum connman_network_type type;
35         enum connman_network_protocol protocol;
36         connman_bool_t connected;
37         connman_uint8_t strength;
38         char *identifier;
39         char *name;
40         char *node;
41
42         struct connman_network_driver *driver;
43         void *driver_data;
44
45         struct connman_device *device;
46
47         struct {
48                 void *ssid;
49                 int ssid_len;
50                 char *mode;
51                 char *security;
52                 char *passphrase;
53         } wifi;
54 };
55
56 static DBusMessage *get_properties(DBusConnection *conn,
57                                         DBusMessage *msg, void *data)
58 {
59         struct connman_network *network = data;
60         DBusMessage *reply;
61         DBusMessageIter array, dict;
62
63         DBG("conn %p", conn);
64
65         reply = dbus_message_new_method_return(msg);
66         if (reply == NULL)
67                 return NULL;
68
69         dbus_message_iter_init_append(reply, &array);
70
71         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
72                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
73                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
74                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
75
76         if (network->device) {
77                 const char *path = connman_device_get_path(network->device);
78                 if (path != NULL)
79                         connman_dbus_dict_append_variant(&dict, "Device",
80                                                 DBUS_TYPE_OBJECT_PATH, &path);
81         }
82
83         if (network->name != NULL)
84                 connman_dbus_dict_append_variant(&dict, "Name",
85                                         DBUS_TYPE_STRING, &network->name);
86
87         connman_dbus_dict_append_variant(&dict, "Connected",
88                                 DBUS_TYPE_BOOLEAN, &network->connected);
89
90         if (network->strength > 0)
91                 connman_dbus_dict_append_variant(&dict, "Strength",
92                                         DBUS_TYPE_BYTE, &network->strength);
93
94         if (network->wifi.ssid != NULL && network->wifi.ssid_len > 0)
95                 connman_dbus_dict_append_array(&dict, "WiFi.SSID",
96                                 DBUS_TYPE_BYTE, &network->wifi.ssid,
97                                                 network->wifi.ssid_len);
98
99         if (network->wifi.mode != NULL)
100                 connman_dbus_dict_append_variant(&dict, "WiFi.Mode",
101                                 DBUS_TYPE_STRING, &network->wifi.mode);
102
103         if (network->wifi.security != NULL)
104                 connman_dbus_dict_append_variant(&dict, "WiFi.Security",
105                                 DBUS_TYPE_STRING, &network->wifi.security);
106
107         if (network->wifi.passphrase != NULL)
108                 connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase",
109                                 DBUS_TYPE_STRING, &network->wifi.passphrase);
110
111         dbus_message_iter_close_container(&array, &dict);
112
113         return reply;
114 }
115
116 static DBusMessage *set_property(DBusConnection *conn,
117                                         DBusMessage *msg, void *data)
118 {
119         DBusMessageIter iter, value;
120         const char *name;
121
122         DBG("conn %p", conn);
123
124         if (dbus_message_iter_init(msg, &iter) == FALSE)
125                 return __connman_error_invalid_arguments(msg);
126
127         dbus_message_iter_get_basic(&iter, &name);
128         dbus_message_iter_next(&iter);
129         dbus_message_iter_recurse(&iter, &value);
130
131         if (__connman_security_check_privileges(msg) < 0)
132                 return __connman_error_permission_denied(msg);
133
134         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
135 }
136
137 static DBusMessage *do_connect(DBusConnection *conn,
138                                         DBusMessage *msg, void *data)
139 {
140         struct connman_network *network = data;
141         int err;
142
143         DBG("conn %p", conn);
144
145         if (network->driver && network->driver->connect) {
146                 err = network->driver->connect(network);
147                 if (err < 0 && err != -EINPROGRESS)
148                         return __connman_error_failed(msg);
149         }
150
151         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
152 }
153
154 static DBusMessage *do_disconnect(DBusConnection *conn,
155                                         DBusMessage *msg, void *data)
156 {
157         struct connman_network *network = data;
158         int err;
159
160         DBG("conn %p", conn);
161
162         if (network->driver && network->driver->disconnect) {
163                 err = network->driver->disconnect(network);
164                 if (err < 0 && err != -EINPROGRESS)
165                         return __connman_error_failed(msg);
166         }
167
168         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
169 }
170
171 static GDBusMethodTable network_methods[] = {
172         { "GetProperties", "",   "a{sv}", get_properties },
173         { "SetProperty",   "sv", "",      set_property   },
174         { "Connect",       "",   "",      do_connect     },
175         { "Disconnect",    "",   "",      do_disconnect  },
176         { },
177 };
178
179 static GDBusSignalTable network_signals[] = {
180         { "PropertyChanged", "sv" },
181         { },
182 };
183
184 static DBusConnection *connection;
185
186 static void emit_networks_signal(void)
187 {
188 }
189
190 static int register_interface(struct connman_element *element)
191 {
192         struct connman_network *network = element->network;
193
194         DBG("element %p name %s", element, element->name);
195
196         if (g_dbus_register_interface(connection, element->path,
197                                         CONNMAN_NETWORK_INTERFACE,
198                                         network_methods, network_signals,
199                                         NULL, network, NULL) == FALSE) {
200                 connman_error("Failed to register %s network", element->path);
201                 return -EIO;
202         }
203
204         emit_networks_signal();
205
206         return 0;
207 }
208
209 static void unregister_interface(struct connman_element *element)
210 {
211         DBG("element %p name %s", element, element->name);
212
213         emit_networks_signal();
214
215         g_dbus_unregister_interface(connection, element->path,
216                                                 CONNMAN_NETWORK_INTERFACE);
217 }
218
219 static GSList *driver_list = NULL;
220
221 static gint compare_priority(gconstpointer a, gconstpointer b)
222 {
223         const struct connman_network_driver *driver1 = a;
224         const struct connman_network_driver *driver2 = b;
225
226         return driver2->priority - driver1->priority;
227 }
228
229 /**
230  * connman_network_driver_register:
231  * @driver: network driver definition
232  *
233  * Register a new network driver
234  *
235  * Returns: %0 on success
236  */
237 int connman_network_driver_register(struct connman_network_driver *driver)
238 {
239         DBG("driver %p name %s", driver, driver->name);
240
241         driver_list = g_slist_insert_sorted(driver_list, driver,
242                                                         compare_priority);
243
244         return 0;
245 }
246
247 /**
248  * connman_network_driver_unregister:
249  * @driver: network driver definition
250  *
251  * Remove a previously registered network driver
252  */
253 void connman_network_driver_unregister(struct connman_network_driver *driver)
254 {
255         DBG("driver %p name %s", driver, driver->name);
256
257         driver_list = g_slist_remove(driver_list, driver);
258 }
259
260 static void network_destruct(struct connman_element *element)
261 {
262         struct connman_network *network = element->network;
263
264         DBG("element %p name %s", element, element->name);
265
266         g_free(network->wifi.ssid);
267         g_free(network->wifi.mode);
268         g_free(network->wifi.security);
269         g_free(network->wifi.passphrase);
270
271         g_free(network->node);
272         g_free(network->name);
273         g_free(network->identifier);
274 }
275
276 /**
277  * connman_network_create:
278  * @identifier: network identifier (for example an unqiue name)
279  *
280  * Allocate a new network and assign the #identifier to it.
281  *
282  * Returns: a newly-allocated #connman_network structure
283  */
284 struct connman_network *connman_network_create(const char *identifier,
285                                                 enum connman_network_type type)
286 {
287         struct connman_network *network;
288
289         DBG("identifier %s type %d", identifier, type);
290
291         network = g_try_new0(struct connman_network, 1);
292         if (network == NULL)
293                 return NULL;
294
295         DBG("network %p", network);
296
297         network->element.refcount = 1;
298
299         network->element.name = g_strdup(identifier);
300         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
301         network->element.index = -1;
302
303         switch (type) {
304         case CONNMAN_NETWORK_TYPE_UNKNOWN:
305         case CONNMAN_NETWORK_TYPE_VENDOR:
306                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
307                 break;
308         case CONNMAN_NETWORK_TYPE_WIFI:
309                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_WIFI;
310                 break;
311         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
312         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
313                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH;
314                 break;
315         case CONNMAN_NETWORK_TYPE_HSO:
316                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_CELLULAR;
317                 break;
318         }
319
320         network->element.network = network;
321         network->element.destruct = network_destruct;
322
323         network->type = type;
324         network->identifier = g_strdup(identifier);
325
326         return network;
327 }
328
329 /**
330  * connman_network_ref:
331  * @network: network structure
332  *
333  * Increase reference counter of  network
334  */
335 struct connman_network *connman_network_ref(struct connman_network *network)
336 {
337         if (connman_element_ref(&network->element) == NULL)
338                 return NULL;
339
340         return network;
341 }
342
343 /**
344  * connman_network_unref:
345  * @network: network structure
346  *
347  * Decrease reference counter of network
348  */
349 void connman_network_unref(struct connman_network *network)
350 {
351         connman_element_unref(&network->element);
352 }
353
354 /**
355  * connman_network_get_identifier:
356  * @network: network structure
357  *
358  * Get identifier of network
359  */
360 const char *connman_network_get_identifier(struct connman_network *network)
361 {
362         return network->identifier;
363 }
364
365 /**
366  * connman_network_get_path:
367  * @network: network structure
368  *
369  * Get path name of network
370  */
371 const char *connman_network_get_path(struct connman_network *network)
372 {
373         return network->element.path;
374 }
375
376 /**
377  * connman_network_set_index:
378  * @network: network structure
379  * @index: index number
380  *
381  * Set index number of network
382  */
383 void connman_network_set_index(struct connman_network *network, int index)
384 {
385         network->element.index = index;
386 }
387
388 /**
389  * connman_network_get_index:
390  * @network: network structure
391  *
392  * Get index number of network
393  */
394 int connman_network_get_index(struct connman_network *network)
395 {
396         return network->element.index;
397 }
398
399 /**
400  * connman_network_set_protocol:
401  * @network: network structure
402  * @protocol: network protocol
403  *
404  * Change protocol of network
405  */
406 void connman_network_set_protocol(struct connman_network *network,
407                                         enum connman_network_protocol protocol)
408 {
409         network->protocol = protocol;
410 }
411
412 /**
413  * connman_network_set_connected:
414  * @network: network structure
415  * @connected: connected state
416  *
417  * Change connected state of network
418  */
419 int connman_network_set_connected(struct connman_network *network,
420                                                 connman_bool_t connected)
421 {
422         DBG("network %p connected %d", network, connected);
423
424         if (network->connected == connected)
425                 return -EALREADY;
426
427         network->connected = connected;
428
429         if (connected == TRUE) {
430                 struct connman_element *element;
431                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
432
433                 switch (network->protocol) {
434                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
435                         return 0;
436                 case CONNMAN_NETWORK_PROTOCOL_IP:
437                         type = CONNMAN_ELEMENT_TYPE_DHCP;
438                         break;
439                 case CONNMAN_NETWORK_PROTOCOL_PPP:
440                         type = CONNMAN_ELEMENT_TYPE_PPP;
441                         break;
442                 }
443
444                 element = connman_element_create(NULL);
445                 if (element != NULL) {
446                         element->type    = type;
447                         element->subtype = network->element.subtype;
448                         element->index   = network->element.index;
449
450                         if (connman_element_register(element,
451                                                         &network->element) < 0)
452                                 connman_element_unref(element);
453                 }
454         } else
455                 connman_element_unregister_children(&network->element);
456
457         return 0;
458 }
459
460 /**
461  * connman_network_set_string:
462  * @network: network structure
463  * @key: unique identifier
464  * @value: string value
465  *
466  * Set string value for specific key
467  */
468 int connman_network_set_string(struct connman_network *network,
469                                         const char *key, const char *value)
470 {
471         DBG("network %p key %s value %s", network, key, value);
472
473         if (g_str_equal(key, "Name") == TRUE) {
474                 g_free(network->name);
475                 network->name = g_strdup(value);
476         } else if (g_str_equal(key, "Node") == TRUE) {
477                 g_free(network->node);
478                 network->node = g_strdup(value);
479         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
480                 g_free(network->wifi.mode);
481                 network->wifi.mode = g_strdup(value);
482         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
483                 g_free(network->wifi.security);
484                 network->wifi.security = g_strdup(value);
485         }
486
487         return 0;
488 }
489
490 /**
491  * connman_network_get_string:
492  * @network: network structure
493  * @key: unique identifier
494  *
495  * Get string value for specific key
496  */
497 const char *connman_network_get_string(struct connman_network *network,
498                                                         const char *key)
499 {
500         DBG("network %p key %s", network);
501
502         if (g_str_equal(key, "Name") == TRUE)
503                 return network->name;
504         else if (g_str_equal(key, "Node") == TRUE)
505                 return network->node;
506         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
507                 return network->wifi.mode;
508         else if (g_str_equal(key, "WiFi.Security") == TRUE)
509                 return network->wifi.security;
510
511         return NULL;
512 }
513
514 /**
515  * connman_network_set_uint8:
516  * @network: network structure
517  * @key: unique identifier
518  * @value: integer value
519  *
520  * Set integer value for specific key
521  */
522 int connman_network_set_uint8(struct connman_network *network,
523                                         const char *key, connman_uint8_t value)
524 {
525         DBG("network %p key %s value %d", network, key, value);
526
527         if (g_str_equal(key, "Strength") == TRUE)
528                 network->strength = value;
529
530         return 0;
531 }
532
533 /**
534  * connman_network_set_blob:
535  * @network: network structure
536  * @key: unique identifier
537  * @data: blob data
538  * @size: blob size
539  *
540  * Set binary blob value for specific key
541  */
542 int connman_network_set_blob(struct connman_network *network,
543                         const char *key, const void *data, unsigned int size)
544 {
545         DBG("network %p key %s size %d", network, key, size);
546
547         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
548                 g_free(network->wifi.ssid);
549                 network->wifi.ssid = g_try_malloc(size);
550                 if (network->wifi.ssid != NULL) {
551                         memcpy(network->wifi.ssid, data, size);
552                         network->wifi.ssid_len = size;
553                 } else
554                         network->wifi.ssid_len = 0;
555         }
556
557         return 0;
558 }
559
560 void __connman_network_set_device(struct connman_network *network,
561                                         struct connman_device *device)
562 {
563         network->device = device;
564 }
565
566 /**
567  * connman_network_get_device:
568  * @network: network structure
569  *
570  * Get parent device of network
571  */
572 struct connman_device *connman_network_get_device(struct connman_network *network)
573 {
574         return network->device;
575 }
576
577 /**
578  * connman_network_get_data:
579  * @network: network structure
580  *
581  * Get private network data pointer
582  */
583 void *connman_network_get_data(struct connman_network *network)
584 {
585         return network->driver_data;
586 }
587
588 /**
589  * connman_network_set_data:
590  * @network: network structure
591  * @data: data pointer
592  *
593  * Set private network data pointer
594  */
595 void connman_network_set_data(struct connman_network *network, void *data)
596 {
597         network->driver_data = data;
598 }
599
600 static gboolean match_driver(struct connman_network *network,
601                                         struct connman_network_driver *driver)
602 {
603         if (network->type == driver->type ||
604                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
605                 return TRUE;
606
607         return FALSE;
608 }
609
610 static int network_probe(struct connman_element *element)
611 {
612         struct connman_network *network = element->network;
613         GSList *list;
614         int err;
615
616         DBG("element %p name %s", element, element->name);
617
618         if (network == NULL)
619                 return -ENODEV;
620
621         for (list = driver_list; list; list = list->next) {
622                 struct connman_network_driver *driver = list->data;
623
624                 if (match_driver(network, driver) == FALSE)
625                         continue;
626
627                 DBG("driver %p name %s", driver, driver->name);
628
629                 if (driver->probe(network) == 0) {
630                         network->driver = driver;
631                         break;
632                 }
633         }
634
635         if (network->driver == NULL)
636                 return -ENODEV;
637
638         err = register_interface(element);
639         if (err < 0) {
640                 if (network->driver->remove)
641                         network->driver->remove(network);
642                 return err;
643         }
644
645         return 0;
646 }
647
648 static void network_remove(struct connman_element *element)
649 {
650         struct connman_network *network = element->network;
651
652         DBG("element %p name %s", element, element->name);
653
654         if (network == NULL)
655                 return;
656
657         if (network->driver == NULL)
658                 return;
659
660         unregister_interface(element);
661
662         if (network->driver->remove)
663                 network->driver->remove(network);
664 }
665
666 static struct connman_driver network_driver = {
667         .name           = "network",
668         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
669         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
670         .probe          = network_probe,
671         .remove         = network_remove,
672 };
673
674 static int network_load(struct connman_network *network)
675 {
676         DBG("network %p", network);
677
678         return 0;
679 }
680
681 static int network_save(struct connman_network *network)
682 {
683         DBG("network %p", network);
684
685         return 0;
686 }
687
688 static struct connman_storage network_storage = {
689         .name           = "network",
690         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
691         .network_load   = network_load,
692         .network_save   = network_save,
693 };
694
695 int __connman_network_init(void)
696 {
697         DBG("");
698
699         connection = connman_dbus_get_connection();
700
701         if (connman_storage_register(&network_storage) < 0)
702                 connman_error("Failed to register network storage");
703
704         return connman_driver_register(&network_driver);
705 }
706
707 void __connman_network_cleanup(void)
708 {
709         DBG("");
710
711         connman_driver_unregister(&network_driver);
712
713         connman_storage_unregister(&network_storage);
714
715         dbus_connection_unref(connection);
716 }