Add option for network protocol
[connman] / src / network.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 <gdbus.h>
27
28 #include "connman.h"
29
30 struct connman_network {
31         struct connman_element element;
32         enum connman_network_type type;
33         enum connman_network_protocol protocol;
34         gboolean connected;
35         char *identifier;
36         char *path;
37
38         struct connman_network_driver *driver;
39         void *driver_data;
40
41         struct connman_device *device;
42 };
43
44 static DBusMessage *get_properties(DBusConnection *conn,
45                                         DBusMessage *msg, void *data)
46 {
47         struct connman_network *network = data;
48         DBusMessage *reply;
49         DBusMessageIter array, dict;
50
51         DBG("conn %p", conn);
52
53         reply = dbus_message_new_method_return(msg);
54         if (reply == NULL)
55                 return NULL;
56
57         dbus_message_iter_init_append(reply, &array);
58
59         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
60                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
61                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
62                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
63
64         if (network->identifier != NULL)
65                 connman_dbus_dict_append_variant(&dict, "Name",
66                                 DBUS_TYPE_STRING, &network->identifier);
67
68         connman_dbus_dict_append_variant(&dict, "Connected",
69                                 DBUS_TYPE_BOOLEAN, &network->connected);
70
71         dbus_message_iter_close_container(&array, &dict);
72
73         return reply;
74 }
75
76 static DBusMessage *set_property(DBusConnection *conn,
77                                         DBusMessage *msg, void *data)
78 {
79         DBusMessageIter iter, value;
80         const char *name;
81
82         DBG("conn %p", conn);
83
84         if (dbus_message_iter_init(msg, &iter) == FALSE)
85                 return __connman_error_invalid_arguments(msg);
86
87         dbus_message_iter_get_basic(&iter, &name);
88         dbus_message_iter_next(&iter);
89         dbus_message_iter_recurse(&iter, &value);
90
91         if (__connman_security_check_privileges(msg) < 0)
92                 return __connman_error_permission_denied(msg);
93
94         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
95 }
96
97 static DBusMessage *do_connect(DBusConnection *conn,
98                                         DBusMessage *msg, void *data)
99 {
100         struct connman_network *network = data;
101         int err;
102
103         DBG("conn %p", conn);
104
105         if (network->driver && network->driver->connect) {
106                 err = network->driver->connect(network);
107                 if (err < 0 && err != -EINPROGRESS)
108                         return __connman_error_failed(msg);
109         }
110
111         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
112 }
113
114 static DBusMessage *do_disconnect(DBusConnection *conn,
115                                         DBusMessage *msg, void *data)
116 {
117         struct connman_network *network = data;
118         int err;
119
120         DBG("conn %p", conn);
121
122         if (network->driver && network->driver->disconnect) {
123                 err = network->driver->disconnect(network);
124                 if (err < 0 && err != -EINPROGRESS)
125                         return __connman_error_failed(msg);
126         }
127
128         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
129 }
130
131 static GDBusMethodTable network_methods[] = {
132         { "GetProperties", "",   "a{sv}", get_properties },
133         { "SetProperty",   "sv", "",      set_property   },
134         { "Connect",       "",   "",      do_connect     },
135         { "Disconnect",    "",   "",      do_disconnect  },
136         { },
137 };
138
139 static GDBusSignalTable network_signals[] = {
140         { "PropertyChanged", "sv" },
141         { },
142 };
143
144 static DBusConnection *connection;
145
146 static void emit_networks_signal(void)
147 {
148 }
149
150 static int register_interface(struct connman_element *element)
151 {
152         struct connman_network *network = element->network;
153
154         DBG("element %p name %s", element, element->name);
155
156         g_dbus_unregister_interface(connection, element->path,
157                                                 CONNMAN_NETWORK_INTERFACE);
158
159         if (g_dbus_register_interface(connection, element->path,
160                                         CONNMAN_NETWORK_INTERFACE,
161                                         network_methods, network_signals,
162                                         NULL, network, NULL) == FALSE) {
163                 connman_error("Failed to register %s network", element->path);
164                 return -EIO;
165         }
166
167         emit_networks_signal();
168
169         return 0;
170 }
171
172 static void unregister_interface(struct connman_element *element)
173 {
174         DBG("element %p name %s", element, element->name);
175
176         emit_networks_signal();
177
178         g_dbus_unregister_interface(connection, element->path,
179                                                 CONNMAN_NETWORK_INTERFACE);
180 }
181
182 static GSList *driver_list = NULL;
183
184 static gint compare_priority(gconstpointer a, gconstpointer b)
185 {
186         const struct connman_network_driver *driver1 = a;
187         const struct connman_network_driver *driver2 = b;
188
189         return driver2->priority - driver1->priority;
190 }
191
192 /**
193  * connman_network_driver_register:
194  * @driver: network driver definition
195  *
196  * Register a new network driver
197  *
198  * Returns: %0 on success
199  */
200 int connman_network_driver_register(struct connman_network_driver *driver)
201 {
202         DBG("driver %p name %s", driver, driver->name);
203
204         driver_list = g_slist_insert_sorted(driver_list, driver,
205                                                         compare_priority);
206
207         return 0;
208 }
209
210 /**
211  * connman_network_driver_unregister:
212  * @driver: network driver definition
213  *
214  * Remove a previously registered network driver
215  */
216 void connman_network_driver_unregister(struct connman_network_driver *driver)
217 {
218         DBG("driver %p name %s", driver, driver->name);
219
220         driver_list = g_slist_remove(driver_list, driver);
221 }
222
223 static void network_destruct(struct connman_element *element)
224 {
225         struct connman_network *network = element->network;
226
227         DBG("element %p name %s", element, element->name);
228
229         g_free(network->path);
230         g_free(network->identifier);
231 }
232
233 /**
234  * connman_network_create:
235  * @identifier: network identifier (for example an unqiue name)
236  *
237  * Allocate a new network and assign the #identifier to it.
238  *
239  * Returns: a newly-allocated #connman_network structure
240  */
241 struct connman_network *connman_network_create(const char *identifier,
242                                                 enum connman_network_type type)
243 {
244         struct connman_network *network;
245
246         DBG("identifier %s type %d", identifier, type);
247
248         network = g_try_new0(struct connman_network, 1);
249         if (network == NULL)
250                 return NULL;
251
252         DBG("network %p", network);
253
254         network->element.refcount = 1;
255
256         network->element.name = g_strdup(identifier);
257         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
258         network->element.index = -1;
259
260         switch (type) {
261         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
262         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
263                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH;
264                 break;
265         case CONNMAN_NETWORK_TYPE_HSO:
266                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_CELLULAR;
267                 break;
268         default:
269                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
270                 break;
271         }
272
273         network->element.network = network;
274         network->element.destruct = network_destruct;
275
276         network->type = type;
277         network->identifier = g_strdup(identifier);
278
279         return network;
280 }
281
282 /**
283  * connman_network_ref:
284  * @network: network structure
285  *
286  * Increase reference counter of  network
287  */
288 struct connman_network *connman_network_ref(struct connman_network *network)
289 {
290         if (connman_element_ref(&network->element) == NULL)
291                 return NULL;
292
293         return network;
294 }
295
296 /**
297  * connman_network_unref:
298  * @network: network structure
299  *
300  * Decrease reference counter of network
301  */
302 void connman_network_unref(struct connman_network *network)
303 {
304         connman_element_unref(&network->element);
305 }
306
307 /**
308  * connman_network_get_identifier:
309  * @network: network structure
310  *
311  * Get identifier of network
312  */
313 const char *connman_network_get_identifier(struct connman_network *network)
314 {
315         return network->identifier;
316 }
317
318 /**
319  * connman_network_set_path:
320  * @network: network structure
321  * @path: path name
322  *
323  * Set path name of network
324  */
325 void connman_network_set_path(struct connman_network *network, const char *path)
326 {
327         g_free(network->element.devpath);
328         network->element.devpath = g_strdup(path);
329
330         g_free(network->path);
331         network->path = g_strdup(path);
332 }
333
334 /**
335  * connman_network_get_path:
336  * @network: network structure
337  *
338  * Get path name of network
339  */
340 const char *connman_network_get_path(struct connman_network *network)
341 {
342         return network->path;
343 }
344
345 /**
346  * connman_network_set_index:
347  * @network: network structure
348  * @index: index number
349  *
350  * Set index number of network
351  */
352 void connman_network_set_index(struct connman_network *network, int index)
353 {
354         network->element.index = index;
355 }
356
357 /**
358  * connman_network_get_index:
359  * @network: network structure
360  *
361  * Get index number of network
362  */
363 int connman_network_get_index(struct connman_network *network)
364 {
365         return network->element.index;
366 }
367
368 /**
369  * connman_network_set_protocol:
370  * @network: network structure
371  * @protocol: network protocol
372  *
373  * Change protocol of network
374  */
375 void connman_network_set_protocol(struct connman_network *network,
376                                         enum connman_network_protocol protocol)
377 {
378         network->protocol = protocol;
379 }
380
381 /**
382  * connman_network_set_connected:
383  * @network: network structure
384  * @connected: connected state
385  *
386  * Change connected state of network
387  */
388 int connman_network_set_connected(struct connman_network *network,
389                                                 connman_bool_t connected)
390 {
391         DBG("network %p connected %d", network, connected);
392
393         if (network->connected == connected)
394                 return -EALREADY;
395
396         network->connected = connected;
397
398         if (connected == TRUE) {
399                 struct connman_element *element;
400
401                 element = connman_element_create(NULL);
402                 if (element != NULL) {
403                         element->type    = CONNMAN_ELEMENT_TYPE_DEVICE;
404                         element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK;
405                         element->index   = network->element.index;
406
407                         if (connman_element_register(element,
408                                                         &network->element) < 0)
409                                 connman_element_unref(element);
410                 }
411         } else
412                 connman_element_unregister_children(&network->element);
413
414         return 0;
415 }
416
417 void __connman_network_set_device(struct connman_network *network,
418                                         struct connman_device *device)
419 {
420         network->device = device;
421 }
422
423 /**
424  * connman_network_get_device:
425  * @network: network structure
426  *
427  * Get parent device of network
428  */
429 struct connman_device *connman_network_get_device(struct connman_network *network)
430 {
431         return network->device;
432 }
433
434 /**
435  * connman_network_get_data:
436  * @network: network structure
437  *
438  * Get private network data pointer
439  */
440 void *connman_network_get_data(struct connman_network *network)
441 {
442         return network->driver_data;
443 }
444
445 /**
446  * connman_network_set_data:
447  * @network: network structure
448  * @data: data pointer
449  *
450  * Set private network data pointer
451  */
452 void connman_network_set_data(struct connman_network *network, void *data)
453 {
454         network->driver_data = data;
455 }
456
457 static gboolean match_driver(struct connman_network *network,
458                                         struct connman_network_driver *driver)
459 {
460         if (network->type == driver->type ||
461                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
462                 return TRUE;
463
464         return FALSE;
465 }
466
467 static int network_probe(struct connman_element *element)
468 {
469         struct connman_network *network = element->network;
470         GSList *list;
471         int err;
472
473         DBG("element %p name %s", element, element->name);
474
475         if (network == NULL)
476                 return -ENODEV;
477
478         for (list = driver_list; list; list = list->next) {
479                 struct connman_network_driver *driver = list->data;
480
481                 if (match_driver(network, driver) == FALSE)
482                         continue;
483
484                 DBG("driver %p name %s", driver, driver->name);
485
486                 if (driver->probe(network) == 0) {
487                         network->driver = driver;
488                         break;
489                 }
490         }
491
492         if (network->driver == NULL)
493                 return -ENODEV;
494
495         err = register_interface(element);
496         if (err < 0) {
497                 if (network->driver->remove)
498                         network->driver->remove(network);
499                 return err;
500         }
501
502         return 0;
503 }
504
505 static void network_remove(struct connman_element *element)
506 {
507         struct connman_network *network = element->network;
508
509         DBG("element %p name %s", element, element->name);
510
511         if (network == NULL)
512                 return;
513
514         if (network->driver == NULL)
515                 return;
516
517         unregister_interface(element);
518
519         if (network->driver->remove)
520                 network->driver->remove(network);
521 }
522
523 static struct connman_driver network_driver = {
524         .name           = "network",
525         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
526         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
527         .probe          = network_probe,
528         .remove         = network_remove,
529 };
530
531 int __connman_network_init(void)
532 {
533         DBG("");
534
535         connection = connman_dbus_get_connection();
536
537         return connman_driver_register(&network_driver);
538 }
539
540 void __connman_network_cleanup(void)
541 {
542         DBG("");
543
544         connman_driver_unregister(&network_driver);
545
546         dbus_connection_unref(connection);
547 }