Fix signal emission for network changes
[platform/upstream/connman.git] / 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 available;
37         connman_bool_t connected;
38         connman_bool_t remember;
39         connman_uint8_t priority;
40         connman_uint8_t strength;
41         char *identifier;
42         char *name;
43         char *node;
44
45         struct connman_network_driver *driver;
46         void *driver_data;
47
48         connman_bool_t registered;
49
50         struct connman_device *device;
51
52         struct {
53                 void *ssid;
54                 int ssid_len;
55                 char *mode;
56                 char *security;
57                 char *passphrase;
58         } wifi;
59 };
60
61 static const char *type2string(enum connman_network_type type)
62 {
63         switch (type) {
64         case CONNMAN_NETWORK_TYPE_UNKNOWN:
65         case CONNMAN_NETWORK_TYPE_VENDOR:
66                 break;
67         case CONNMAN_NETWORK_TYPE_WIFI:
68                 return "wifi";
69         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
70         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
71                 return "bluetooth";
72         case CONNMAN_NETWORK_TYPE_HSO:
73                 return "cellular";
74         }
75
76         return NULL;
77 }
78
79 static DBusMessage *get_properties(DBusConnection *conn,
80                                         DBusMessage *msg, void *data)
81 {
82         struct connman_network *network = data;
83         DBusMessage *reply;
84         DBusMessageIter array, dict;
85
86         DBG("conn %p", conn);
87
88         if (__connman_security_check_privilege(msg,
89                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
90                 return __connman_error_permission_denied(msg);
91
92         reply = dbus_message_new_method_return(msg);
93         if (reply == NULL)
94                 return NULL;
95
96         dbus_message_iter_init_append(reply, &array);
97
98         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
99                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
100                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
101                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
102
103         if (network->device) {
104                 const char *path = connman_device_get_path(network->device);
105                 if (path != NULL)
106                         connman_dbus_dict_append_variant(&dict, "Device",
107                                                 DBUS_TYPE_OBJECT_PATH, &path);
108         }
109
110         if (network->name != NULL)
111                 connman_dbus_dict_append_variant(&dict, "Name",
112                                         DBUS_TYPE_STRING, &network->name);
113
114         connman_dbus_dict_append_variant(&dict, "Available",
115                                 DBUS_TYPE_BOOLEAN, &network->available);
116
117         connman_dbus_dict_append_variant(&dict, "Connected",
118                                 DBUS_TYPE_BOOLEAN, &network->connected);
119
120         connman_dbus_dict_append_variant(&dict, "Remember",
121                                 DBUS_TYPE_BOOLEAN, &network->remember);
122
123         if (network->priority > 0)
124                 connman_dbus_dict_append_variant(&dict, "Priority",
125                                         DBUS_TYPE_BYTE, &network->priority);
126
127         if (network->strength > 0)
128                 connman_dbus_dict_append_variant(&dict, "Strength",
129                                         DBUS_TYPE_BYTE, &network->strength);
130
131         if (network->wifi.ssid != NULL && network->wifi.ssid_len > 0)
132                 connman_dbus_dict_append_array(&dict, "WiFi.SSID",
133                                 DBUS_TYPE_BYTE, &network->wifi.ssid,
134                                                 network->wifi.ssid_len);
135
136         if (network->wifi.mode != NULL)
137                 connman_dbus_dict_append_variant(&dict, "WiFi.Mode",
138                                 DBUS_TYPE_STRING, &network->wifi.mode);
139
140         if (network->wifi.security != NULL)
141                 connman_dbus_dict_append_variant(&dict, "WiFi.Security",
142                                 DBUS_TYPE_STRING, &network->wifi.security);
143
144         if (network->wifi.passphrase != NULL &&
145                         __connman_security_check_privilege(msg,
146                                 CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
147                 connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase",
148                                 DBUS_TYPE_STRING, &network->wifi.passphrase);
149
150         dbus_message_iter_close_container(&array, &dict);
151
152         return reply;
153 }
154
155 static DBusMessage *set_property(DBusConnection *conn,
156                                         DBusMessage *msg, void *data)
157 {
158         struct connman_network *network = data;
159         DBusMessageIter iter, value;
160         const char *name;
161
162         DBG("conn %p", conn);
163
164         if (dbus_message_iter_init(msg, &iter) == FALSE)
165                 return __connman_error_invalid_arguments(msg);
166
167         dbus_message_iter_get_basic(&iter, &name);
168         dbus_message_iter_next(&iter);
169         dbus_message_iter_recurse(&iter, &value);
170
171         if (__connman_security_check_privilege(msg,
172                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
173                 return __connman_error_permission_denied(msg);
174
175         if (g_str_equal(name, "Remember") == TRUE) {
176                 connman_bool_t remember;
177
178                 dbus_message_iter_get_basic(&value, &remember);
179
180                 if (network->remember == remember)
181                         return __connman_error_invalid_arguments(msg);
182         } else if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
183                 const char *passphrase;
184
185                 if (__connman_security_check_privilege(msg,
186                                         CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
187                         return __connman_error_permission_denied(msg);
188
189                 dbus_message_iter_get_basic(&value, &passphrase);
190
191                 g_free(network->wifi.passphrase);
192                 network->wifi.passphrase = g_strdup(passphrase);
193         } else if (g_str_equal(name, "Priority") == TRUE) {
194                 connman_uint8_t priority;
195
196                 dbus_message_iter_get_basic(&value, &priority);
197
198                 network->priority = priority;
199         }
200
201         __connman_storage_save_network(network);
202
203         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
204 }
205
206 static DBusMessage *do_connect(DBusConnection *conn,
207                                         DBusMessage *msg, void *data)
208 {
209         struct connman_network *network = data;
210         int err;
211
212         DBG("conn %p", conn);
213
214         if (__connman_security_check_privilege(msg,
215                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
216                 return __connman_error_permission_denied(msg);
217
218         if (network->connected == TRUE)
219                 return __connman_error_failed(msg);
220
221         if (network->driver && network->driver->connect) {
222                 err = network->driver->connect(network);
223                 if (err < 0 && err != -EINPROGRESS)
224                         return __connman_error_failed(msg);
225         } else
226                 network->connected = TRUE;
227
228         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
229 }
230
231 static DBusMessage *do_disconnect(DBusConnection *conn,
232                                         DBusMessage *msg, void *data)
233 {
234         struct connman_network *network = data;
235         int err;
236
237         DBG("conn %p", conn);
238
239         if (__connman_security_check_privilege(msg,
240                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
241                 return __connman_error_permission_denied(msg);
242
243         if (network->connected == FALSE)
244                 return __connman_error_failed(msg);
245
246         connman_element_unregister_children(&network->element);
247
248         if (network->driver && network->driver->disconnect) {
249                 err = network->driver->disconnect(network);
250                 if (err < 0 && err != -EINPROGRESS)
251                         return __connman_error_failed(msg);
252         } else
253                 network->connected = FALSE;
254
255         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
256 }
257
258 static GDBusMethodTable network_methods[] = {
259         { "GetProperties", "",   "a{sv}", get_properties },
260         { "SetProperty",   "sv", "",      set_property   },
261         { "Connect",       "",   "",      do_connect     },
262         { "Disconnect",    "",   "",      do_disconnect  },
263         { },
264 };
265
266 static GDBusSignalTable network_signals[] = {
267         { "PropertyChanged", "sv" },
268         { },
269 };
270
271 static DBusConnection *connection;
272
273 static void append_networks(struct connman_device *device,
274                                                 DBusMessageIter *entry)
275 {
276         DBusMessageIter value, iter;
277         const char *key = "Networks";
278
279         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
280
281         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
282                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
283                                                                 &value);
284
285         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
286                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
287         __connman_element_list((struct connman_element *) device,
288                                         CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
289         dbus_message_iter_close_container(&value, &iter);
290
291         dbus_message_iter_close_container(entry, &value);
292 }
293
294 static void emit_networks_signal(struct connman_device *device)
295 {
296         const char *path = connman_device_get_path(device);
297         DBusMessage *signal;
298         DBusMessageIter entry;
299
300         signal = dbus_message_new_signal(path,
301                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
302         if (signal == NULL)
303                 return;
304
305         dbus_message_iter_init_append(signal, &entry);
306
307         append_networks(device, &entry);
308
309         g_dbus_send_message(connection, signal);
310 }
311
312 static int register_interface(struct connman_element *element)
313 {
314         struct connman_network *network = element->network;
315
316         DBG("element %p name %s", element, element->name);
317
318         if (g_dbus_register_interface(connection, element->path,
319                                         CONNMAN_NETWORK_INTERFACE,
320                                         network_methods, network_signals,
321                                         NULL, network, NULL) == FALSE) {
322                 connman_error("Failed to register %s network", element->path);
323                 return -EIO;
324         }
325
326         network->registered = TRUE;
327
328         emit_networks_signal(network->device);
329
330         return 0;
331 }
332
333 static void unregister_interface(struct connman_element *element)
334 {
335         struct connman_network * network = element->network;
336
337         DBG("element %p name %s", element, element->name);
338
339         network->registered = FALSE;
340
341         emit_networks_signal(network->device);
342
343         g_dbus_unregister_interface(connection, element->path,
344                                                 CONNMAN_NETWORK_INTERFACE);
345 }
346
347 connman_bool_t __connman_network_has_driver(struct connman_network *network)
348 {
349         if (network == NULL || network->driver == NULL)
350                 return FALSE;
351
352         return network->registered;
353 }
354
355 static GSList *driver_list = NULL;
356
357 static gint compare_priority(gconstpointer a, gconstpointer b)
358 {
359         const struct connman_network_driver *driver1 = a;
360         const struct connman_network_driver *driver2 = b;
361
362         return driver2->priority - driver1->priority;
363 }
364
365 /**
366  * connman_network_driver_register:
367  * @driver: network driver definition
368  *
369  * Register a new network driver
370  *
371  * Returns: %0 on success
372  */
373 int connman_network_driver_register(struct connman_network_driver *driver)
374 {
375         DBG("driver %p name %s", driver, driver->name);
376
377         driver_list = g_slist_insert_sorted(driver_list, driver,
378                                                         compare_priority);
379
380         return 0;
381 }
382
383 /**
384  * connman_network_driver_unregister:
385  * @driver: network driver definition
386  *
387  * Remove a previously registered network driver
388  */
389 void connman_network_driver_unregister(struct connman_network_driver *driver)
390 {
391         DBG("driver %p name %s", driver, driver->name);
392
393         driver_list = g_slist_remove(driver_list, driver);
394 }
395
396 static void network_destruct(struct connman_element *element)
397 {
398         struct connman_network *network = element->network;
399
400         DBG("element %p name %s", element, element->name);
401
402         g_free(network->wifi.ssid);
403         g_free(network->wifi.mode);
404         g_free(network->wifi.security);
405         g_free(network->wifi.passphrase);
406
407         g_free(network->node);
408         g_free(network->name);
409         g_free(network->identifier);
410 }
411
412 /**
413  * connman_network_create:
414  * @identifier: network identifier (for example an unqiue name)
415  *
416  * Allocate a new network and assign the #identifier to it.
417  *
418  * Returns: a newly-allocated #connman_network structure
419  */
420 struct connman_network *connman_network_create(const char *identifier,
421                                                 enum connman_network_type type)
422 {
423         struct connman_network *network;
424         connman_uint8_t strength = 0;
425         const char *str;
426
427         DBG("identifier %s type %d", identifier, type);
428
429         network = g_try_new0(struct connman_network, 1);
430         if (network == NULL)
431                 return NULL;
432
433         DBG("network %p", network);
434
435         network->element.refcount = 1;
436
437         network->element.name = g_strdup(identifier);
438         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
439         network->element.index = -1;
440
441         network->element.network = network;
442         network->element.destruct = network_destruct;
443
444         str = type2string(type);
445         if (str != NULL)
446                 connman_element_add_static_property(&network->element,
447                                         "Type", DBUS_TYPE_STRING, &str);
448
449         connman_element_add_static_property(&network->element,
450                                         "Strength", DBUS_TYPE_BYTE, &strength);
451
452         network->type = type;
453         network->identifier = g_strdup(identifier);
454
455         return network;
456 }
457
458 /**
459  * connman_network_ref:
460  * @network: network structure
461  *
462  * Increase reference counter of  network
463  */
464 struct connman_network *connman_network_ref(struct connman_network *network)
465 {
466         if (connman_element_ref(&network->element) == NULL)
467                 return NULL;
468
469         return network;
470 }
471
472 /**
473  * connman_network_unref:
474  * @network: network structure
475  *
476  * Decrease reference counter of network
477  */
478 void connman_network_unref(struct connman_network *network)
479 {
480         connman_element_unref(&network->element);
481 }
482
483 /**
484  * connman_network_get_identifier:
485  * @network: network structure
486  *
487  * Get identifier of network
488  */
489 const char *connman_network_get_identifier(struct connman_network *network)
490 {
491         return network->identifier;
492 }
493
494 /**
495  * connman_network_get_path:
496  * @network: network structure
497  *
498  * Get path name of network
499  */
500 const char *connman_network_get_path(struct connman_network *network)
501 {
502         return network->element.path;
503 }
504
505 /**
506  * connman_network_set_index:
507  * @network: network structure
508  * @index: index number
509  *
510  * Set index number of network
511  */
512 void connman_network_set_index(struct connman_network *network, int index)
513 {
514         network->element.index = index;
515 }
516
517 /**
518  * connman_network_get_index:
519  * @network: network structure
520  *
521  * Get index number of network
522  */
523 int connman_network_get_index(struct connman_network *network)
524 {
525         return network->element.index;
526 }
527
528 /**
529  * connman_network_set_protocol:
530  * @network: network structure
531  * @protocol: network protocol
532  *
533  * Change protocol of network
534  */
535 void connman_network_set_protocol(struct connman_network *network,
536                                         enum connman_network_protocol protocol)
537 {
538         network->protocol = protocol;
539 }
540
541 /**
542  * connman_network_set_available:
543  * @network: network structure
544  * @available: availability state
545  *
546  * Change availability state of network (in range)
547  */
548 int connman_network_set_available(struct connman_network *network,
549                                                 connman_bool_t available)
550 {
551         DBusMessage *signal;
552         DBusMessageIter entry, value;
553         const char *key = "Available";
554
555         DBG("network %p available %d", network, available);
556
557         if (network->available == available)
558                 return -EALREADY;
559
560         network->available = available;
561
562         if (network->registered == FALSE)
563                 return 0;
564
565         if (network->connected == FALSE && network->remember == FALSE)
566                 return 0;
567
568         signal = dbus_message_new_signal(network->element.path,
569                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
570         if (signal == NULL)
571                 return 0;
572
573         dbus_message_iter_init_append(signal, &entry);
574
575         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
576
577         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
578                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
579         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &available);
580         dbus_message_iter_close_container(&entry, &value);
581
582         g_dbus_send_message(connection, signal);
583
584         return 0;
585 }
586
587 /**
588  * connman_network_get_available:
589  * @network: network structure
590  *
591  * Get network available setting
592  */
593 connman_bool_t connman_network_get_available(struct connman_network *network)
594 {
595         return network->available;
596 }
597
598 /**
599  * connman_network_set_connected:
600  * @network: network structure
601  * @connected: connected state
602  *
603  * Change connected state of network
604  */
605 int connman_network_set_connected(struct connman_network *network,
606                                                 connman_bool_t connected)
607 {
608         DBusMessage *signal;
609         DBusMessageIter entry, value;
610         const char *key = "Connected";
611
612         DBG("network %p connected %d", network, connected);
613
614         if (network->connected == connected)
615                 return -EALREADY;
616
617         network->connected = connected;
618
619         if (network->registered == FALSE)
620                 return 0;
621
622         signal = dbus_message_new_signal(network->element.path,
623                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
624         if (signal == NULL)
625                 return 0;
626
627         dbus_message_iter_init_append(signal, &entry);
628
629         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
630
631         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
632                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
633         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &connected);
634         dbus_message_iter_close_container(&entry, &value);
635
636         g_dbus_send_message(connection, signal);
637
638         if (connected == TRUE) {
639                 struct connman_element *element;
640                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
641
642                 switch (network->protocol) {
643                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
644                         return 0;
645                 case CONNMAN_NETWORK_PROTOCOL_IP:
646                         type = CONNMAN_ELEMENT_TYPE_DHCP;
647                         break;
648                 case CONNMAN_NETWORK_PROTOCOL_PPP:
649                         type = CONNMAN_ELEMENT_TYPE_PPP;
650                         break;
651                 }
652
653                 __connman_device_increase_connections(network->device);
654
655                 element = connman_element_create(NULL);
656                 if (element != NULL) {
657                         element->type  = type;
658                         element->index = network->element.index;
659
660                         if (connman_element_register(element,
661                                                 &network->element) < 0)
662                                 connman_element_unref(element);
663                 }
664         } else {
665                 connman_element_unregister_children(&network->element);
666
667                 __connman_device_decrease_connections(network->device);
668         }
669
670         return 0;
671 }
672
673 /**
674  * connman_network_set_remember:
675  * @network: network structure
676  * @remember: remember state
677  *
678  * Change remember state of network (known networks)
679  */
680 int connman_network_set_remember(struct connman_network *network,
681                                                 connman_bool_t remember)
682 {
683         DBusMessage *signal;
684         DBusMessageIter entry, value;
685         const char *key = "Remember";
686
687         DBG("network %p remember %d", network, remember);
688
689         if (network->remember == remember)
690                 return -EALREADY;
691
692         network->remember = remember;
693
694         if (network->registered == FALSE)
695                 return 0;
696
697         signal = dbus_message_new_signal(network->element.path,
698                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
699         if (signal == NULL)
700                 return 0;
701
702         dbus_message_iter_init_append(signal, &entry);
703
704         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
705
706         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
707                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
708         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &remember);
709         dbus_message_iter_close_container(&entry, &value);
710
711         g_dbus_send_message(connection, signal);
712
713         return 0;
714 }
715
716 /**
717  * connman_network_get_remember:
718  * @network: network structure
719  *
720  * Get network remember setting
721  */
722 connman_bool_t connman_network_get_remember(struct connman_network *network)
723 {
724         return network->remember;
725 }
726
727 /**
728  * connman_network_connect:
729  * @network: network structure
730  *
731  * Connect network
732  */
733 int connman_network_connect(struct connman_network *network)
734 {
735         if (network->connected == TRUE)
736                 return -EALREADY;
737
738         if (network->driver && network->driver->connect)
739                 return network->driver->connect(network);
740
741         network->connected = TRUE;
742
743         return 0;
744 }
745
746 /**
747  * connman_network_set_string:
748  * @network: network structure
749  * @key: unique identifier
750  * @value: string value
751  *
752  * Set string value for specific key
753  */
754 int connman_network_set_string(struct connman_network *network,
755                                         const char *key, const char *value)
756 {
757         DBG("network %p key %s value %s", network, key, value);
758
759         if (g_str_equal(key, "Name") == TRUE) {
760                 g_free(network->name);
761                 network->name = g_strdup(value);
762         } else if (g_str_equal(key, "Node") == TRUE) {
763                 g_free(network->node);
764                 network->node = g_strdup(value);
765         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
766                 g_free(network->wifi.mode);
767                 network->wifi.mode = g_strdup(value);
768         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
769                 g_free(network->wifi.security);
770                 network->wifi.security = g_strdup(value);
771         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
772                 g_free(network->wifi.passphrase);
773                 network->wifi.passphrase = g_strdup(value);
774         }
775
776         return 0;
777 }
778
779 /**
780  * connman_network_get_string:
781  * @network: network structure
782  * @key: unique identifier
783  *
784  * Get string value for specific key
785  */
786 const char *connman_network_get_string(struct connman_network *network,
787                                                         const char *key)
788 {
789         DBG("network %p key %s", network, key);
790
791         if (g_str_equal(key, "Name") == TRUE)
792                 return network->name;
793         else if (g_str_equal(key, "Node") == TRUE)
794                 return network->node;
795         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
796                 return network->wifi.mode;
797         else if (g_str_equal(key, "WiFi.Security") == TRUE)
798                 return network->wifi.security;
799         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
800                 return network->wifi.passphrase;
801
802         return NULL;
803 }
804
805 /**
806  * connman_network_set_uint8:
807  * @network: network structure
808  * @key: unique identifier
809  * @value: integer value
810  *
811  * Set integer value for specific key
812  */
813 int connman_network_set_uint8(struct connman_network *network,
814                                         const char *key, connman_uint8_t value)
815 {
816         DBG("network %p key %s value %d", network, key, value);
817
818         if (g_str_equal(key, "Priority") == TRUE)
819                 network->priority = value;
820         else if (g_str_equal(key, "Strength") == TRUE) {
821                 network->strength = value;
822                 connman_element_set_static_property(&network->element,
823                                         "Strength", DBUS_TYPE_BYTE, &value);
824         }
825
826         return 0;
827 }
828
829 /**
830  * connman_network_get_uint8:
831  * @network: network structure
832  * @key: unique identifier
833  *
834  * Get integer value for specific key
835  */
836 connman_uint8_t connman_network_get_uint8(struct connman_network *network,
837                                                         const char *key)
838 {
839         DBG("network %p key %s", network, key);
840
841         if (g_str_equal(key, "Priority") == TRUE)
842                 return network->priority;
843         else if (g_str_equal(key, "Strength") == TRUE)
844                 return network->strength;
845
846         return 0;
847 }
848
849 /**
850  * connman_network_set_blob:
851  * @network: network structure
852  * @key: unique identifier
853  * @data: blob data
854  * @size: blob size
855  *
856  * Set binary blob value for specific key
857  */
858 int connman_network_set_blob(struct connman_network *network,
859                         const char *key, const void *data, unsigned int size)
860 {
861         DBG("network %p key %s size %d", network, key, size);
862
863         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
864                 g_free(network->wifi.ssid);
865                 network->wifi.ssid = g_try_malloc(size);
866                 if (network->wifi.ssid != NULL) {
867                         memcpy(network->wifi.ssid, data, size);
868                         network->wifi.ssid_len = size;
869                 } else
870                         network->wifi.ssid_len = 0;
871         }
872
873         return 0;
874 }
875
876 /**
877  * connman_network_get_blob:
878  * @network: network structure
879  * @key: unique identifier
880  * @size: pointer to blob size
881  *
882  * Get binary blob value for specific key
883  */
884 const void *connman_network_get_blob(struct connman_network *network,
885                                         const char *key, unsigned int *size)
886 {
887         DBG("network %p key %s", network, key);
888
889         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
890                 if (size != NULL)
891                         *size = network->wifi.ssid_len;
892                 return network->wifi.ssid;
893         }
894
895         return NULL;
896 }
897
898 void __connman_network_set_device(struct connman_network *network,
899                                         struct connman_device *device)
900 {
901         network->device = device;
902 }
903
904 /**
905  * connman_network_get_device:
906  * @network: network structure
907  *
908  * Get parent device of network
909  */
910 struct connman_device *connman_network_get_device(struct connman_network *network)
911 {
912         return network->device;
913 }
914
915 /**
916  * connman_network_get_data:
917  * @network: network structure
918  *
919  * Get private network data pointer
920  */
921 void *connman_network_get_data(struct connman_network *network)
922 {
923         return network->driver_data;
924 }
925
926 /**
927  * connman_network_set_data:
928  * @network: network structure
929  * @data: data pointer
930  *
931  * Set private network data pointer
932  */
933 void connman_network_set_data(struct connman_network *network, void *data)
934 {
935         network->driver_data = data;
936 }
937
938 static gboolean match_driver(struct connman_network *network,
939                                         struct connman_network_driver *driver)
940 {
941         if (network->type == driver->type ||
942                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
943                 return TRUE;
944
945         return FALSE;
946 }
947
948 static int network_probe(struct connman_element *element)
949 {
950         struct connman_network *network = element->network;
951         GSList *list;
952         int err;
953
954         DBG("element %p name %s", element, element->name);
955
956         if (network == NULL)
957                 return -ENODEV;
958
959         for (list = driver_list; list; list = list->next) {
960                 struct connman_network_driver *driver = list->data;
961
962                 if (match_driver(network, driver) == FALSE)
963                         continue;
964
965                 DBG("driver %p name %s", driver, driver->name);
966
967                 if (driver->probe(network) == 0) {
968                         network->driver = driver;
969                         break;
970                 }
971         }
972
973         if (network->driver == NULL)
974                 return -ENODEV;
975
976         err = register_interface(element);
977         if (err < 0) {
978                 if (network->driver->remove)
979                         network->driver->remove(network);
980                 return err;
981         }
982
983         return 0;
984 }
985
986 static void network_remove(struct connman_element *element)
987 {
988         struct connman_network *network = element->network;
989
990         DBG("element %p name %s", element, element->name);
991
992         if (network == NULL)
993                 return;
994
995         if (network->driver == NULL)
996                 return;
997
998         unregister_interface(element);
999
1000         if (network->driver->remove)
1001                 network->driver->remove(network);
1002 }
1003
1004 static struct connman_driver network_driver = {
1005         .name           = "network",
1006         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
1007         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1008         .probe          = network_probe,
1009         .remove         = network_remove,
1010 };
1011
1012 static int network_init(struct connman_device *device)
1013 {
1014         DBG("device %p", device);
1015
1016         return 0;
1017 }
1018
1019 static int network_load(struct connman_network *network)
1020 {
1021         GKeyFile *keyfile;
1022         gchar *pathname, *data = NULL;
1023         gsize length;
1024         const char *name;
1025         int val;
1026
1027         DBG("network %p", network);
1028
1029         name = connman_device_get_name(network->device);
1030         if (name == NULL)
1031                 return -EINVAL;
1032
1033         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
1034         if (pathname == NULL)
1035                 return -ENOMEM;
1036
1037         keyfile = g_key_file_new();
1038
1039         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1040                 g_free(pathname);
1041                 return -ENOENT;
1042         }
1043
1044         g_free(pathname);
1045
1046         if (g_key_file_load_from_data(keyfile, data, length,
1047                                                         0, NULL) == FALSE) {
1048                 g_free(data);
1049                 return -EILSEQ;
1050         }
1051
1052         g_free(data);
1053
1054         network->remember = g_key_file_get_boolean(keyfile,
1055                                         network->identifier, "Remember", NULL);
1056
1057         val = g_key_file_get_integer(keyfile, network->identifier,
1058                                                         "Priority", NULL);
1059         if (val > 0)
1060                 network->priority = val;
1061
1062         if (network->remember == TRUE) {
1063                 g_free(network->wifi.security);
1064                 network->wifi.security = g_key_file_get_string(keyfile,
1065                                 network->identifier, "WiFi.Security", NULL);
1066
1067                 g_free(network->wifi.passphrase);
1068                 network->wifi.passphrase = g_key_file_get_string(keyfile,
1069                                 network->identifier, "WiFi.Passphrase", NULL);
1070         }
1071
1072         g_key_file_free(keyfile);
1073
1074         return 0;
1075 }
1076
1077 static int network_save(struct connman_network *network)
1078 {
1079         GKeyFile *keyfile;
1080         gchar *pathname, *data = NULL;
1081         gsize length;
1082         const char *name;
1083
1084         DBG("network %p", network);
1085
1086         name = connman_device_get_name(network->device);
1087         if (name == NULL)
1088                 return -EINVAL;
1089
1090         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
1091         if (pathname == NULL)
1092                 return -ENOMEM;
1093
1094         keyfile = g_key_file_new();
1095
1096         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1097                 goto update;
1098
1099         if (length > 0) {
1100                 if (g_key_file_load_from_data(keyfile, data, length,
1101                                                         0, NULL) == FALSE)
1102                         goto done;
1103         }
1104
1105         g_free(data);
1106
1107 update:
1108         g_key_file_set_boolean(keyfile, network->identifier,
1109                                         "Remember", network->remember);
1110
1111         if (network->priority > 0)
1112                 g_key_file_set_integer(keyfile, network->identifier,
1113                                                 "Priority", network->priority);
1114
1115         if (network->remember == TRUE) {
1116                 if (network->wifi.security != NULL)
1117                         g_key_file_set_string(keyfile, network->identifier,
1118                                 "WiFi.Security", network->wifi.security);
1119
1120                 if (network->wifi.passphrase != NULL)
1121                         g_key_file_set_string(keyfile, network->identifier,
1122                                 "WiFi.Passphrase", network->wifi.passphrase);
1123         }
1124
1125         data = g_key_file_to_data(keyfile, &length, NULL);
1126
1127         g_file_set_contents(pathname, data, length, NULL);
1128
1129 done:
1130         g_free(data);
1131
1132         g_key_file_free(keyfile);
1133
1134         g_free(pathname);
1135
1136         return 0;
1137 }
1138
1139 static struct connman_storage network_storage = {
1140         .name           = "network",
1141         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1142         .network_init   = network_init,
1143         .network_load   = network_load,
1144         .network_save   = network_save,
1145 };
1146
1147 int __connman_network_init(void)
1148 {
1149         DBG("");
1150
1151         connection = connman_dbus_get_connection();
1152
1153         if (connman_storage_register(&network_storage) < 0)
1154                 connman_error("Failed to register network storage");
1155
1156         return connman_driver_register(&network_driver);
1157 }
1158
1159 void __connman_network_cleanup(void)
1160 {
1161         DBG("");
1162
1163         connman_driver_unregister(&network_driver);
1164
1165         connman_storage_unregister(&network_storage);
1166
1167         dbus_connection_unref(connection);
1168 }