Remove deprecated network subtype
[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                 enum connman_element_type type;
401
402                 switch (network->protocol) {
403                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
404                         return 0;
405                 case CONNMAN_NETWORK_PROTOCOL_IP:
406                         type = CONNMAN_ELEMENT_TYPE_DHCP;
407                         break;
408                 case CONNMAN_NETWORK_PROTOCOL_PPP:
409                         type = CONNMAN_ELEMENT_TYPE_PPP;
410                         break;
411                 }
412
413                 element = connman_element_create(NULL);
414                 if (element != NULL) {
415                         element->type    = type;
416                         element->subtype = network->element.subtype;
417                         element->index   = network->element.index;
418
419                         if (connman_element_register(element,
420                                                         &network->element) < 0)
421                                 connman_element_unref(element);
422                 }
423         } else
424                 connman_element_unregister_children(&network->element);
425
426         return 0;
427 }
428
429 void __connman_network_set_device(struct connman_network *network,
430                                         struct connman_device *device)
431 {
432         network->device = device;
433 }
434
435 /**
436  * connman_network_get_device:
437  * @network: network structure
438  *
439  * Get parent device of network
440  */
441 struct connman_device *connman_network_get_device(struct connman_network *network)
442 {
443         return network->device;
444 }
445
446 /**
447  * connman_network_get_data:
448  * @network: network structure
449  *
450  * Get private network data pointer
451  */
452 void *connman_network_get_data(struct connman_network *network)
453 {
454         return network->driver_data;
455 }
456
457 /**
458  * connman_network_set_data:
459  * @network: network structure
460  * @data: data pointer
461  *
462  * Set private network data pointer
463  */
464 void connman_network_set_data(struct connman_network *network, void *data)
465 {
466         network->driver_data = data;
467 }
468
469 static gboolean match_driver(struct connman_network *network,
470                                         struct connman_network_driver *driver)
471 {
472         if (network->type == driver->type ||
473                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
474                 return TRUE;
475
476         return FALSE;
477 }
478
479 static int network_probe(struct connman_element *element)
480 {
481         struct connman_network *network = element->network;
482         GSList *list;
483         int err;
484
485         DBG("element %p name %s", element, element->name);
486
487         if (network == NULL)
488                 return -ENODEV;
489
490         for (list = driver_list; list; list = list->next) {
491                 struct connman_network_driver *driver = list->data;
492
493                 if (match_driver(network, driver) == FALSE)
494                         continue;
495
496                 DBG("driver %p name %s", driver, driver->name);
497
498                 if (driver->probe(network) == 0) {
499                         network->driver = driver;
500                         break;
501                 }
502         }
503
504         if (network->driver == NULL)
505                 return -ENODEV;
506
507         err = register_interface(element);
508         if (err < 0) {
509                 if (network->driver->remove)
510                         network->driver->remove(network);
511                 return err;
512         }
513
514         return 0;
515 }
516
517 static void network_remove(struct connman_element *element)
518 {
519         struct connman_network *network = element->network;
520
521         DBG("element %p name %s", element, element->name);
522
523         if (network == NULL)
524                 return;
525
526         if (network->driver == NULL)
527                 return;
528
529         unregister_interface(element);
530
531         if (network->driver->remove)
532                 network->driver->remove(network);
533 }
534
535 static struct connman_driver network_driver = {
536         .name           = "network",
537         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
538         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
539         .probe          = network_probe,
540         .remove         = network_remove,
541 };
542
543 int __connman_network_init(void)
544 {
545         DBG("");
546
547         connection = connman_dbus_get_connection();
548
549         return connman_driver_register(&network_driver);
550 }
551
552 void __connman_network_cleanup(void)
553 {
554         DBG("");
555
556         connman_driver_unregister(&network_driver);
557
558         dbus_connection_unref(connection);
559 }