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