Remove the manager Providers property
[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 *name;
43         char *type;
44         char *dns;
45         char *domain;
46         struct connman_provider_driver *driver;
47         void *driver_data;
48 };
49
50 void __connman_provider_append_properties(struct connman_provider *provider,
51                                                         DBusMessageIter *iter)
52 {
53         if (provider->name != NULL)
54                 connman_dbus_dict_append_basic(iter, "Name",
55                                         DBUS_TYPE_STRING, &provider->name);
56
57         if (provider->type != NULL)
58                 connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING,
59                                                  &provider->type);
60 }
61
62 static struct connman_provider *connman_provider_lookup(const char *identifier)
63 {
64         struct connman_provider *provider = NULL;
65
66         provider = g_hash_table_lookup(provider_hash, identifier);
67
68         return provider;
69 }
70
71 static void connman_provider_setup_vpn_ipv4(struct connman_provider *provider,
72                                                 struct connman_element *element)
73 {
74         if (element == NULL || provider == NULL)
75                 return;
76
77         DBG("set vpn type %d", element->type);
78
79         if (provider == NULL)
80                 return;
81
82         g_free(element->ipv4.address);
83         element->ipv4.address = g_strdup(provider->element.ipv4.address);
84
85         g_free(element->ipv4.netmask);
86         element->ipv4.netmask = g_strdup(provider->element.ipv4.netmask);
87
88         g_free(element->ipv4.gateway);
89         element->ipv4.gateway = g_strdup(provider->element.ipv4.gateway);
90
91         g_free(element->ipv4.broadcast);
92         element->ipv4.broadcast = g_strdup(provider->element.ipv4.broadcast);
93
94         g_free(element->ipv4.pac);
95         element->ipv4.pac = g_strdup(provider->element.ipv4.pac);
96
97         DBG("VPN exist");
98 }
99
100 struct connman_provider *connman_provider_ref(struct connman_provider *provider)
101 {
102         DBG("provider %p", provider);
103
104         if (connman_element_ref(&provider->element) == NULL)
105                 return NULL;
106
107         return provider;
108 }
109
110 void connman_provider_unref(struct connman_provider *provider)
111 {
112         DBG("provider %p", provider);
113
114         connman_element_unref(&provider->element);
115 }
116
117 static gboolean match_driver(struct connman_provider *provider,
118                                 struct connman_provider_driver *driver)
119 {
120         if (g_strcmp0(driver->name, provider->type) == 0)
121                 return TRUE;
122
123         return FALSE;
124 }
125
126 static int provider_probe(struct connman_provider *provider)
127 {
128         GSList *list;
129
130         DBG("provider %p name %s", provider, provider->name);
131
132         if (provider->driver != NULL)
133                 return -EALREADY;
134
135         for (list = driver_list; list; list = list->next) {
136                 struct connman_provider_driver *driver = list->data;
137
138                 if (match_driver(provider, driver) == FALSE)
139                         continue;
140
141                 DBG("driver %p name %s", driver, driver->name);
142
143                 if (driver->probe != NULL && driver->probe(provider) == 0) {
144                         provider->driver = driver;
145                         break;
146                 }
147         }
148
149         if (provider->driver == NULL)
150                 return -ENODEV;
151
152         return 0;
153 }
154
155 int __connman_provider_disconnect(struct connman_provider *provider)
156 {
157         int err;
158
159         DBG("provider %p", provider);
160
161         if (provider->driver != NULL && provider->driver->disconnect != NULL)
162                 err = provider->driver->disconnect(provider);
163         else
164                 return -EOPNOTSUPP;
165
166         __connman_service_indicate_state(provider->vpn_service,
167                                         CONNMAN_SERVICE_STATE_DISCONNECT);
168         if (err < 0) {
169                 if (err != -EINPROGRESS)
170                         return err;
171
172                 return -EINPROGRESS;
173         }
174
175         return 0;
176 }
177
178 int __connman_provider_connect(struct connman_provider *provider)
179 {
180         int err;
181
182         DBG("provider %p", provider);
183
184         g_free(provider->element.ipv4.address);
185         g_free(provider->element.ipv4.netmask);
186         g_free(provider->element.ipv4.gateway);
187         g_free(provider->element.ipv4.broadcast);
188         g_free(provider->element.ipv4.pac);
189
190         provider->element.ipv4.address = NULL;
191         provider->element.ipv4.netmask = NULL;
192         provider->element.ipv4.gateway = NULL;
193         provider->element.ipv4.broadcast = NULL;
194         provider->element.ipv4.pac = NULL;
195
196         if (provider->driver != NULL && provider->driver->connect != NULL)
197                 err = provider->driver->connect(provider);
198         else
199                 return -EOPNOTSUPP;
200
201         if (err < 0) {
202                 if (err != -EINPROGRESS)
203                         return err;
204
205                 __connman_service_indicate_state(provider->vpn_service,
206                                         CONNMAN_SERVICE_STATE_ASSOCIATION);
207                 return -EINPROGRESS;
208         }
209
210         return 0;
211 }
212
213 int __connman_provider_remove(const char *path)
214 {
215         struct connman_provider *provider;
216
217         DBG("path %s", path);
218
219         provider = g_hash_table_lookup(provider_hash, path);
220         if (provider == NULL) {
221                 DBG("patch %s not found", path);
222                 return -ENXIO;
223         }
224
225         g_hash_table_remove(provider_hash, path);
226
227         return 0;
228 }
229
230 int connman_provider_set_connected(struct connman_provider *provider,
231                                                 connman_bool_t connected)
232 {
233         if (connected == TRUE) {
234                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
235                 struct connman_element *element;
236
237                 type = CONNMAN_ELEMENT_TYPE_IPV4;
238
239                 element = connman_element_create(NULL);
240                 if (element != NULL) {
241                         element->type  = type;
242                         element->index = provider->element.index;
243
244                         connman_provider_setup_vpn_ipv4(provider, element);
245
246                         if (connman_element_register(element,
247                                         &provider->element) < 0)
248                                 connman_element_unref(element);
249                         else {
250                                 char *nameservers = NULL;
251                                 const char *value;
252                                 char *name = NULL;
253
254                                 DBG("set dns");
255                                 nameservers = g_strdup(provider->dns);
256                                 value = nameservers;
257                                 name = connman_inet_ifname(
258                                                 provider->element.index);
259                                 while (value) {
260                                         char *next = strchr(value, ' ');
261                                         if (next)
262                                                 *(next++) = 0;
263
264                                         connman_resolver_append(name,
265                                                         provider->domain,
266                                                         value);
267                                         value = next;
268                                 }
269                                 DBG("free extra");
270                                 g_free(nameservers);
271                                 g_free(name);
272                         }
273
274                 }
275                 __connman_service_indicate_state(provider->vpn_service,
276                                                 CONNMAN_SERVICE_STATE_READY);
277         } else {
278                 connman_element_unregister_children(&provider->element);
279                 __connman_service_indicate_state(provider->vpn_service,
280                                                 CONNMAN_SERVICE_STATE_IDLE);
281         }
282
283         return 0;
284 }
285
286 static void provider_free(gpointer user_data)
287 {
288         struct connman_provider *provider = user_data;
289
290         DBG("provider %p", provider);
291
292         g_free(provider->name);
293         g_free(provider->type);
294         g_free(provider->domain);
295         g_free(provider->identifier);
296         g_free(provider->dns);
297         __connman_service_put(provider->vpn_service);
298 }
299
300 static void unregister_provider(gpointer data)
301 {
302         struct connman_provider *provider = data;
303
304         DBG("provider %p", provider);
305
306         __connman_provider_disconnect(provider);
307
308         connman_element_unregister(&provider->element);
309         connman_provider_unref(provider);
310 }
311
312 static void provider_destruct(struct connman_element *element)
313 {
314         struct connman_provider *provider = element->private;
315
316         DBG("provider %p", provider);
317
318         provider_free(provider);
319 }
320
321 static void __connman_provider_initialize(struct connman_provider *provider)
322 {
323         DBG("provider %p", provider);
324
325         __connman_element_initialize(&provider->element);
326
327         provider->element.private = provider;
328         provider->element.destruct = provider_destruct;
329
330         provider->element.ipv4.address = NULL;
331         provider->element.ipv4.netmask = NULL;
332         provider->element.ipv4.gateway = NULL;
333         provider->element.ipv4.broadcast = NULL;
334         provider->element.ipv4.pac = NULL;
335
336         provider->name = NULL;
337         provider->type = NULL;
338         provider->dns = NULL;
339         provider->domain = NULL;
340         provider->identifier = NULL;
341 }
342
343 static struct connman_provider *connman_provider_new(void)
344 {
345         struct connman_provider *provider;
346
347         provider = g_try_new0(struct connman_provider, 1);
348         if (provider == NULL)
349                 return NULL;
350
351         DBG("provider %p", provider);
352         __connman_provider_initialize(provider);
353
354         return provider;
355 }
356
357 static int provider_register(struct connman_provider *provider)
358 {
359         DBG("provider %p", provider);
360
361         return 0;
362 }
363
364 static struct connman_provider *connman_provider_get(const char *identifier)
365 {
366         struct connman_provider *provider;
367
368         provider = g_hash_table_lookup(provider_hash, identifier);
369         if (provider != NULL)
370                 return provider;
371
372         provider = connman_provider_new();
373         if (provider == NULL)
374                 return NULL;
375
376         DBG("provider %p", provider);
377
378         provider->identifier = g_strdup(identifier);
379
380         g_hash_table_insert(provider_hash, provider->identifier, provider);
381
382         provider->element.name = g_strdup(identifier);
383         connman_element_register(&provider->element, NULL);
384
385         return provider;
386 }
387
388 static struct connman_provider *connman_provider_create(const char *name)
389 {
390         struct connman_provider *provider;
391
392         provider = connman_provider_get(name);
393
394         if (provider == NULL)
395                 return NULL;
396
397         provider_register(provider);
398
399         return provider;
400 }
401
402 int __connman_provider_create_and_connect(DBusMessage *msg)
403 {
404         struct connman_provider *provider;
405         DBusMessageIter iter, array;
406         const char *type = NULL, *name = NULL, *service_path = NULL;
407         char *ident;
408         gboolean created = FALSE;
409         int err;
410
411         dbus_message_iter_init(msg, &iter);
412         dbus_message_iter_recurse(&iter, &array);
413
414         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
415                 DBusMessageIter entry, value;
416                 const char *key;
417
418                 dbus_message_iter_recurse(&array, &entry);
419                 dbus_message_iter_get_basic(&entry, &key);
420
421                 dbus_message_iter_next(&entry);
422                 dbus_message_iter_recurse(&entry, &value);
423
424                 switch (dbus_message_iter_get_arg_type(&value)) {
425                 case DBUS_TYPE_STRING:
426                         if (g_str_equal(key, "Type") == TRUE)
427                                 dbus_message_iter_get_basic(&value, &type);
428                         else if (g_str_equal(key, "Name") == TRUE)
429                                 dbus_message_iter_get_basic(&value, &name);
430                         break;
431                 }
432
433                 if (type != NULL && name != NULL)
434                         break;
435
436                 dbus_message_iter_next(&array);
437         }
438
439         DBG("Type %s name %s", type, name);
440
441         if (type == NULL || name == NULL) {
442                 err = -EOPNOTSUPP;
443                 goto failed;
444         }
445
446         ident = g_strdup_printf("%s_%s", type, name);
447
448         provider = connman_provider_lookup(ident);
449
450         if (provider == NULL) {
451                 created = TRUE;
452                 provider = connman_provider_create(ident);
453                 if (provider) {
454                         provider->name = g_strdup(name);
455                         provider->type = g_strdup(type);
456                 }
457         }
458
459         if (provider == NULL) {
460                 DBG("can not create provider");
461                 err = -EOPNOTSUPP;
462                 goto failed;
463         }
464         dbus_message_iter_init(msg, &iter);
465         dbus_message_iter_recurse(&iter, &array);
466
467         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
468                 DBusMessageIter entry, value;
469                 const char *key, *str;
470
471                 dbus_message_iter_recurse(&array, &entry);
472                 dbus_message_iter_get_basic(&entry, &key);
473
474                 dbus_message_iter_next(&entry);
475                 dbus_message_iter_recurse(&entry, &value);
476
477                 switch (dbus_message_iter_get_arg_type(&value)) {
478                 case DBUS_TYPE_STRING:
479                         dbus_message_iter_get_basic(&value, &str);
480                         connman_provider_set_string(provider, key, str);
481                         break;
482                 }
483
484                 dbus_message_iter_next(&array);
485         }
486
487         g_free(ident);
488
489         if (provider == NULL) {
490                 err = -EOPNOTSUPP;
491                 goto failed;
492         }
493
494         if (created == TRUE)
495                 provider_probe(provider);
496
497         provider->vpn_service =
498                         __connman_service_create_from_provider(provider);
499         if (provider->vpn_service == NULL) {
500                 err = -EOPNOTSUPP;
501                 goto failed;
502         }
503
504         err = __connman_service_connect(provider->vpn_service);
505         if (err < 0 && err != -EINPROGRESS)
506                 goto failed;
507
508         service_path = __connman_service_get_path(provider->vpn_service);
509         g_dbus_send_reply(connection, msg,
510                                 DBUS_TYPE_OBJECT_PATH, &service_path,
511                                                         DBUS_TYPE_INVALID);
512         return 0;
513
514 failed:
515         if (provider != NULL && created == TRUE) {
516                 DBG("can not connect delete provider");
517                 connman_provider_unref(provider);
518
519                 if (provider->vpn_service != NULL)
520                         __connman_service_put(provider->vpn_service);
521         }
522
523         return err;
524 }
525
526 const char * __connman_provider_get_ident(struct connman_provider *provider)
527 {
528         if (provider == NULL)
529                 return NULL;
530
531         return provider->identifier;
532 }
533
534 int connman_provider_set_string(struct connman_provider *provider,
535                                         const char *key, const char *value)
536 {
537         DBG("provider %p key %s value %s", provider, key, value);
538
539         if (g_str_equal(key, "Type") == TRUE) {
540                 g_free(provider->type);
541                 provider->type = g_strdup(value);
542         } else if (g_str_equal(key, "Name") == TRUE) {
543                 g_free(provider->name);
544                 provider->name = g_strdup(value);
545         } else if (g_str_equal(key, "Gateway") == TRUE) {
546                 g_free(provider->element.ipv4.gateway);
547                 provider->element.ipv4.gateway = g_strdup(value);
548         } else if (g_str_equal(key, "Address") == TRUE) {
549                 g_free(provider->element.ipv4.address);
550                 provider->element.ipv4.address = g_strdup(value);
551         } else if (g_str_equal(key, "Netmask") == TRUE) {
552                 g_free(provider->element.ipv4.netmask);
553                 provider->element.ipv4.netmask = g_strdup(value);
554         } else if (g_str_equal(key, "PAC") == TRUE) {
555                 g_free(provider->element.ipv4.pac);
556                 provider->element.ipv4.pac = g_strdup(value);
557         } else if (g_str_equal(key, "DNS") == TRUE) {
558                 g_free(provider->dns);
559                 provider->dns = g_strdup(value);
560         } else if (g_str_equal(key, "Domain") == TRUE) {
561                 g_free(provider->domain);
562                 provider->domain = g_strdup(value);
563         }
564
565         return connman_element_set_string(&provider->element, key, value);
566 }
567
568 const char *connman_provider_get_string(struct connman_provider *provider,
569                                                         const char *key)
570 {
571         DBG("provider %p key %s", provider, key);
572
573         if (g_str_equal(key, "Type") == TRUE)
574                 return provider->type;
575         else if (g_str_equal(key, "Name") == TRUE)
576                 return provider->name;
577
578         return connman_element_get_string(&provider->element, key);
579 }
580
581 void *connman_provider_get_data(struct connman_provider *provider)
582 {
583         return provider->driver_data;
584 }
585
586 void connman_provider_set_data(struct connman_provider *provider, void *data)
587 {
588         provider->driver_data = data;
589 }
590
591 void connman_provider_set_index(struct connman_provider *provider, int index)
592 {
593         provider->element.index = index;
594 }
595
596 int connman_provider_get_index(struct connman_provider *provider)
597 {
598         return provider->element.index;
599 }
600
601 static gint compare_priority(gconstpointer a, gconstpointer b)
602 {
603         return 0;
604 }
605
606 static void clean_provider(gpointer key, gpointer value, gpointer user_data)
607 {
608         struct connman_provider *provider = value;
609
610         if (provider->driver != NULL && provider->driver->remove)
611                 provider->driver->remove(provider);
612 }
613
614 int connman_provider_driver_register(struct connman_provider_driver *driver)
615 {
616         DBG("driver %p name %s", driver, driver->name);
617
618         driver_list = g_slist_insert_sorted(driver_list, driver,
619                                                         compare_priority);
620         return 0;
621 }
622
623 void connman_provider_driver_unregister(struct connman_provider_driver *driver)
624 {
625         DBG("driver %p name %s", driver, driver->name);
626
627         driver_list = g_slist_remove(driver_list, driver);
628 }
629
630 int __connman_provider_init(void)
631 {
632         DBG("");
633
634         connection = connman_dbus_get_connection();
635
636         provider_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
637                                                 NULL, unregister_provider);
638         return 0;
639 }
640
641 void __connman_provider_cleanup(void)
642 {
643         DBG("");
644
645         g_hash_table_foreach(provider_hash, clean_provider, NULL);
646
647         g_hash_table_destroy(provider_hash);
648         provider_hash = NULL;
649
650         dbus_connection_unref(connection);
651 }