9365ed6f959abf72a796ff9491f428b30283ef71
[framework/connectivity/connman.git] / src / network.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 "connman.h"
30
31 static unsigned int hidden_counter = 0;
32
33 struct connman_network {
34         struct connman_element element;
35         enum connman_network_type type;
36         connman_bool_t available;
37         connman_bool_t connected;
38         connman_bool_t roaming;
39         connman_bool_t hidden;
40         connman_uint8_t strength;
41         connman_uint16_t frequency;
42         char *identifier;
43         char *address;
44         char *name;
45         char *node;
46         char *group;
47         struct connman_ipconfig *ipconfig;
48
49         struct connman_network_driver *driver;
50         void *driver_data;
51
52         connman_bool_t connecting;
53         connman_bool_t associating;
54
55         struct connman_device *device;
56
57         struct {
58                 void *ssid;
59                 int ssid_len;
60                 char *mode;
61                 unsigned short channel;
62                 char *security;
63                 char *passphrase;
64                 char *eap;
65                 char *identity;
66                 char *ca_cert_path;
67                 char *client_cert_path;
68                 char *private_key_path;
69                 char *private_key_passphrase;
70                 char *phase2_auth;
71         } wifi;
72 };
73
74 static const char *type2string(enum connman_network_type type)
75 {
76         switch (type) {
77         case CONNMAN_NETWORK_TYPE_UNKNOWN:
78         case CONNMAN_NETWORK_TYPE_VENDOR:
79                 break;
80         case CONNMAN_NETWORK_TYPE_ETHERNET:
81                 return "ethernet";
82         case CONNMAN_NETWORK_TYPE_WIFI:
83                 return "wifi";
84         case CONNMAN_NETWORK_TYPE_WIMAX:
85                 return "wimax";
86         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
87         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
88                 return "bluetooth";
89         case CONNMAN_NETWORK_TYPE_CELLULAR:
90                 return "cellular";
91         }
92
93         return NULL;
94 }
95
96 connman_bool_t __connman_network_has_driver(struct connman_network *network)
97 {
98         if (network == NULL || network->driver == NULL)
99                 return FALSE;
100
101         return TRUE;
102 }
103
104 static GSList *driver_list = NULL;
105
106 static gint compare_priority(gconstpointer a, gconstpointer b)
107 {
108         const struct connman_network_driver *driver1 = a;
109         const struct connman_network_driver *driver2 = b;
110
111         return driver2->priority - driver1->priority;
112 }
113
114 /**
115  * connman_network_driver_register:
116  * @driver: network driver definition
117  *
118  * Register a new network driver
119  *
120  * Returns: %0 on success
121  */
122 int connman_network_driver_register(struct connman_network_driver *driver)
123 {
124         GSList *list;
125
126         DBG("driver %p name %s", driver, driver->name);
127
128         for (list = driver_list; list; list = list->next) {
129                 struct connman_network_driver *tmp = list->data;
130
131                 if (tmp->type == driver->type)
132                         return -EALREADY;
133
134         }
135
136         driver_list = g_slist_insert_sorted(driver_list, driver,
137                                                         compare_priority);
138
139         return 0;
140 }
141
142 /**
143  * connman_network_driver_unregister:
144  * @driver: network driver definition
145  *
146  * Remove a previously registered network driver
147  */
148 void connman_network_driver_unregister(struct connman_network_driver *driver)
149 {
150         DBG("driver %p name %s", driver, driver->name);
151
152         driver_list = g_slist_remove(driver_list, driver);
153 }
154
155 static void network_destruct(struct connman_element *element)
156 {
157         struct connman_network *network = element->network;
158
159         DBG("element %p name %s", element, element->name);
160
161         g_free(network->wifi.ssid);
162         g_free(network->wifi.mode);
163         g_free(network->wifi.security);
164         g_free(network->wifi.passphrase);
165
166         g_free(network->group);
167         g_free(network->node);
168         g_free(network->name);
169         g_free(network->address);
170         g_free(network->identifier);
171
172         if (network->ipconfig) {
173                 connman_ipconfig_unref(network->ipconfig);
174                 network->ipconfig = NULL;
175         }
176
177         network->device = NULL;
178 }
179
180 /**
181  * connman_network_create:
182  * @identifier: network identifier (for example an unqiue name)
183  *
184  * Allocate a new network and assign the #identifier to it.
185  *
186  * Returns: a newly-allocated #connman_network structure
187  */
188 struct connman_network *connman_network_create(const char *identifier,
189                                                 enum connman_network_type type)
190 {
191         struct connman_network *network;
192         connman_uint8_t strength = 0;
193         const char *str;
194         char *temp;
195
196         DBG("identifier %s type %d", identifier, type);
197
198         network = g_try_new0(struct connman_network, 1);
199         if (network == NULL)
200                 return NULL;
201
202         DBG("network %p", network);
203
204         __connman_element_initialize(&network->element);
205
206         if (identifier == NULL) {
207                 temp = g_strdup_printf("hidden_%d", hidden_counter++);
208                 network->hidden = TRUE;
209         } else
210                 temp = g_strdup(identifier);
211
212         if (temp == NULL) {
213                 g_free(network);
214                 return NULL;
215         }
216
217         network->element.name = temp;
218         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
219
220         network->element.network = network;
221         network->element.destruct = network_destruct;
222
223         str = type2string(type);
224         if (str != NULL)
225                 connman_element_set_string(&network->element, "Type", str);
226
227         connman_element_set_uint8(&network->element, "Strength", strength);
228
229         network->type       = type;
230         network->identifier = g_strdup(temp);
231
232         return network;
233 }
234
235 /**
236  * connman_network_ref:
237  * @network: network structure
238  *
239  * Increase reference counter of  network
240  */
241 struct connman_network *connman_network_ref(struct connman_network *network)
242 {
243         if (connman_element_ref(&network->element) == NULL)
244                 return NULL;
245
246         return network;
247 }
248
249 /**
250  * connman_network_unref:
251  * @network: network structure
252  *
253  * Decrease reference counter of network
254  */
255 void connman_network_unref(struct connman_network *network)
256 {
257         connman_element_unref(&network->element);
258 }
259
260 const char *__connman_network_get_type(struct connman_network *network)
261 {
262         return type2string(network->type);
263 }
264
265 /**
266  * connman_network_get_type:
267  * @network: network structure
268  *
269  * Get type of network
270  */
271 enum connman_network_type connman_network_get_type(struct connman_network *network)
272 {
273         return network->type;
274 }
275
276 /**
277  * connman_network_get_identifier:
278  * @network: network structure
279  *
280  * Get identifier of network
281  */
282 const char *connman_network_get_identifier(struct connman_network *network)
283 {
284         return network->identifier;
285 }
286
287 /**
288  * connman_network_get_path:
289  * @network: network structure
290  *
291  * Get path name of network
292  */
293 const char *connman_network_get_path(struct connman_network *network)
294 {
295         return network->element.path;
296 }
297
298 /**
299  * connman_network_set_index:
300  * @network: network structure
301  * @index: index number
302  *
303  * Set index number of network
304  */
305 void connman_network_set_index(struct connman_network *network, int index)
306 {
307         struct connman_service *service;
308         struct connman_ipconfig *ipconfig;
309
310         service = __connman_service_lookup_from_network(network);
311         if (service == NULL)
312                 goto done;
313
314         ipconfig = __connman_service_get_ipconfig(service);
315
316         if (network->element.index < 0 && ipconfig == NULL)
317                 /*
318                  * This is needed for plugins that havent set their ipconfig
319                  * layer yet, due to not being able to get a network index
320                  * prior to creating a service.
321                  */
322                 __connman_service_create_ipconfig(service, index);
323         else {
324                 /* If index changed, the index of ipconfig must be reset. */
325                 if (ipconfig == NULL)
326                         goto done;
327
328                 __connman_ipconfig_set_index(ipconfig, index);
329         }
330
331 done:
332         network->element.index = index;
333 }
334
335 /**
336  * connman_network_get_index:
337  * @network: network structure
338  *
339  * Get index number of network
340  */
341 int connman_network_get_index(struct connman_network *network)
342 {
343         return network->element.index;
344 }
345
346 /**
347  * connman_network_get_element:
348  * @network: network structure
349  *
350  * Get connman_element of network
351  */
352 struct connman_element *connman_network_get_element(
353                                 struct connman_network *network)
354 {
355         return &network->element;
356 }
357
358 /**
359  * connman_network_set_group:
360  * @network: network structure
361  * @group: group name
362  *
363  * Set group name for automatic clustering
364  */
365 void connman_network_set_group(struct connman_network *network,
366                                                         const char *group)
367 {
368         switch (network->type) {
369         case CONNMAN_NETWORK_TYPE_UNKNOWN:
370         case CONNMAN_NETWORK_TYPE_VENDOR:
371                 return;
372         case CONNMAN_NETWORK_TYPE_ETHERNET:
373         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
374         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
375         case CONNMAN_NETWORK_TYPE_CELLULAR:
376         case CONNMAN_NETWORK_TYPE_WIFI:
377         case CONNMAN_NETWORK_TYPE_WIMAX:
378                 break;
379         }
380
381         if (g_strcmp0(network->group, group) == 0) {
382                 if (group != NULL)
383                         __connman_profile_update_network(network);
384                 return;
385         }
386
387         if (network->group != NULL) {
388                 __connman_profile_remove_network(network);
389
390                 g_free(network->group);
391         }
392
393         network->group = g_strdup(group);
394
395         if (network->group != NULL)
396                         __connman_profile_add_network(network);
397 }
398
399 /**
400  * connman_network_get_group:
401  * @network: network structure
402  *
403  * Get group name for automatic clustering
404  */
405 const char *connman_network_get_group(struct connman_network *network)
406 {
407         return network->group;
408 }
409
410 const char *__connman_network_get_ident(struct connman_network *network)
411 {
412         if (network->device == NULL)
413                 return NULL;
414
415         return connman_device_get_ident(network->device);
416 }
417
418 connman_bool_t __connman_network_get_weakness(struct connman_network *network)
419 {
420         switch (network->type) {
421         case CONNMAN_NETWORK_TYPE_UNKNOWN:
422         case CONNMAN_NETWORK_TYPE_VENDOR:
423         case CONNMAN_NETWORK_TYPE_ETHERNET:
424         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
425         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
426         case CONNMAN_NETWORK_TYPE_CELLULAR:
427         case CONNMAN_NETWORK_TYPE_WIMAX:
428                 break;
429         case CONNMAN_NETWORK_TYPE_WIFI:
430                 if (g_strcmp0(network->wifi.mode, "adhoc") == 0)
431                         return TRUE;
432                 if (network->strength > 0 && network->strength < 20)
433                         return TRUE;
434                 break;
435         }
436
437         return FALSE;
438 }
439
440 connman_bool_t __connman_network_get_connecting(struct connman_network *network)
441 {
442         return network->connecting;
443 }
444
445 /**
446  * connman_network_set_available:
447  * @network: network structure
448  * @available: availability state
449  *
450  * Change availability state of network (in range)
451  */
452 int connman_network_set_available(struct connman_network *network,
453                                                 connman_bool_t available)
454 {
455         DBG("network %p available %d", network, available);
456
457         if (network->available == available)
458                 return -EALREADY;
459
460         network->available = available;
461
462         return 0;
463 }
464
465 /**
466  * connman_network_get_available:
467  * @network: network structure
468  *
469  * Get network available setting
470  */
471 connman_bool_t connman_network_get_available(struct connman_network *network)
472 {
473         if (network->hidden == TRUE)
474                 return TRUE;
475
476         return network->available;
477 }
478
479 /**
480  * connman_network_set_associating:
481  * @network: network structure
482  * @associating: associating state
483  *
484  * Change associating state of network
485  */
486 int connman_network_set_associating(struct connman_network *network,
487                                                 connman_bool_t associating)
488 {
489         DBG("network %p associating %d", network, associating);
490
491         if (network->associating == associating)
492                 return -EALREADY;
493
494         network->associating = associating;
495
496         if (associating == TRUE) {
497                 struct connman_service *service;
498
499                 service = __connman_service_lookup_from_network(network);
500                 __connman_service_indicate_state(service,
501                                         CONNMAN_SERVICE_STATE_ASSOCIATION);
502         }
503
504         return 0;
505 }
506
507 static void set_associate_error(struct connman_network *network)
508 {
509         struct connman_service *service;
510
511         if (network->associating == FALSE)
512                 return ;
513
514         network->associating = FALSE;
515
516         service = __connman_service_lookup_from_network(network);
517
518         __connman_service_indicate_state(service,
519                                         CONNMAN_SERVICE_STATE_FAILURE);
520 }
521
522 static void set_configure_error(struct connman_network *network)
523 {
524         struct connman_service *service;
525
526         network->connecting = FALSE;
527
528         service = __connman_service_lookup_from_network(network);
529
530         __connman_service_indicate_state(service,
531                                         CONNMAN_SERVICE_STATE_FAILURE);
532 }
533
534 void connman_network_set_method(struct connman_network *network,
535                                         enum connman_ipconfig_method method)
536 {
537         struct connman_service *service;
538         struct connman_ipconfig *ipconfig;
539
540         network->element.ipv4.method = method;
541
542         service = __connman_service_lookup_from_network(network);
543         if (service == NULL)
544                 return;
545
546         ipconfig = __connman_service_get_ipconfig(service);
547         if (ipconfig == NULL)
548                 return;
549
550         connman_ipconfig_set_method(ipconfig, method);
551 }
552
553 void connman_network_set_error(struct connman_network *network,
554                                         enum connman_network_error error)
555 {
556         DBG("nework %p, error %d", network, error);
557
558         network->connecting = FALSE;
559
560         switch (error) {
561         case CONNMAN_NETWORK_ERROR_UNKNOWN:
562                 return;
563         case CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL:
564                 set_associate_error(network);
565                 break;
566         case CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL:
567                 set_configure_error(network);
568                 break;
569         }
570 }
571
572 static void set_configuration(struct connman_network *network)
573 {
574         struct connman_service *service;
575
576         DBG("network %p", network);
577
578         __connman_device_increase_connections(network->device);
579
580         __connman_device_set_network(network->device, network);
581
582         connman_device_set_disconnected(network->device, FALSE);
583
584         service = __connman_service_lookup_from_network(network);
585         __connman_service_indicate_state(service,
586                                         CONNMAN_SERVICE_STATE_CONFIGURATION);
587 }
588
589 static int set_connected_fixed(struct connman_network *network)
590 {
591         struct connman_service *service;
592         struct connman_element *parent, *element;
593
594         DBG("");
595
596         service = __connman_service_lookup_from_network(network);
597
598         parent = connman_network_get_element(network);
599
600         set_configuration(network);
601
602         if (parent->ipv4.address == NULL)
603                 return -EINVAL;
604
605         if (parent->ipv4.netmask == NULL)
606                 return -EINVAL;
607
608         element = connman_element_create(NULL);
609         if (element == NULL) {
610                 connman_error("Can not create connman_element");
611                 return -ENOMEM;
612         }
613
614         element->type = CONNMAN_ELEMENT_TYPE_IPV4;
615         element->index = parent->index;
616
617         if (connman_element_register(element, parent) < 0) {
618                 connman_error("Can not register connman_element");
619                 return -EINVAL;
620         }
621
622         network->connecting = FALSE;
623
624         connman_network_set_associating(network, FALSE);
625
626         return 0;
627 }
628
629 static void set_connected_manual(struct connman_network *network)
630 {
631         struct connman_service *service;
632         struct connman_ipconfig *ipconfig;
633         const char *nameserver = NULL;
634         int err;
635
636         DBG("network %p", network);
637
638         service = __connman_service_lookup_from_network(network);
639
640         ipconfig = __connman_service_get_ipconfig(service);
641
642         set_configuration(network);
643
644         err = __connman_ipconfig_set_address(ipconfig);
645         if (err < 0) {
646                 connman_network_set_error(network,
647                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
648                 return;
649         }
650
651         connman_element_get_value(&network->element,
652                         CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
653         if (nameserver != NULL)
654                 __connman_service_append_nameserver(service, nameserver);
655
656         __connman_ipconfig_set_gateway(ipconfig, &network->element);
657
658         network->connecting = FALSE;
659
660         connman_network_set_associating(network, FALSE);
661
662         __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY);
663 }
664
665 static int set_connected_dhcp(struct connman_network *network)
666 {
667         struct connman_element *element;
668         int error;
669
670         DBG("network %p", network);
671
672         element = connman_element_create(NULL);
673         if (element == NULL)
674                 return -ENOMEM;
675
676         element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
677         element->index = network->element.index;
678
679         error = connman_element_register(element, &network->element);
680         if (error < 0) {
681                 connman_element_unref(element);
682                 return error;
683         }
684
685         set_configuration(network);
686
687         return 0;
688 }
689
690 static int manual_ipv6_set(struct connman_network *network,
691                                 struct connman_ipconfig *ipconfig_ipv6)
692 {
693         struct connman_service *service;
694         int err;
695
696         service = __connman_service_lookup_from_network(network);
697         if (service == NULL)
698                 return -EINVAL;
699
700         err = __connman_ipconfig_set_address(ipconfig_ipv6);
701         if (err < 0) {
702                 connman_network_set_error(network,
703                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
704                 return err;
705         }
706
707         /*
708          * READY state will be indicated by IPV4 setting
709          * gateway will be set by IPV4 setting
710          */
711
712         return 0;
713 }
714
715 static gboolean set_connected(gpointer user_data)
716 {
717         struct connman_network *network = user_data;
718         struct connman_service *service;
719         struct connman_ipconfig *ipconfig;
720         enum connman_ipconfig_method method;
721
722         service = __connman_service_lookup_from_network(network);
723
724         ipconfig = __connman_service_get_ipconfig(service);
725
726         method = __connman_ipconfig_get_method(ipconfig);
727
728         DBG("method %d", method);
729
730         if (network->connected == TRUE) {
731                 enum connman_ipconfig_method ipv6_method;
732                 struct connman_ipconfig *ipv6config;
733                 int ret;
734
735                 ipv6config = connman_ipconfig_get_ipv6config(ipconfig);
736                 ipv6_method = __connman_ipconfig_get_method(ipv6config);
737                 switch (ipv6_method) {
738                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
739                 case CONNMAN_IPCONFIG_METHOD_OFF:
740                         break;
741                 case CONNMAN_IPCONFIG_METHOD_FIXED:
742                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
743                         ret = manual_ipv6_set(network, ipv6config);
744                         if (ret != 0) {
745                                 connman_network_set_error(network,
746                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
747                                 return FALSE;
748                         }
749                         break;
750                 case CONNMAN_IPCONFIG_METHOD_DHCP:
751                         break;
752                 }
753
754                 switch (method) {
755                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
756                 case CONNMAN_IPCONFIG_METHOD_OFF:
757                         return FALSE;
758                 case CONNMAN_IPCONFIG_METHOD_FIXED:
759                         if (set_connected_fixed(network) < 0) {
760                                 connman_network_set_error(network,
761                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
762                                 return FALSE;
763                         }
764                         return TRUE;
765                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
766                         set_connected_manual(network);
767                         return TRUE;
768                 case CONNMAN_IPCONFIG_METHOD_DHCP:
769                         if (set_connected_dhcp(network) < 0) {
770                                 connman_network_set_error(network,
771                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
772                                 return FALSE;
773                         }
774                 }
775
776         } else {
777                 struct connman_service *service;
778
779                 connman_element_unregister_children(&network->element);
780
781                 __connman_device_set_network(network->device, NULL);
782                 network->hidden = FALSE;
783
784                 __connman_device_decrease_connections(network->device);
785
786                 service = __connman_service_lookup_from_network(network);
787
788                 __connman_service_indicate_state(service,
789                                                 CONNMAN_SERVICE_STATE_IDLE);
790         }
791
792         network->connecting = FALSE;
793
794         connman_network_set_associating(network, FALSE);
795
796         return FALSE;
797 }
798
799 /**
800  * connman_network_set_connected:
801  * @network: network structure
802  * @connected: connected state
803  *
804  * Change connected state of network
805  */
806 int connman_network_set_connected(struct connman_network *network,
807                                                 connman_bool_t connected)
808 {
809         DBG("network %p connected %d", network, connected);
810
811         if ((network->connecting == TRUE || network->associating == TRUE) &&
812                                                         connected == FALSE) {
813                 connman_element_set_error(&network->element,
814                                         CONNMAN_ELEMENT_ERROR_CONNECT_FAILED);
815                 __connman_network_disconnect(network);
816         }
817
818         if (network->connected == connected)
819                 return -EALREADY;
820
821         network->connected = connected;
822
823         set_connected(network);
824
825         return 0;
826 }
827
828 /**
829  * connman_network_get_connected:
830  * @network: network structure
831  *
832  * Get network connection status
833  */
834 connman_bool_t connman_network_get_connected(struct connman_network *network)
835 {
836         return network->connected;
837 }
838
839 /**
840  * connman_network_get_associating:
841  * @network: network structure
842  *
843  * Get network associating status
844  */
845 connman_bool_t connman_network_get_associating(struct connman_network *network)
846 {
847         return network->associating;
848 }
849
850 /**
851  * __connman_network_connect:
852  * @network: network structure
853  *
854  * Connect network
855  */
856 int __connman_network_connect(struct connman_network *network)
857 {
858         struct connman_service *service;
859         int err;
860
861         DBG("network %p", network);
862
863         if (network->connected == TRUE)
864                 return -EISCONN;
865
866         if (network->connecting == TRUE || network->associating == TRUE)
867                 return -EALREADY;
868
869         if (network->driver == NULL)
870                 return -EUNATCH;
871
872         if (network->driver->connect == NULL)
873                 return -ENOSYS;
874
875         if (network->device == NULL)
876                 return -ENODEV;
877
878         __connman_device_disconnect(network->device);
879
880         network->connecting = TRUE;
881
882         service = __connman_service_lookup_from_network(network);
883
884         err = network->driver->connect(network);
885         if (err < 0) {
886                 if (err == -EINPROGRESS)
887                         connman_network_set_associating(network, TRUE);
888                 else {
889                         network->connecting = FALSE;
890                         network->hidden = FALSE;
891                 }
892
893                 return err;
894         }
895
896         network->connected = TRUE;
897         set_connected(network);
898
899         return err;
900 }
901
902 /**
903  * __connman_network_disconnect:
904  * @network: network structure
905  *
906  * Disconnect network
907  */
908 int __connman_network_disconnect(struct connman_network *network)
909 {
910         int err;
911
912         DBG("network %p", network);
913
914         if (network->connected == FALSE && network->connecting == FALSE &&
915                                                 network->associating == FALSE)
916                 return -ENOTCONN;
917
918         if (network->driver == NULL)
919                 return -EUNATCH;
920
921         if (network->driver->disconnect == NULL)
922                 return -ENOSYS;
923
924         network->connecting = FALSE;
925
926         err = network->driver->disconnect(network);
927         if (err == 0) {
928                 connman_network_set_connected(network, FALSE);
929                 set_connected(network);
930         }
931
932         return err;
933 }
934
935 static int dhcp_start(struct connman_network *network)
936 {
937         struct connman_element *element;
938         int error;
939
940         element = connman_element_create(NULL);
941         if (element == NULL)
942                 return -ENOMEM;
943
944         element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
945         element->index = network->element.index;
946
947         error = connman_element_register(element, &network->element);
948         if (error < 0) {
949                 connman_element_unref(element);
950                 return error;
951         }
952
953         return 0;
954 }
955
956 static int dhcp_stop(struct connman_network *network)
957 {
958         connman_element_unregister_children_type(&network->element,
959                                         CONNMAN_ELEMENT_TYPE_CONNECTION);
960         connman_element_unregister_children_type(&network->element,
961                                                 CONNMAN_ELEMENT_TYPE_IPV4);
962         connman_element_unregister_children_type(&network->element,
963                                                 CONNMAN_ELEMENT_TYPE_DHCP);
964
965         return 0;
966 }
967
968 static int manual_ipv4_set(struct connman_network *network,
969                                 struct connman_ipconfig *ipconfig)
970 {
971         struct connman_service *service;
972         int err;
973
974         service = __connman_service_lookup_from_network(network);
975         if (service == NULL)
976                 return -EINVAL;
977
978         err = __connman_ipconfig_set_address(ipconfig);
979         if (err < 0) {
980                 connman_network_set_error(network,
981                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
982                 return err;
983         }
984
985         __connman_ipconfig_set_gateway(ipconfig, &network->element);
986
987         __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY);
988
989         return 0;
990 }
991
992 int __connman_network_clear_ipconfig(struct connman_network *network,
993                                         struct connman_ipconfig *ipconfig)
994 {
995         struct connman_service *service;
996         enum connman_ipconfig_method method;
997
998         service = __connman_service_lookup_from_network(network);
999         if (service == NULL)
1000                 return -EINVAL;
1001
1002         method = __connman_ipconfig_get_method(ipconfig);
1003
1004         switch (method) {
1005         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1006         case CONNMAN_IPCONFIG_METHOD_OFF:
1007         case CONNMAN_IPCONFIG_METHOD_FIXED:
1008                 return -EINVAL;
1009         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1010                 connman_element_unregister_children_type(&network->element,
1011                                         CONNMAN_ELEMENT_TYPE_CONNECTION);
1012                 __connman_ipconfig_clear_address(ipconfig);
1013                 break;
1014         case CONNMAN_IPCONFIG_METHOD_DHCP:
1015                 dhcp_stop(network);
1016                 break;
1017         }
1018
1019         __connman_service_indicate_state(service,
1020                                         CONNMAN_SERVICE_STATE_CONFIGURATION);
1021
1022         return 0;
1023 }
1024
1025 int __connman_network_set_ipconfig(struct connman_network *network,
1026                                         struct connman_ipconfig *ipconfig)
1027 {
1028         struct connman_ipconfig *ipv6config;
1029         enum connman_ipconfig_method method;
1030         int ret;
1031
1032         ipv6config = connman_ipconfig_get_ipv6config(ipconfig);
1033         method = __connman_ipconfig_get_method(ipv6config);
1034         switch (method) {
1035         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1036         case CONNMAN_IPCONFIG_METHOD_OFF:
1037                 break;
1038         case CONNMAN_IPCONFIG_METHOD_FIXED:
1039         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1040                 ret = manual_ipv6_set(network, ipv6config);
1041                 if (ret != 0) {
1042                         connman_network_set_error(network,
1043                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
1044                         return FALSE;
1045                 }
1046                 break;
1047         case CONNMAN_IPCONFIG_METHOD_DHCP:
1048                 break;
1049         }
1050
1051         method = __connman_ipconfig_get_method(ipconfig);
1052
1053         switch (method) {
1054         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1055         case CONNMAN_IPCONFIG_METHOD_OFF:
1056         case CONNMAN_IPCONFIG_METHOD_FIXED:
1057                 return -EINVAL;
1058         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1059                 return manual_ipv4_set(network, ipconfig);
1060         case CONNMAN_IPCONFIG_METHOD_DHCP:
1061                 return dhcp_start(network);
1062         }
1063
1064         return 0;
1065 }
1066
1067 /**
1068  * connman_network_set_address:
1069  * @network: network structure
1070  * @address: binary address value
1071  * @size: binary address length
1072  *
1073  * Set unique address value for network
1074  */
1075 int connman_network_set_address(struct connman_network *network,
1076                                 const void *address, unsigned int size)
1077 {
1078         const unsigned char *addr_octet = address;
1079         char *str;
1080
1081         DBG("network %p size %d", network, size);
1082
1083         if (size != 6)
1084                 return -EINVAL;
1085
1086         str = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X",
1087                                 addr_octet[0], addr_octet[1], addr_octet[2],
1088                                 addr_octet[3], addr_octet[4], addr_octet[5]);
1089         if (str == NULL)
1090                 return -ENOMEM;
1091
1092         g_free(network->address);
1093         network->address = str;
1094
1095         return connman_element_set_string(&network->element,
1096                                                 "Address", network->address);
1097 }
1098
1099 /**
1100  * connman_network_set_name:
1101  * @network: network structure
1102  * @name: name value
1103  *
1104  * Set display name value for network
1105  */
1106 int connman_network_set_name(struct connman_network *network,
1107                                                         const char *name)
1108 {
1109         DBG("network %p name %s", network, name);
1110
1111         g_free(network->name);
1112         network->name = g_strdup(name);
1113
1114         return connman_element_set_string(&network->element, "Name", name);
1115 }
1116
1117 /**
1118  * connman_network_set_strength:
1119  * @network: network structure
1120  * @strength: strength value
1121  *
1122  * Set signal strength value for network
1123  */
1124 int connman_network_set_strength(struct connman_network *network,
1125                                                 connman_uint8_t strength)
1126 {
1127         DBG("network %p strengh %d", network, strength);
1128
1129         network->strength = strength;
1130
1131         return connman_element_set_uint8(&network->element,
1132                                                 "Strength", strength);
1133 }
1134
1135 /**
1136  * connman_network_set_roaming:
1137  * @network: network structure
1138  * @roaming: roaming state
1139  *
1140  * Set roaming state for network
1141  */
1142 int connman_network_set_roaming(struct connman_network *network,
1143                                                 connman_bool_t roaming)
1144 {
1145         DBG("network %p roaming %d", network, roaming);
1146
1147         network->roaming = roaming;
1148
1149         return connman_element_set_bool(&network->element,
1150                                                 "Roaming", roaming);
1151 }
1152
1153 /**
1154  * connman_network_set_string:
1155  * @network: network structure
1156  * @key: unique identifier
1157  * @value: string value
1158  *
1159  * Set string value for specific key
1160  */
1161 int connman_network_set_string(struct connman_network *network,
1162                                         const char *key, const char *value)
1163 {
1164         int err;
1165
1166         DBG("network %p key %s value %s", network, key, value);
1167
1168         if (g_strcmp0(key, "Name") == 0)
1169                 return connman_network_set_name(network, value);
1170
1171         if (g_str_equal(key, "Address") == TRUE) {
1172                 g_free(network->address);
1173                 network->address = g_strdup(value);
1174         } else if (g_str_equal(key, "Node") == TRUE) {
1175                 g_free(network->node);
1176                 network->node = g_strdup(value);
1177         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
1178                 g_free(network->wifi.mode);
1179                 network->wifi.mode = g_strdup(value);
1180         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
1181                 g_free(network->wifi.security);
1182                 network->wifi.security = g_strdup(value);
1183         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
1184                 g_free(network->wifi.passphrase);
1185                 network->wifi.passphrase = g_strdup(value);
1186         } else if (g_str_equal(key, "WiFi.EAP") == TRUE) {
1187                 g_free(network->wifi.eap);
1188                 network->wifi.eap = g_strdup(value);
1189         } else if (g_str_equal(key, "WiFi.Identity") == TRUE) {
1190                 g_free(network->wifi.identity);
1191                 network->wifi.identity = g_strdup(value);
1192         } else if (g_str_equal(key, "WiFi.CACertFile") == TRUE) {
1193                 g_free(network->wifi.ca_cert_path);
1194                 network->wifi.ca_cert_path = g_strdup(value);
1195         } else if (g_str_equal(key, "WiFi.ClientCertFile") == TRUE) {
1196                 g_free(network->wifi.client_cert_path);
1197                 network->wifi.client_cert_path = g_strdup(value);
1198         } else if (g_str_equal(key, "WiFi.PrivateKeyFile") == TRUE) {
1199                 g_free(network->wifi.private_key_path);
1200                 network->wifi.private_key_path = g_strdup(value);
1201         } else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase") == TRUE) {
1202                 g_free(network->wifi.private_key_passphrase);
1203                 network->wifi.private_key_passphrase = g_strdup(value);
1204         } else if (g_str_equal(key, "WiFi.Phase2") == TRUE) {
1205                 g_free(network->wifi.phase2_auth);
1206                 network->wifi.phase2_auth = g_strdup(value);
1207         }
1208
1209         err = connman_element_set_string(&network->element, key, value);
1210         if (err < 0)
1211                 return err;
1212
1213         if (network->driver == NULL)
1214                 return 0;
1215
1216         if (network->driver->setup)
1217                 return network->driver->setup(network, key);
1218
1219         return 0;
1220 }
1221
1222 /**
1223  * connman_network_get_string:
1224  * @network: network structure
1225  * @key: unique identifier
1226  *
1227  * Get string value for specific key
1228  */
1229 const char *connman_network_get_string(struct connman_network *network,
1230                                                         const char *key)
1231 {
1232         DBG("network %p key %s", network, key);
1233
1234         if (g_str_equal(key, "Address") == TRUE)
1235                 return network->address;
1236         else if (g_str_equal(key, "Name") == TRUE)
1237                 return network->name;
1238         else if (g_str_equal(key, "Node") == TRUE)
1239                 return network->node;
1240         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
1241                 return network->wifi.mode;
1242         else if (g_str_equal(key, "WiFi.Security") == TRUE)
1243                 return network->wifi.security;
1244         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
1245                 return network->wifi.passphrase;
1246         else if (g_str_equal(key, "WiFi.EAP") == TRUE)
1247                 return network->wifi.eap;
1248         else if (g_str_equal(key, "WiFi.Identity") == TRUE)
1249                 return network->wifi.identity;
1250         else if (g_str_equal(key, "WiFi.CACertFile") == TRUE)
1251                 return network->wifi.ca_cert_path;
1252         else if (g_str_equal(key, "WiFi.ClientCertFile") == TRUE)
1253                 return network->wifi.client_cert_path;
1254         else if (g_str_equal(key, "WiFi.PrivateKeyFile") == TRUE)
1255                 return network->wifi.private_key_path;
1256         else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase") == TRUE)
1257                 return network->wifi.private_key_passphrase;
1258         else if (g_str_equal(key, "WiFi.Phase2") == TRUE)
1259                 return network->wifi.phase2_auth;
1260
1261         return connman_element_get_string(&network->element, key);
1262 }
1263
1264 /**
1265  * connman_network_set_passphrase:
1266  * @network: network structure
1267  * @passphrase: network passphrase
1268  *
1269  * Set network passphrase.
1270  * If the network is linked to a service, the latter gets his passphrase
1271  * set as well.
1272  */
1273 int connman_network_set_passphrase(struct connman_network *network,
1274                                                 const char* passphrase)
1275 {
1276         struct connman_service *service;
1277
1278         service = __connman_service_lookup_from_network(network);
1279         if (service == NULL) {
1280                 connman_network_set_string(network, "WiFi.Passphrase",
1281                                                 passphrase);
1282
1283                 return 0;
1284         }
1285
1286         __connman_service_set_passphrase(service, passphrase);
1287
1288         return 0;
1289 }
1290
1291
1292 /**
1293  * connman_network_set_bool:
1294  * @network: network structure
1295  * @key: unique identifier
1296  * @value: boolean value
1297  *
1298  * Set boolean value for specific key
1299  */
1300 int connman_network_set_bool(struct connman_network *network,
1301                                         const char *key, connman_bool_t value)
1302 {
1303         DBG("network %p key %s value %d", network, key, value);
1304
1305         if (g_strcmp0(key, "Roaming") == 0)
1306                 return connman_network_set_roaming(network, value);
1307
1308         return connman_element_set_bool(&network->element, key, value);
1309 }
1310
1311 /**
1312  * connman_network_get_bool:
1313  * @network: network structure
1314  * @key: unique identifier
1315  *
1316  * Get boolean value for specific key
1317  */
1318 connman_bool_t connman_network_get_bool(struct connman_network *network,
1319                                                         const char *key)
1320 {
1321         DBG("network %p key %s", network, key);
1322
1323         if (g_str_equal(key, "Roaming") == TRUE)
1324                 return network->roaming;
1325
1326         return connman_element_get_bool(&network->element, key);
1327 }
1328
1329 /**
1330  * connman_network_set_uint8:
1331  * @network: network structure
1332  * @key: unique identifier
1333  * @value: integer value
1334  *
1335  * Set integer value for specific key
1336  */
1337 int connman_network_set_uint8(struct connman_network *network,
1338                                         const char *key, connman_uint8_t value)
1339 {
1340         DBG("network %p key %s value %d", network, key, value);
1341
1342         if (g_strcmp0(key, "Strength") == 0)
1343                 return connman_network_set_strength(network, value);
1344
1345         return connman_element_set_uint8(&network->element, key, value);
1346 }
1347
1348 /**
1349  * connman_network_get_uint8:
1350  * @network: network structure
1351  * @key: unique identifier
1352  *
1353  * Get integer value for specific key
1354  */
1355 connman_uint8_t connman_network_get_uint8(struct connman_network *network,
1356                                                         const char *key)
1357 {
1358         DBG("network %p key %s", network, key);
1359
1360         if (g_str_equal(key, "Strength") == TRUE)
1361                 return network->strength;
1362
1363         return connman_element_get_uint8(&network->element, key);
1364 }
1365
1366 /**
1367  * connman_network_set_uint16:
1368  * @network: network structure
1369  * @key: unique identifier
1370  * @value: integer value
1371  *
1372  * Set integer value for specific key
1373  */
1374 int connman_network_set_uint16(struct connman_network *network,
1375                                 const char *key, connman_uint16_t value)
1376 {
1377         DBG("network %p key %s value %d", network, key, value);
1378
1379         if (g_str_equal(key, "Frequency") == TRUE)
1380                 network->frequency = value;
1381         else if (g_str_equal(key, "WiFi.Channel") == TRUE)
1382                 network->wifi.channel = value;
1383
1384         return -EINVAL;
1385 }
1386
1387 /**
1388  * connman_network_get_uint16:
1389  * @network: network structure
1390  * @key: unique identifier
1391  *
1392  * Get integer value for specific key
1393  */
1394 connman_uint16_t connman_network_get_uint16(struct connman_network *network,
1395                                                         const char *key)
1396 {
1397         DBG("network %p key %s", network, key);
1398
1399         if (g_str_equal(key, "Frequency") == TRUE)
1400                 return network->frequency;
1401         else if (g_str_equal(key, "WiFi.Channel") == TRUE)
1402                 return network->wifi.channel;
1403
1404         return 0;
1405 }
1406
1407 /**
1408  * connman_network_set_blob:
1409  * @network: network structure
1410  * @key: unique identifier
1411  * @data: blob data
1412  * @size: blob size
1413  *
1414  * Set binary blob value for specific key
1415  */
1416 int connman_network_set_blob(struct connman_network *network,
1417                         const char *key, const void *data, unsigned int size)
1418 {
1419         DBG("network %p key %s size %d", network, key, size);
1420
1421         if (g_strcmp0(key, "Address") == 0)
1422                 return connman_network_set_address(network, data, size);
1423
1424         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1425                 g_free(network->wifi.ssid);
1426                 network->wifi.ssid = g_try_malloc(size);
1427                 if (network->wifi.ssid != NULL) {
1428                         memcpy(network->wifi.ssid, data, size);
1429                         network->wifi.ssid_len = size;
1430                 } else
1431                         network->wifi.ssid_len = 0;
1432         }
1433
1434         return connman_element_set_blob(&network->element, key, data, size);
1435 }
1436
1437 /**
1438  * connman_network_get_blob:
1439  * @network: network structure
1440  * @key: unique identifier
1441  * @size: pointer to blob size
1442  *
1443  * Get binary blob value for specific key
1444  */
1445 const void *connman_network_get_blob(struct connman_network *network,
1446                                         const char *key, unsigned int *size)
1447 {
1448         DBG("network %p key %s", network, key);
1449
1450         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1451                 if (size != NULL)
1452                         *size = network->wifi.ssid_len;
1453                 return network->wifi.ssid;
1454         }
1455
1456         return connman_element_get_blob(&network->element, key, size);
1457 }
1458
1459 void __connman_network_set_device(struct connman_network *network,
1460                                         struct connman_device *device)
1461 {
1462         network->device = device;
1463 }
1464
1465 /**
1466  * connman_network_get_device:
1467  * @network: network structure
1468  *
1469  * Get parent device of network
1470  */
1471 struct connman_device *connman_network_get_device(struct connman_network *network)
1472 {
1473         return network->device;
1474 }
1475
1476 /**
1477  * connman_network_get_data:
1478  * @network: network structure
1479  *
1480  * Get private network data pointer
1481  */
1482 void *connman_network_get_data(struct connman_network *network)
1483 {
1484         return network->driver_data;
1485 }
1486
1487 /**
1488  * connman_network_set_data:
1489  * @network: network structure
1490  * @data: data pointer
1491  *
1492  * Set private network data pointer
1493  */
1494 void connman_network_set_data(struct connman_network *network, void *data)
1495 {
1496         network->driver_data = data;
1497 }
1498
1499 void connman_network_update(struct connman_network *network)
1500 {
1501         switch (network->type) {
1502         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1503         case CONNMAN_NETWORK_TYPE_VENDOR:
1504                 return;
1505         case CONNMAN_NETWORK_TYPE_ETHERNET:
1506         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1507         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1508         case CONNMAN_NETWORK_TYPE_CELLULAR:
1509         case CONNMAN_NETWORK_TYPE_WIFI:
1510         case CONNMAN_NETWORK_TYPE_WIMAX:
1511                 break;
1512         }
1513
1514         if (network->group != NULL)
1515                 __connman_service_update_from_network(network);
1516
1517         return;
1518 }
1519
1520 static gboolean match_driver(struct connman_network *network,
1521                                         struct connman_network_driver *driver)
1522 {
1523         if (network->type == driver->type ||
1524                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
1525                 return TRUE;
1526
1527         return FALSE;
1528 }
1529
1530 static int network_probe(struct connman_element *element)
1531 {
1532         struct connman_network *network = element->network;
1533         GSList *list;
1534
1535         DBG("element %p name %s", element, element->name);
1536
1537         if (network == NULL)
1538                 return -ENODEV;
1539
1540         for (list = driver_list; list; list = list->next) {
1541                 struct connman_network_driver *driver = list->data;
1542
1543                 if (match_driver(network, driver) == FALSE)
1544                         continue;
1545
1546                 DBG("driver %p name %s", driver, driver->name);
1547
1548                 if (driver->probe(network) == 0) {
1549                         network->driver = driver;
1550                         break;
1551                 }
1552         }
1553
1554         if (network->driver == NULL)
1555                 return -ENODEV;
1556
1557         switch (network->type) {
1558         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1559         case CONNMAN_NETWORK_TYPE_VENDOR:
1560                 break;
1561         case CONNMAN_NETWORK_TYPE_ETHERNET:
1562         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1563         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1564         case CONNMAN_NETWORK_TYPE_CELLULAR:
1565         case CONNMAN_NETWORK_TYPE_WIFI:
1566         case CONNMAN_NETWORK_TYPE_WIMAX:
1567                 if (network->group != NULL)
1568                         __connman_profile_add_network(network);
1569                 break;
1570         }
1571
1572         return 0;
1573 }
1574
1575 static void network_remove(struct connman_element *element)
1576 {
1577         struct connman_network *network = element->network;
1578
1579         DBG("element %p name %s", element, element->name);
1580
1581         if (network == NULL)
1582                 return;
1583
1584         if (network->driver == NULL)
1585                 return;
1586
1587         switch (network->type) {
1588         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1589         case CONNMAN_NETWORK_TYPE_VENDOR:
1590                 break;
1591         case CONNMAN_NETWORK_TYPE_ETHERNET:
1592         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1593         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1594         case CONNMAN_NETWORK_TYPE_CELLULAR:
1595         case CONNMAN_NETWORK_TYPE_WIFI:
1596         case CONNMAN_NETWORK_TYPE_WIMAX:
1597                 if (network->group != NULL) {
1598                         __connman_profile_remove_network(network);
1599
1600                         g_free(network->group);
1601                         network->group = NULL;
1602                 }
1603                 break;
1604         }
1605
1606         if (network->driver->remove)
1607                 network->driver->remove(network);
1608 }
1609
1610 static void network_change(struct connman_element *element)
1611 {
1612         struct connman_network *network = element->network;
1613
1614         DBG("element %p name %s", element, element->name);
1615
1616         if (element->state != CONNMAN_ELEMENT_STATE_ERROR)
1617                 return;
1618
1619         if (element->error != CONNMAN_ELEMENT_ERROR_DHCP_FAILED)
1620                 return;
1621
1622         if (network->connected == FALSE)
1623                 return;
1624
1625         connman_element_unregister_children(element);
1626
1627         connman_device_set_disconnected(network->device, TRUE);
1628
1629         if (network->driver && network->driver->disconnect) {
1630                 network->driver->disconnect(network);
1631                 return;
1632         }
1633
1634         network->connected = FALSE;
1635 }
1636
1637 static struct connman_driver network_driver = {
1638         .name           = "network",
1639         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
1640         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1641         .probe          = network_probe,
1642         .remove         = network_remove,
1643         .change         = network_change,
1644 };
1645
1646 int __connman_network_init(void)
1647 {
1648         DBG("");
1649
1650         return connman_driver_register(&network_driver);
1651 }
1652
1653 void __connman_network_cleanup(void)
1654 {
1655         DBG("");
1656
1657         connman_driver_unregister(&network_driver);
1658 }