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