2cf4f084d8dbadb3515b6ef8ace37015450d93ba
[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 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         DBusMessage *signal;
297         DBusMessageIter entry;
298
299         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
300                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
301         if (signal == NULL)
302                 return;
303
304         dbus_message_iter_init_append(signal, &entry);
305
306         append_networks(device, &entry);
307
308         g_dbus_send_message(connection, signal);
309 }
310
311 static int register_interface(struct connman_element *element)
312 {
313         struct connman_network *network = element->network;
314
315         DBG("element %p name %s", element, element->name);
316
317         if (g_dbus_register_interface(connection, element->path,
318                                         CONNMAN_NETWORK_INTERFACE,
319                                         network_methods, network_signals,
320                                         NULL, network, NULL) == FALSE) {
321                 connman_error("Failed to register %s network", element->path);
322                 return -EIO;
323         }
324
325         network->registered = TRUE;
326
327         emit_networks_signal(network->device);
328
329         return 0;
330 }
331
332 static void unregister_interface(struct connman_element *element)
333 {
334         struct connman_network * network = element->network;
335
336         DBG("element %p name %s", element, element->name);
337
338         network->registered = FALSE;
339
340         emit_networks_signal(network->device);
341
342         g_dbus_unregister_interface(connection, element->path,
343                                                 CONNMAN_NETWORK_INTERFACE);
344 }
345
346 connman_bool_t __connman_network_has_driver(struct connman_network *network)
347 {
348         if (network == NULL || network->driver == NULL)
349                 return FALSE;
350
351         return network->registered;
352 }
353
354 static GSList *driver_list = NULL;
355
356 static gint compare_priority(gconstpointer a, gconstpointer b)
357 {
358         const struct connman_network_driver *driver1 = a;
359         const struct connman_network_driver *driver2 = b;
360
361         return driver2->priority - driver1->priority;
362 }
363
364 /**
365  * connman_network_driver_register:
366  * @driver: network driver definition
367  *
368  * Register a new network driver
369  *
370  * Returns: %0 on success
371  */
372 int connman_network_driver_register(struct connman_network_driver *driver)
373 {
374         DBG("driver %p name %s", driver, driver->name);
375
376         driver_list = g_slist_insert_sorted(driver_list, driver,
377                                                         compare_priority);
378
379         return 0;
380 }
381
382 /**
383  * connman_network_driver_unregister:
384  * @driver: network driver definition
385  *
386  * Remove a previously registered network driver
387  */
388 void connman_network_driver_unregister(struct connman_network_driver *driver)
389 {
390         DBG("driver %p name %s", driver, driver->name);
391
392         driver_list = g_slist_remove(driver_list, driver);
393 }
394
395 static void network_destruct(struct connman_element *element)
396 {
397         struct connman_network *network = element->network;
398
399         DBG("element %p name %s", element, element->name);
400
401         g_free(network->wifi.ssid);
402         g_free(network->wifi.mode);
403         g_free(network->wifi.security);
404         g_free(network->wifi.passphrase);
405
406         g_free(network->node);
407         g_free(network->name);
408         g_free(network->identifier);
409 }
410
411 /**
412  * connman_network_create:
413  * @identifier: network identifier (for example an unqiue name)
414  *
415  * Allocate a new network and assign the #identifier to it.
416  *
417  * Returns: a newly-allocated #connman_network structure
418  */
419 struct connman_network *connman_network_create(const char *identifier,
420                                                 enum connman_network_type type)
421 {
422         struct connman_network *network;
423         connman_uint8_t strength = 0;
424         const char *str;
425
426         DBG("identifier %s type %d", identifier, type);
427
428         network = g_try_new0(struct connman_network, 1);
429         if (network == NULL)
430                 return NULL;
431
432         DBG("network %p", network);
433
434         network->element.refcount = 1;
435
436         network->element.name = g_strdup(identifier);
437         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
438         network->element.index = -1;
439
440         network->element.network = network;
441         network->element.destruct = network_destruct;
442
443         str = type2string(type);
444         if (str != NULL)
445                 connman_element_add_static_property(&network->element,
446                                         "Type", DBUS_TYPE_STRING, &str);
447
448         connman_element_add_static_property(&network->element,
449                                         "Strength", DBUS_TYPE_BYTE, &strength);
450
451         network->type = type;
452         network->identifier = g_strdup(identifier);
453
454         return network;
455 }
456
457 /**
458  * connman_network_ref:
459  * @network: network structure
460  *
461  * Increase reference counter of  network
462  */
463 struct connman_network *connman_network_ref(struct connman_network *network)
464 {
465         if (connman_element_ref(&network->element) == NULL)
466                 return NULL;
467
468         return network;
469 }
470
471 /**
472  * connman_network_unref:
473  * @network: network structure
474  *
475  * Decrease reference counter of network
476  */
477 void connman_network_unref(struct connman_network *network)
478 {
479         connman_element_unref(&network->element);
480 }
481
482 /**
483  * connman_network_get_identifier:
484  * @network: network structure
485  *
486  * Get identifier of network
487  */
488 const char *connman_network_get_identifier(struct connman_network *network)
489 {
490         return network->identifier;
491 }
492
493 /**
494  * connman_network_get_path:
495  * @network: network structure
496  *
497  * Get path name of network
498  */
499 const char *connman_network_get_path(struct connman_network *network)
500 {
501         return network->element.path;
502 }
503
504 /**
505  * connman_network_set_index:
506  * @network: network structure
507  * @index: index number
508  *
509  * Set index number of network
510  */
511 void connman_network_set_index(struct connman_network *network, int index)
512 {
513         network->element.index = index;
514 }
515
516 /**
517  * connman_network_get_index:
518  * @network: network structure
519  *
520  * Get index number of network
521  */
522 int connman_network_get_index(struct connman_network *network)
523 {
524         return network->element.index;
525 }
526
527 /**
528  * connman_network_set_protocol:
529  * @network: network structure
530  * @protocol: network protocol
531  *
532  * Change protocol of network
533  */
534 void connman_network_set_protocol(struct connman_network *network,
535                                         enum connman_network_protocol protocol)
536 {
537         network->protocol = protocol;
538 }
539
540 /**
541  * connman_network_set_available:
542  * @network: network structure
543  * @available: availability state
544  *
545  * Change availability state of network (in range)
546  */
547 int connman_network_set_available(struct connman_network *network,
548                                                 connman_bool_t available)
549 {
550         DBusMessage *signal;
551         DBusMessageIter entry, value;
552         const char *key = "Available";
553
554         DBG("network %p available %d", network, available);
555
556         if (network->available == available)
557                 return -EALREADY;
558
559         network->available = available;
560
561         if (network->registered == FALSE)
562                 return 0;
563
564         if (network->connected == FALSE && network->remember == FALSE)
565                 return 0;
566
567         signal = dbus_message_new_signal(network->element.path,
568                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
569         if (signal == NULL)
570                 return 0;
571
572         dbus_message_iter_init_append(signal, &entry);
573
574         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
575
576         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
577                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
578         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &available);
579         dbus_message_iter_close_container(&entry, &value);
580
581         g_dbus_send_message(connection, signal);
582
583         return 0;
584 }
585
586 /**
587  * connman_network_get_available:
588  * @network: network structure
589  *
590  * Get network available setting
591  */
592 connman_bool_t connman_network_get_available(struct connman_network *network)
593 {
594         return network->available;
595 }
596
597 /**
598  * connman_network_set_connected:
599  * @network: network structure
600  * @connected: connected state
601  *
602  * Change connected state of network
603  */
604 int connman_network_set_connected(struct connman_network *network,
605                                                 connman_bool_t connected)
606 {
607         DBusMessage *signal;
608         DBusMessageIter entry, value;
609         const char *key = "Connected";
610
611         DBG("network %p connected %d", network, connected);
612
613         if (network->connected == connected)
614                 return -EALREADY;
615
616         network->connected = connected;
617
618         if (network->registered == FALSE)
619                 return 0;
620
621         signal = dbus_message_new_signal(network->element.path,
622                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
623         if (signal == NULL)
624                 return 0;
625
626         dbus_message_iter_init_append(signal, &entry);
627
628         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
629
630         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
631                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
632         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &connected);
633         dbus_message_iter_close_container(&entry, &value);
634
635         g_dbus_send_message(connection, signal);
636
637         if (connected == TRUE) {
638                 struct connman_element *element;
639                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
640
641                 switch (network->protocol) {
642                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
643                         return 0;
644                 case CONNMAN_NETWORK_PROTOCOL_IP:
645                         type = CONNMAN_ELEMENT_TYPE_DHCP;
646                         break;
647                 case CONNMAN_NETWORK_PROTOCOL_PPP:
648                         type = CONNMAN_ELEMENT_TYPE_PPP;
649                         break;
650                 }
651
652                 __connman_device_increase_connections(network->device);
653
654                 element = connman_element_create(NULL);
655                 if (element != NULL) {
656                         element->type  = type;
657                         element->index = network->element.index;
658
659                         if (connman_element_register(element,
660                                                 &network->element) < 0)
661                                 connman_element_unref(element);
662                 }
663         } else {
664                 connman_element_unregister_children(&network->element);
665
666                 __connman_device_decrease_connections(network->device);
667         }
668
669         return 0;
670 }
671
672 /**
673  * connman_network_set_remember:
674  * @network: network structure
675  * @remember: remember state
676  *
677  * Change remember state of network (known networks)
678  */
679 int connman_network_set_remember(struct connman_network *network,
680                                                 connman_bool_t remember)
681 {
682         DBusMessage *signal;
683         DBusMessageIter entry, value;
684         const char *key = "Remember";
685
686         DBG("network %p remember %d", network, remember);
687
688         if (network->remember == remember)
689                 return -EALREADY;
690
691         network->remember = remember;
692
693         if (network->registered == FALSE)
694                 return 0;
695
696         signal = dbus_message_new_signal(network->element.path,
697                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
698         if (signal == NULL)
699                 return 0;
700
701         dbus_message_iter_init_append(signal, &entry);
702
703         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
704
705         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
706                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
707         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &remember);
708         dbus_message_iter_close_container(&entry, &value);
709
710         g_dbus_send_message(connection, signal);
711
712         return 0;
713 }
714
715 /**
716  * connman_network_get_remember:
717  * @network: network structure
718  *
719  * Get network remember setting
720  */
721 connman_bool_t connman_network_get_remember(struct connman_network *network)
722 {
723         return network->remember;
724 }
725
726 /**
727  * connman_network_connect:
728  * @network: network structure
729  *
730  * Connect network
731  */
732 int connman_network_connect(struct connman_network *network)
733 {
734         if (network->connected == TRUE)
735                 return -EALREADY;
736
737         if (network->driver && network->driver->connect)
738                 return network->driver->connect(network);
739
740         network->connected = TRUE;
741
742         return 0;
743 }
744
745 /**
746  * connman_network_set_string:
747  * @network: network structure
748  * @key: unique identifier
749  * @value: string value
750  *
751  * Set string value for specific key
752  */
753 int connman_network_set_string(struct connman_network *network,
754                                         const char *key, const char *value)
755 {
756         DBG("network %p key %s value %s", network, key, value);
757
758         if (g_str_equal(key, "Name") == TRUE) {
759                 g_free(network->name);
760                 network->name = g_strdup(value);
761         } else if (g_str_equal(key, "Node") == TRUE) {
762                 g_free(network->node);
763                 network->node = g_strdup(value);
764         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
765                 g_free(network->wifi.mode);
766                 network->wifi.mode = g_strdup(value);
767         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
768                 g_free(network->wifi.security);
769                 network->wifi.security = g_strdup(value);
770         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
771                 g_free(network->wifi.passphrase);
772                 network->wifi.passphrase = g_strdup(value);
773         }
774
775         return 0;
776 }
777
778 /**
779  * connman_network_get_string:
780  * @network: network structure
781  * @key: unique identifier
782  *
783  * Get string value for specific key
784  */
785 const char *connman_network_get_string(struct connman_network *network,
786                                                         const char *key)
787 {
788         DBG("network %p key %s", network, key);
789
790         if (g_str_equal(key, "Name") == TRUE)
791                 return network->name;
792         else if (g_str_equal(key, "Node") == TRUE)
793                 return network->node;
794         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
795                 return network->wifi.mode;
796         else if (g_str_equal(key, "WiFi.Security") == TRUE)
797                 return network->wifi.security;
798         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
799                 return network->wifi.passphrase;
800
801         return NULL;
802 }
803
804 /**
805  * connman_network_set_uint8:
806  * @network: network structure
807  * @key: unique identifier
808  * @value: integer value
809  *
810  * Set integer value for specific key
811  */
812 int connman_network_set_uint8(struct connman_network *network,
813                                         const char *key, connman_uint8_t value)
814 {
815         DBG("network %p key %s value %d", network, key, value);
816
817         if (g_str_equal(key, "Strength") == TRUE) {
818                 network->strength = value;
819                 connman_element_set_static_property(&network->element,
820                                         "Strength", DBUS_TYPE_BYTE, &value);
821         }
822
823         return 0;
824 }
825
826 /**
827  * connman_network_set_blob:
828  * @network: network structure
829  * @key: unique identifier
830  * @data: blob data
831  * @size: blob size
832  *
833  * Set binary blob value for specific key
834  */
835 int connman_network_set_blob(struct connman_network *network,
836                         const char *key, const void *data, unsigned int size)
837 {
838         DBG("network %p key %s size %d", network, key, size);
839
840         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
841                 g_free(network->wifi.ssid);
842                 network->wifi.ssid = g_try_malloc(size);
843                 if (network->wifi.ssid != NULL) {
844                         memcpy(network->wifi.ssid, data, size);
845                         network->wifi.ssid_len = size;
846                 } else
847                         network->wifi.ssid_len = 0;
848         }
849
850         return 0;
851 }
852
853 /**
854  * connman_network_get_blob:
855  * @network: network structure
856  * @key: unique identifier
857  * @size: pointer to blob size
858  *
859  * Get binary blob value for specific key
860  */
861 const void *connman_network_get_blob(struct connman_network *network,
862                                         const char *key, unsigned int *size)
863 {
864         DBG("network %p key %s", network, key);
865
866         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
867                 if (size != NULL)
868                         *size = network->wifi.ssid_len;
869                 return network->wifi.ssid;
870         }
871
872         return NULL;
873 }
874
875 void __connman_network_set_device(struct connman_network *network,
876                                         struct connman_device *device)
877 {
878         network->device = device;
879 }
880
881 /**
882  * connman_network_get_device:
883  * @network: network structure
884  *
885  * Get parent device of network
886  */
887 struct connman_device *connman_network_get_device(struct connman_network *network)
888 {
889         return network->device;
890 }
891
892 /**
893  * connman_network_get_data:
894  * @network: network structure
895  *
896  * Get private network data pointer
897  */
898 void *connman_network_get_data(struct connman_network *network)
899 {
900         return network->driver_data;
901 }
902
903 /**
904  * connman_network_set_data:
905  * @network: network structure
906  * @data: data pointer
907  *
908  * Set private network data pointer
909  */
910 void connman_network_set_data(struct connman_network *network, void *data)
911 {
912         network->driver_data = data;
913 }
914
915 static gboolean match_driver(struct connman_network *network,
916                                         struct connman_network_driver *driver)
917 {
918         if (network->type == driver->type ||
919                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
920                 return TRUE;
921
922         return FALSE;
923 }
924
925 static int network_probe(struct connman_element *element)
926 {
927         struct connman_network *network = element->network;
928         GSList *list;
929         int err;
930
931         DBG("element %p name %s", element, element->name);
932
933         if (network == NULL)
934                 return -ENODEV;
935
936         for (list = driver_list; list; list = list->next) {
937                 struct connman_network_driver *driver = list->data;
938
939                 if (match_driver(network, driver) == FALSE)
940                         continue;
941
942                 DBG("driver %p name %s", driver, driver->name);
943
944                 if (driver->probe(network) == 0) {
945                         network->driver = driver;
946                         break;
947                 }
948         }
949
950         if (network->driver == NULL)
951                 return -ENODEV;
952
953         err = register_interface(element);
954         if (err < 0) {
955                 if (network->driver->remove)
956                         network->driver->remove(network);
957                 return err;
958         }
959
960         return 0;
961 }
962
963 static void network_remove(struct connman_element *element)
964 {
965         struct connman_network *network = element->network;
966
967         DBG("element %p name %s", element, element->name);
968
969         if (network == NULL)
970                 return;
971
972         if (network->driver == NULL)
973                 return;
974
975         unregister_interface(element);
976
977         if (network->driver->remove)
978                 network->driver->remove(network);
979 }
980
981 static struct connman_driver network_driver = {
982         .name           = "network",
983         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
984         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
985         .probe          = network_probe,
986         .remove         = network_remove,
987 };
988
989 static int network_load(struct connman_network *network)
990 {
991         GKeyFile *keyfile;
992         gchar *pathname, *data = NULL;
993         gsize length;
994         const char *name;
995         int val;
996
997         DBG("network %p", network);
998
999         name = connman_device_get_name(network->device);
1000         if (name == NULL)
1001                 return -EINVAL;
1002
1003         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
1004         if (pathname == NULL)
1005                 return -ENOMEM;
1006
1007         keyfile = g_key_file_new();
1008
1009         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1010                 g_free(pathname);
1011                 return -ENOENT;
1012         }
1013
1014         g_free(pathname);
1015
1016         if (g_key_file_load_from_data(keyfile, data, length,
1017                                                         0, NULL) == FALSE) {
1018                 g_free(data);
1019                 return -EILSEQ;
1020         }
1021
1022         g_free(data);
1023
1024         network->remember = g_key_file_get_boolean(keyfile,
1025                                         network->identifier, "Remember", NULL);
1026
1027         val = g_key_file_get_integer(keyfile, network->identifier,
1028                                                         "Priority", NULL);
1029         if (val > 0)
1030                 network->priority = val;
1031
1032         if (network->remember == TRUE) {
1033                 g_free(network->wifi.security);
1034                 network->wifi.security = g_key_file_get_string(keyfile,
1035                                 network->identifier, "WiFi.Security", NULL);
1036
1037                 g_free(network->wifi.passphrase);
1038                 network->wifi.passphrase = g_key_file_get_string(keyfile,
1039                                 network->identifier, "WiFi.Passphrase", NULL);
1040         }
1041
1042         g_key_file_free(keyfile);
1043
1044         return 0;
1045 }
1046
1047 static int network_save(struct connman_network *network)
1048 {
1049         GKeyFile *keyfile;
1050         gchar *pathname, *data = NULL;
1051         gsize length;
1052         const char *name;
1053
1054         DBG("network %p", network);
1055
1056         name = connman_device_get_name(network->device);
1057         if (name == NULL)
1058                 return -EINVAL;
1059
1060         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
1061         if (pathname == NULL)
1062                 return -ENOMEM;
1063
1064         keyfile = g_key_file_new();
1065
1066         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1067                 goto update;
1068
1069         if (length > 0) {
1070                 if (g_key_file_load_from_data(keyfile, data, length,
1071                                                         0, NULL) == FALSE)
1072                         goto done;
1073         }
1074
1075         g_free(data);
1076
1077 update:
1078         g_key_file_set_boolean(keyfile, network->identifier,
1079                                         "Remember", network->remember);
1080
1081         if (network->priority > 0)
1082                 g_key_file_set_integer(keyfile, network->identifier,
1083                                                 "Priority", network->priority);
1084
1085         if (network->remember == TRUE) {
1086                 if (network->wifi.security != NULL)
1087                         g_key_file_set_string(keyfile, network->identifier,
1088                                 "WiFi.Security", network->wifi.security);
1089
1090                 if (network->wifi.passphrase != NULL)
1091                         g_key_file_set_string(keyfile, network->identifier,
1092                                 "WiFi.Passphrase", network->wifi.passphrase);
1093         }
1094
1095         data = g_key_file_to_data(keyfile, &length, NULL);
1096
1097         g_file_set_contents(pathname, data, length, NULL);
1098
1099 done:
1100         g_free(data);
1101
1102         g_key_file_free(keyfile);
1103
1104         g_free(pathname);
1105
1106         return 0;
1107 }
1108
1109 static struct connman_storage network_storage = {
1110         .name           = "network",
1111         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1112         .network_load   = network_load,
1113         .network_save   = network_save,
1114 };
1115
1116 int __connman_network_init(void)
1117 {
1118         DBG("");
1119
1120         connection = connman_dbus_get_connection();
1121
1122         if (connman_storage_register(&network_storage) < 0)
1123                 connman_error("Failed to register network storage");
1124
1125         return connman_driver_register(&network_driver);
1126 }
1127
1128 void __connman_network_cleanup(void)
1129 {
1130         DBG("");
1131
1132         connman_driver_unregister(&network_driver);
1133
1134         connman_storage_unregister(&network_storage);
1135
1136         dbus_connection_unref(connection);
1137 }