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