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