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