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