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