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