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