provider: Set service pointer for provider_set_nameservers
[platform/upstream/connman.git] / src / provider.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 <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 static DBusConnection *connection = NULL;
34
35 static GHashTable *provider_hash = NULL;
36
37 static GSList *driver_list = NULL;
38
39 struct connman_route {
40         int family;
41         char *host;
42         char *netmask;
43         char *gateway;
44 };
45
46 struct connman_provider {
47         struct connman_element element;
48         struct connman_service *vpn_service;
49         char *identifier;
50         char *name;
51         char *type;
52         char *host;
53         char *dns;
54         char *domain;
55         GSList *route_list;
56         struct connman_provider_driver *driver;
57         void *driver_data;
58 };
59
60 void __connman_provider_append_properties(struct connman_provider *provider,
61                                                         DBusMessageIter *iter)
62 {
63         if (provider->host != NULL)
64                 connman_dbus_dict_append_basic(iter, "Host",
65                                         DBUS_TYPE_STRING, &provider->host);
66
67         if (provider->domain != NULL)
68                 connman_dbus_dict_append_basic(iter, "Domain",
69                                         DBUS_TYPE_STRING, &provider->domain);
70
71         if (provider->type != NULL)
72                 connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING,
73                                                  &provider->type);
74 }
75
76 static struct connman_provider *connman_provider_lookup(const char *identifier)
77 {
78         struct connman_provider *provider = NULL;
79
80         provider = g_hash_table_lookup(provider_hash, identifier);
81
82         return provider;
83 }
84
85 static int connman_provider_setup_vpn_ipv4(struct connman_provider *provider,
86                                                 struct connman_element *element)
87 {
88         if (element == NULL || provider == NULL)
89                 return -EINVAL;
90
91         DBG("set vpn type %d", element->type);
92
93         g_free(element->ipv4.address);
94         element->ipv4.address = g_strdup(provider->element.ipv4.address);
95
96         g_free(element->ipv4.peer);
97         element->ipv4.peer = g_strdup(provider->element.ipv4.peer);
98
99         g_free(element->ipv4.netmask);
100         element->ipv4.netmask = g_strdup(provider->element.ipv4.netmask);
101
102         g_free(element->ipv4.gateway);
103         element->ipv4.gateway = g_strdup(provider->element.ipv4.gateway);
104
105         g_free(element->ipv4.broadcast);
106         element->ipv4.broadcast = g_strdup(provider->element.ipv4.broadcast);
107
108         g_free(element->ipv4.pac);
109         element->ipv4.pac = g_strdup(provider->element.ipv4.pac);
110
111         return connman_element_register(element, &provider->element);
112 }
113
114 struct connman_provider *connman_provider_ref(struct connman_provider *provider)
115 {
116         DBG("provider %p", provider);
117
118         if (connman_element_ref(&provider->element) == NULL)
119                 return NULL;
120
121         return provider;
122 }
123
124 void connman_provider_unref(struct connman_provider *provider)
125 {
126         DBG("provider %p", provider);
127
128         connman_element_unref(&provider->element);
129 }
130
131 static gboolean match_driver(struct connman_provider *provider,
132                                 struct connman_provider_driver *driver)
133 {
134         if (g_strcmp0(driver->name, provider->type) == 0)
135                 return TRUE;
136
137         return FALSE;
138 }
139
140 static int provider_probe(struct connman_provider *provider)
141 {
142         GSList *list;
143
144         DBG("provider %p name %s", provider, provider->name);
145
146         if (provider->driver != NULL)
147                 return -EALREADY;
148
149         for (list = driver_list; list; list = list->next) {
150                 struct connman_provider_driver *driver = list->data;
151
152                 if (match_driver(provider, driver) == FALSE)
153                         continue;
154
155                 DBG("driver %p name %s", driver, driver->name);
156
157                 if (driver->probe != NULL && driver->probe(provider) == 0) {
158                         provider->driver = driver;
159                         break;
160                 }
161         }
162
163         if (provider->driver == NULL)
164                 return -ENODEV;
165
166         return 0;
167 }
168
169 int __connman_provider_disconnect(struct connman_provider *provider)
170 {
171         int err;
172
173         DBG("provider %p", provider);
174
175         if (provider->driver != NULL && provider->driver->disconnect != NULL)
176                 err = provider->driver->disconnect(provider);
177         else
178                 return -EOPNOTSUPP;
179
180         if (provider->vpn_service != NULL)
181                 __connman_service_indicate_state(provider->vpn_service,
182                                         CONNMAN_SERVICE_STATE_DISCONNECT);
183         if (err < 0) {
184                 if (err != -EINPROGRESS)
185                         return err;
186
187                 return -EINPROGRESS;
188         }
189
190         return 0;
191 }
192
193 int __connman_provider_connect(struct connman_provider *provider)
194 {
195         int err;
196
197         DBG("provider %p", provider);
198
199         g_free(provider->element.ipv4.address);
200         g_free(provider->element.ipv4.peer);
201         g_free(provider->element.ipv4.netmask);
202         g_free(provider->element.ipv4.gateway);
203         g_free(provider->element.ipv4.broadcast);
204         g_free(provider->element.ipv4.pac);
205
206         provider->element.ipv4.address = NULL;
207         provider->element.ipv4.peer = NULL;
208         provider->element.ipv4.netmask = NULL;
209         provider->element.ipv4.gateway = NULL;
210         provider->element.ipv4.broadcast = NULL;
211         provider->element.ipv4.pac = NULL;
212
213         if (provider->driver != NULL && provider->driver->connect != NULL)
214                 err = provider->driver->connect(provider);
215         else
216                 return -EOPNOTSUPP;
217
218         if (err < 0) {
219                 if (err != -EINPROGRESS)
220                         return err;
221
222                 __connman_service_indicate_state(provider->vpn_service,
223                                         CONNMAN_SERVICE_STATE_ASSOCIATION);
224                 return -EINPROGRESS;
225         }
226
227         return 0;
228 }
229
230 int __connman_provider_remove(const char *path)
231 {
232         struct connman_provider *provider;
233         GHashTableIter iter;
234         gpointer value, key;
235
236         DBG("path %s", path);
237
238         g_hash_table_iter_init(&iter, provider_hash);
239         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
240                 const char *srv_path;
241                 provider = value;
242
243                 if (provider->vpn_service == NULL)
244                         continue;
245
246                 srv_path = __connman_service_get_path(provider->vpn_service);
247
248                 if (g_strcmp0(srv_path, path) == 0) {
249                         DBG("Removing VPN %s", provider->identifier);
250                         g_hash_table_remove(provider_hash,
251                                                 provider->identifier);
252                         return 0;
253                 }
254         }
255
256         return -ENXIO;
257 }
258
259 static void provider_set_nameservers(struct connman_provider *provider)
260 {
261         struct connman_service *service = provider->vpn_service;
262
263         char *nameservers = NULL, *name = NULL;
264         const char *value;
265         char *second_ns;
266
267         if (service == NULL)
268                 return;
269
270         if (provider->dns == NULL)
271                 return;
272
273         name = connman_inet_ifname(provider->element.index);
274
275         nameservers = g_strdup(provider->dns);
276         value = nameservers;
277         second_ns = strchr(value, ' ');
278         if (second_ns)
279                 *(second_ns++) = 0;
280         __connman_service_append_nameserver(service, value);
281         value = second_ns;
282
283         while (value) {
284                 char *next = strchr(value, ' ');
285                 if (next)
286                         *(next++) = 0;
287
288                 connman_resolver_append(name, provider->domain, value);
289                 value = next;
290         }
291
292         g_free(nameservers);
293         g_free(name);
294 }
295
296 static int set_connected(struct connman_provider *provider,
297                                         connman_bool_t connected)
298 {
299         struct connman_service *service = provider->vpn_service;
300
301         if (service == NULL)
302                 return -ENODEV;
303
304         if (connected == TRUE) {
305                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
306                 struct connman_element *element;
307                 GSList *list;
308                 int err;
309
310                 __connman_service_indicate_state(provider->vpn_service,
311                                         CONNMAN_SERVICE_STATE_CONFIGURATION);
312
313                 type = CONNMAN_ELEMENT_TYPE_IPV4;
314
315                 element = connman_element_create(NULL);
316                 if (element == NULL)
317                         return -ENOMEM;
318
319                 element->type  = type;
320                 element->index = provider->element.index;
321
322                 err = connman_provider_setup_vpn_ipv4(provider, element);
323                 if (err < 0) {
324                         connman_element_unref(element);
325
326                         __connman_service_indicate_state(service,
327                                                 CONNMAN_SERVICE_STATE_FAILURE);
328
329                         return err;
330                 }
331
332                 __connman_service_indicate_state(service,
333                                                 CONNMAN_SERVICE_STATE_READY);
334
335                 __connman_service_set_domainname(service, provider->domain);
336
337                 provider_set_nameservers(provider);
338
339                 for (list = provider->route_list; list; list = list->next) {
340                         struct connman_route *route = list->data;
341                         int index = provider->element.index;
342
343                         if (route->family == AF_INET6) {
344                                 unsigned char prefix_len = atoi(route->netmask);
345
346                                 connman_inet_add_ipv6_network_route(index,
347                                                                 route->host,
348                                                                 route->gateway,
349                                                                 prefix_len);
350                         } else {
351                                 connman_inet_add_network_route(index,
352                                                         route->host,
353                                                         route->gateway,
354                                                         route->netmask);
355                         }
356                 }
357         } else {
358                 connman_element_unregister_children(&provider->element);
359                 __connman_service_indicate_state(service,
360                                                 CONNMAN_SERVICE_STATE_IDLE);
361         }
362
363         return 0;
364 }
365
366 int connman_provider_set_state(struct connman_provider *provider,
367                                         enum connman_provider_state state)
368 {
369         if (provider == NULL || provider->vpn_service == NULL)
370                 return -EINVAL;
371
372         switch (state) {
373         case CONNMAN_PROVIDER_STATE_UNKNOWN:
374                 return -EINVAL;
375         case CONNMAN_PROVIDER_STATE_IDLE:
376                 return set_connected(provider, FALSE);
377         case CONNMAN_PROVIDER_STATE_CONNECT:
378                 return __connman_service_indicate_state(provider->vpn_service,
379                                         CONNMAN_SERVICE_STATE_ASSOCIATION);
380         case CONNMAN_PROVIDER_STATE_READY:
381                 return set_connected(provider, TRUE);
382         case CONNMAN_PROVIDER_STATE_DISCONNECT:
383                 return __connman_service_indicate_state(provider->vpn_service,
384                                         CONNMAN_SERVICE_STATE_DISCONNECT);
385         case CONNMAN_PROVIDER_STATE_FAILURE:
386                 return __connman_service_indicate_state(provider->vpn_service,
387                                         CONNMAN_SERVICE_STATE_FAILURE);
388         }
389
390         return -EINVAL;
391 }
392
393 static void unregister_provider(gpointer data)
394 {
395         struct connman_provider *provider = data;
396         struct connman_service *service = provider->vpn_service;
397
398         DBG("provider %p", provider);
399
400         provider->vpn_service = NULL;
401         __connman_service_put(service);
402
403         connman_element_unregister(&provider->element);
404         connman_provider_unref(provider);
405 }
406
407 static void provider_destruct(struct connman_element *element)
408 {
409         struct connman_provider *provider = element->private;
410         GSList *list;
411
412         DBG("provider %p", provider);
413
414         g_free(provider->name);
415         g_free(provider->type);
416         g_free(provider->domain);
417         g_free(provider->identifier);
418         g_free(provider->dns);
419
420         for (list = provider->route_list; list; list = list->next) {
421                 struct connman_route *route = list->data;
422
423                 g_free(route->host);
424                 g_free(route->netmask);
425                 g_free(route->gateway);
426         }
427         g_slist_free(provider->route_list);
428 }
429
430 static void provider_initialize(struct connman_provider *provider)
431 {
432         DBG("provider %p", provider);
433
434         __connman_element_initialize(&provider->element);
435
436         provider->element.private = provider;
437         provider->element.destruct = provider_destruct;
438
439         provider->element.ipv4.address = NULL;
440         provider->element.ipv4.netmask = NULL;
441         provider->element.ipv4.gateway = NULL;
442         provider->element.ipv4.broadcast = NULL;
443         provider->element.ipv4.pac = NULL;
444
445         provider->name = NULL;
446         provider->type = NULL;
447         provider->dns = NULL;
448         provider->domain = NULL;
449         provider->identifier = NULL;
450         provider->route_list = NULL;
451 }
452
453 static struct connman_provider *connman_provider_new(void)
454 {
455         struct connman_provider *provider;
456
457         provider = g_try_new0(struct connman_provider, 1);
458         if (provider == NULL)
459                 return NULL;
460
461         DBG("provider %p", provider);
462         provider_initialize(provider);
463
464         return provider;
465 }
466
467 static struct connman_provider *connman_provider_get(const char *identifier)
468 {
469         struct connman_provider *provider;
470
471         provider = g_hash_table_lookup(provider_hash, identifier);
472         if (provider != NULL)
473                 return provider;
474
475         provider = connman_provider_new();
476         if (provider == NULL)
477                 return NULL;
478
479         DBG("provider %p", provider);
480
481         provider->identifier = g_strdup(identifier);
482
483         g_hash_table_insert(provider_hash, provider->identifier, provider);
484
485         provider->element.name = g_strdup(identifier);
486         connman_element_register(&provider->element, NULL);
487
488         return provider;
489 }
490
491 static void provider_dbus_ident(char *ident)
492 {
493         int i, len = strlen(ident);
494
495         for (i = 0; i < len; i++) {
496                 if (ident[i] >= '0' && ident[i] <= '9')
497                         continue;
498                 if (ident[i] >= 'a' && ident[i] <= 'z')
499                         continue;
500                 if (ident[i] >= 'A' && ident[i] <= 'Z')
501                         continue;
502                 ident[i] = '_';
503         }
504 }
505
506 int __connman_provider_create_and_connect(DBusMessage *msg)
507 {
508         struct connman_provider *provider;
509         DBusMessageIter iter, array;
510         const char *type = NULL, *name = NULL, *service_path = NULL;
511         const char *host = NULL, *domain = NULL;
512         char *ident;
513         gboolean created = FALSE;
514         int err;
515
516         dbus_message_iter_init(msg, &iter);
517         dbus_message_iter_recurse(&iter, &array);
518
519         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
520                 DBusMessageIter entry, value;
521                 const char *key;
522
523                 dbus_message_iter_recurse(&array, &entry);
524                 dbus_message_iter_get_basic(&entry, &key);
525
526                 dbus_message_iter_next(&entry);
527                 dbus_message_iter_recurse(&entry, &value);
528
529                 switch (dbus_message_iter_get_arg_type(&value)) {
530                 case DBUS_TYPE_STRING:
531                         if (g_str_equal(key, "Type") == TRUE)
532                                 dbus_message_iter_get_basic(&value, &type);
533                         else if (g_str_equal(key, "Name") == TRUE)
534                                 dbus_message_iter_get_basic(&value, &name);
535                         else if (g_str_equal(key, "Host") == TRUE)
536                                 dbus_message_iter_get_basic(&value, &host);
537                         else if (g_str_equal(key, "VPN.Domain") == TRUE)
538                                 dbus_message_iter_get_basic(&value, &domain);
539                         break;
540                 }
541
542                 dbus_message_iter_next(&array);
543         }
544
545         if (host == NULL || domain == NULL) {
546                 err = -EINVAL;
547                 goto failed;
548         }
549
550         DBG("Type %s name %s", type, name);
551
552         if (type == NULL || name == NULL) {
553                 err = -EOPNOTSUPP;
554                 goto failed;
555         }
556
557         ident = g_strdup_printf("%s_%s", host, domain);
558         provider_dbus_ident(ident);
559
560         DBG("ident %s", ident);
561
562         provider = connman_provider_lookup(ident);
563
564         if (provider == NULL) {
565                 created = TRUE;
566                 provider = connman_provider_get(ident);
567                 if (provider) {
568                         provider->host = g_strdup(host);
569                         provider->domain = g_strdup(domain);
570                         provider->name = g_strdup(name);
571                         provider->type = g_strdup(type);
572                 }
573         }
574
575         if (provider == NULL) {
576                 DBG("can not create provider");
577                 err = -EOPNOTSUPP;
578                 goto failed;
579         }
580         dbus_message_iter_init(msg, &iter);
581         dbus_message_iter_recurse(&iter, &array);
582
583         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
584                 DBusMessageIter entry, value;
585                 const char *key, *str;
586
587                 dbus_message_iter_recurse(&array, &entry);
588                 dbus_message_iter_get_basic(&entry, &key);
589
590                 dbus_message_iter_next(&entry);
591                 dbus_message_iter_recurse(&entry, &value);
592
593                 switch (dbus_message_iter_get_arg_type(&value)) {
594                 case DBUS_TYPE_STRING:
595                         dbus_message_iter_get_basic(&value, &str);
596                         connman_provider_set_string(provider, key, str);
597                         break;
598                 }
599
600                 dbus_message_iter_next(&array);
601         }
602
603         g_free(ident);
604
605         if (provider == NULL) {
606                 err = -EOPNOTSUPP;
607                 goto failed;
608         }
609
610         if (created == TRUE)
611                 provider_probe(provider);
612
613         if (provider->vpn_service == NULL)
614                 provider->vpn_service =
615                         __connman_service_create_from_provider(provider);
616         if (provider->vpn_service == NULL) {
617                 err = -EOPNOTSUPP;
618                 goto failed;
619         }
620
621         err = __connman_service_connect(provider->vpn_service);
622         if (err < 0 && err != -EINPROGRESS)
623                 goto failed;
624
625         service_path = __connman_service_get_path(provider->vpn_service);
626         g_dbus_send_reply(connection, msg,
627                                 DBUS_TYPE_OBJECT_PATH, &service_path,
628                                                         DBUS_TYPE_INVALID);
629         return 0;
630
631 failed:
632         if (provider != NULL && created == TRUE) {
633                 DBG("can not connect delete provider");
634                 connman_provider_unref(provider);
635
636                 if (provider->vpn_service != NULL) {
637                         __connman_service_put(provider->vpn_service);
638                         provider->vpn_service = NULL;
639                 }
640         }
641
642         return err;
643 }
644
645 const char * __connman_provider_get_ident(struct connman_provider *provider)
646 {
647         if (provider == NULL)
648                 return NULL;
649
650         return provider->identifier;
651 }
652
653 int connman_provider_set_string(struct connman_provider *provider,
654                                         const char *key, const char *value)
655 {
656         DBG("provider %p key %s value %s", provider, key, value);
657
658         if (g_str_equal(key, "Type") == TRUE) {
659                 g_free(provider->type);
660                 provider->type = g_strdup(value);
661         } else if (g_str_equal(key, "Name") == TRUE) {
662                 g_free(provider->name);
663                 provider->name = g_strdup(value);
664         } else if (g_str_equal(key, "Gateway") == TRUE) {
665                 g_free(provider->element.ipv4.gateway);
666                 provider->element.ipv4.gateway = g_strdup(value);
667         } else if (g_str_equal(key, "Address") == TRUE) {
668                 g_free(provider->element.ipv4.address);
669                 provider->element.ipv4.address = g_strdup(value);
670         } else if (g_str_equal(key, "Peer") == TRUE) {
671                 g_free(provider->element.ipv4.peer);
672                 provider->element.ipv4.peer = g_strdup(value);
673         } else if (g_str_equal(key, "Netmask") == TRUE) {
674                 g_free(provider->element.ipv4.netmask);
675                 provider->element.ipv4.netmask = g_strdup(value);
676         } else if (g_str_equal(key, "PAC") == TRUE) {
677                 g_free(provider->element.ipv4.pac);
678                 provider->element.ipv4.pac = g_strdup(value);
679                 __connman_service_set_proxy_autoconfig(provider->vpn_service,
680                                                                         value);
681         } else if (g_str_equal(key, "DNS") == TRUE) {
682                 g_free(provider->dns);
683                 provider->dns = g_strdup(value);
684         } else if (g_str_equal(key, "Domain") == TRUE) {
685                 g_free(provider->domain);
686                 provider->domain = g_strdup(value);
687         }
688
689         return connman_element_set_string(&provider->element, key, value);
690 }
691
692 const char *connman_provider_get_string(struct connman_provider *provider,
693                                                         const char *key)
694 {
695         DBG("provider %p key %s", provider, key);
696
697         if (g_str_equal(key, "Type") == TRUE)
698                 return provider->type;
699         else if (g_str_equal(key, "Name") == TRUE)
700                 return provider->name;
701
702         return connman_element_get_string(&provider->element, key);
703 }
704
705 void *connman_provider_get_data(struct connman_provider *provider)
706 {
707         return provider->driver_data;
708 }
709
710 void connman_provider_set_data(struct connman_provider *provider, void *data)
711 {
712         provider->driver_data = data;
713 }
714
715 void connman_provider_set_index(struct connman_provider *provider, int index)
716 {
717         struct connman_service *service = provider->vpn_service;
718         struct connman_ipconfig *ipconfig;
719
720         DBG("");
721
722         if (service == NULL)
723                 return;
724
725         ipconfig = __connman_service_get_ip4config(service);
726
727         if (ipconfig == NULL) {
728                 __connman_service_create_ip4config(service, index);
729
730                 ipconfig = __connman_service_get_ip4config(service);
731                 if (ipconfig == NULL) {
732                         DBG("Couldnt create ipconfig");
733                         goto done;
734                 }
735         }
736
737         connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_FIXED);
738         __connman_ipconfig_set_index(ipconfig, index);
739
740
741         ipconfig = __connman_service_get_ip6config(service);
742
743         if (ipconfig == NULL) {
744                 __connman_service_create_ip6config(service, index);
745
746                 ipconfig = __connman_service_get_ip6config(service);
747                 if (ipconfig == NULL) {
748                         DBG("Couldnt create ipconfig for IPv6");
749                         goto done;
750                 }
751         }
752
753         connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_OFF);
754         __connman_ipconfig_set_index(ipconfig, index);
755
756 done:
757         provider->element.index = index;
758 }
759
760 int connman_provider_get_index(struct connman_provider *provider)
761 {
762         return provider->element.index;
763 }
764
765 int connman_provider_append_route(struct connman_provider *provider,
766                                         int family, const char *host,
767                                         const char *netmask,
768                                         const char *gateway)
769 {
770         struct connman_route *route;
771
772         if (family != AF_INET && family != AF_INET6)
773                 return -EINVAL;
774
775         route = g_try_new0(struct connman_route, 1);
776         if (route == NULL)
777                 return -ENOMEM;
778
779         route->family = family;
780         route->host = g_strdup(host);
781         route->netmask = g_strdup(netmask);
782         route->gateway = g_strdup(gateway);
783
784         provider->route_list = g_slist_append(provider->route_list, route);
785
786         return TRUE;
787 }
788
789 const char *connman_provider_get_driver_name(struct connman_provider *provider)
790 {
791         return provider->driver->name;
792 }
793
794 static gint compare_priority(gconstpointer a, gconstpointer b)
795 {
796         return 0;
797 }
798
799 static void clean_provider(gpointer key, gpointer value, gpointer user_data)
800 {
801         struct connman_provider *provider = value;
802
803         if (provider->driver != NULL && provider->driver->remove)
804                 provider->driver->remove(provider);
805 }
806
807 int connman_provider_driver_register(struct connman_provider_driver *driver)
808 {
809         DBG("driver %p name %s", driver, driver->name);
810
811         driver_list = g_slist_insert_sorted(driver_list, driver,
812                                                         compare_priority);
813         return 0;
814 }
815
816 void connman_provider_driver_unregister(struct connman_provider_driver *driver)
817 {
818         DBG("driver %p name %s", driver, driver->name);
819
820         driver_list = g_slist_remove(driver_list, driver);
821 }
822
823 static void provider_remove(gpointer key, gpointer value,
824                                                 gpointer user_data)
825 {
826         struct connman_provider *provider = value;
827
828         g_hash_table_remove(provider_hash, provider->identifier);
829 }
830
831 static void provider_offline_mode(connman_bool_t enabled)
832 {
833         DBG("enabled %d", enabled);
834
835         if (enabled == TRUE)
836                 g_hash_table_foreach(provider_hash, provider_remove, NULL);
837
838 }
839
840 static struct connman_notifier provider_notifier = {
841         .name                   = "provider",
842         .offline_mode           = provider_offline_mode,
843 };
844
845 int __connman_provider_init(void)
846 {
847         int err;
848
849         DBG("");
850
851         connection = connman_dbus_get_connection();
852
853         provider_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
854                                                 NULL, unregister_provider);
855
856         err = connman_notifier_register(&provider_notifier);
857         if (err < 0) {
858                 g_hash_table_destroy(provider_hash);
859                 dbus_connection_unref(connection);
860         }
861
862         return err;
863 }
864
865 void __connman_provider_cleanup(void)
866 {
867         DBG("");
868
869         connman_notifier_unregister(&provider_notifier);
870
871         g_hash_table_foreach(provider_hash, clean_provider, NULL);
872
873         g_hash_table_destroy(provider_hash);
874         provider_hash = NULL;
875
876         dbus_connection_unref(connection);
877 }