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