b21a224fa53826d9630006dc2514929beec52602
[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 <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_UNKNOWN:
262         case CONNMAN_NETWORK_TYPE_VENDOR:
263                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
264                 break;
265         case CONNMAN_NETWORK_TYPE_WIFI:
266                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_WIFI;
267                 break;
268         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
269         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
270                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH;
271                 break;
272         case CONNMAN_NETWORK_TYPE_HSO:
273                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_CELLULAR;
274                 break;
275         }
276
277         network->element.network = network;
278         network->element.destruct = network_destruct;
279
280         network->type = type;
281         network->identifier = g_strdup(identifier);
282
283         return network;
284 }
285
286 /**
287  * connman_network_ref:
288  * @network: network structure
289  *
290  * Increase reference counter of  network
291  */
292 struct connman_network *connman_network_ref(struct connman_network *network)
293 {
294         if (connman_element_ref(&network->element) == NULL)
295                 return NULL;
296
297         return network;
298 }
299
300 /**
301  * connman_network_unref:
302  * @network: network structure
303  *
304  * Decrease reference counter of network
305  */
306 void connman_network_unref(struct connman_network *network)
307 {
308         connman_element_unref(&network->element);
309 }
310
311 /**
312  * connman_network_get_identifier:
313  * @network: network structure
314  *
315  * Get identifier of network
316  */
317 const char *connman_network_get_identifier(struct connman_network *network)
318 {
319         return network->identifier;
320 }
321
322 /**
323  * connman_network_set_path:
324  * @network: network structure
325  * @path: path name
326  *
327  * Set path name of network
328  */
329 void connman_network_set_path(struct connman_network *network, const char *path)
330 {
331         g_free(network->element.devpath);
332         network->element.devpath = g_strdup(path);
333
334         g_free(network->path);
335         network->path = g_strdup(path);
336 }
337
338 /**
339  * connman_network_get_path:
340  * @network: network structure
341  *
342  * Get path name of network
343  */
344 const char *connman_network_get_path(struct connman_network *network)
345 {
346         return network->path;
347 }
348
349 /**
350  * connman_network_set_index:
351  * @network: network structure
352  * @index: index number
353  *
354  * Set index number of network
355  */
356 void connman_network_set_index(struct connman_network *network, int index)
357 {
358         network->element.index = index;
359 }
360
361 /**
362  * connman_network_get_index:
363  * @network: network structure
364  *
365  * Get index number of network
366  */
367 int connman_network_get_index(struct connman_network *network)
368 {
369         return network->element.index;
370 }
371
372 /**
373  * connman_network_set_protocol:
374  * @network: network structure
375  * @protocol: network protocol
376  *
377  * Change protocol of network
378  */
379 void connman_network_set_protocol(struct connman_network *network,
380                                         enum connman_network_protocol protocol)
381 {
382         network->protocol = protocol;
383 }
384
385 /**
386  * connman_network_set_connected:
387  * @network: network structure
388  * @connected: connected state
389  *
390  * Change connected state of network
391  */
392 int connman_network_set_connected(struct connman_network *network,
393                                                 connman_bool_t connected)
394 {
395         DBG("network %p connected %d", network, connected);
396
397         if (network->connected == connected)
398                 return -EALREADY;
399
400         network->connected = connected;
401
402         if (connected == TRUE) {
403                 struct connman_element *element;
404                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
405
406                 switch (network->protocol) {
407                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
408                         return 0;
409                 case CONNMAN_NETWORK_PROTOCOL_IP:
410                         type = CONNMAN_ELEMENT_TYPE_DHCP;
411                         break;
412                 case CONNMAN_NETWORK_PROTOCOL_PPP:
413                         type = CONNMAN_ELEMENT_TYPE_PPP;
414                         break;
415                 }
416
417                 element = connman_element_create(NULL);
418                 if (element != NULL) {
419                         element->type    = type;
420                         element->subtype = network->element.subtype;
421                         element->index   = network->element.index;
422
423                         if (connman_element_register(element,
424                                                         &network->element) < 0)
425                                 connman_element_unref(element);
426                 }
427         } else
428                 connman_element_unregister_children(&network->element);
429
430         return 0;
431 }
432
433 void __connman_network_set_device(struct connman_network *network,
434                                         struct connman_device *device)
435 {
436         network->device = device;
437 }
438
439 /**
440  * connman_network_get_device:
441  * @network: network structure
442  *
443  * Get parent device of network
444  */
445 struct connman_device *connman_network_get_device(struct connman_network *network)
446 {
447         return network->device;
448 }
449
450 /**
451  * connman_network_get_data:
452  * @network: network structure
453  *
454  * Get private network data pointer
455  */
456 void *connman_network_get_data(struct connman_network *network)
457 {
458         return network->driver_data;
459 }
460
461 /**
462  * connman_network_set_data:
463  * @network: network structure
464  * @data: data pointer
465  *
466  * Set private network data pointer
467  */
468 void connman_network_set_data(struct connman_network *network, void *data)
469 {
470         network->driver_data = data;
471 }
472
473 static gboolean match_driver(struct connman_network *network,
474                                         struct connman_network_driver *driver)
475 {
476         if (network->type == driver->type ||
477                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
478                 return TRUE;
479
480         return FALSE;
481 }
482
483 static int network_probe(struct connman_element *element)
484 {
485         struct connman_network *network = element->network;
486         GSList *list;
487         int err;
488
489         DBG("element %p name %s", element, element->name);
490
491         if (network == NULL)
492                 return -ENODEV;
493
494         for (list = driver_list; list; list = list->next) {
495                 struct connman_network_driver *driver = list->data;
496
497                 if (match_driver(network, driver) == FALSE)
498                         continue;
499
500                 DBG("driver %p name %s", driver, driver->name);
501
502                 if (driver->probe(network) == 0) {
503                         network->driver = driver;
504                         break;
505                 }
506         }
507
508         if (network->driver == NULL)
509                 return -ENODEV;
510
511         err = register_interface(element);
512         if (err < 0) {
513                 if (network->driver->remove)
514                         network->driver->remove(network);
515                 return err;
516         }
517
518         return 0;
519 }
520
521 static void network_remove(struct connman_element *element)
522 {
523         struct connman_network *network = element->network;
524
525         DBG("element %p name %s", element, element->name);
526
527         if (network == NULL)
528                 return;
529
530         if (network->driver == NULL)
531                 return;
532
533         unregister_interface(element);
534
535         if (network->driver->remove)
536                 network->driver->remove(network);
537 }
538
539 static struct connman_driver network_driver = {
540         .name           = "network",
541         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
542         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
543         .probe          = network_probe,
544         .remove         = network_remove,
545 };
546
547 int __connman_network_init(void)
548 {
549         DBG("");
550
551         connection = connman_dbus_get_connection();
552
553         return connman_driver_register(&network_driver);
554 }
555
556 void __connman_network_cleanup(void)
557 {
558         DBG("");
559
560         connman_driver_unregister(&network_driver);
561
562         dbus_connection_unref(connection);
563 }