5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
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.
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.
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
32 static DBusConnection *connection = NULL;
34 static GHashTable *provider_hash = NULL;
36 static GSList *driver_list = NULL;
38 struct connman_provider {
39 struct connman_element element;
40 struct connman_service *vpn_service;
47 struct connman_provider_driver *driver;
51 void __connman_provider_append_properties(struct connman_provider *provider,
52 DBusMessageIter *iter)
54 if (provider->host != NULL)
55 connman_dbus_dict_append_basic(iter, "Host",
56 DBUS_TYPE_STRING, &provider->host);
58 if (provider->domain != NULL)
59 connman_dbus_dict_append_basic(iter, "Domain",
60 DBUS_TYPE_STRING, &provider->domain);
62 if (provider->type != NULL)
63 connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING,
67 static struct connman_provider *connman_provider_lookup(const char *identifier)
69 struct connman_provider *provider = NULL;
71 provider = g_hash_table_lookup(provider_hash, identifier);
76 static int connman_provider_setup_vpn_ipv4(struct connman_provider *provider,
77 struct connman_element *element)
79 if (element == NULL || provider == NULL)
82 DBG("set vpn type %d", element->type);
84 g_free(element->ipv4.address);
85 element->ipv4.address = g_strdup(provider->element.ipv4.address);
87 g_free(element->ipv4.peer);
88 element->ipv4.peer = g_strdup(provider->element.ipv4.peer);
90 g_free(element->ipv4.netmask);
91 element->ipv4.netmask = g_strdup(provider->element.ipv4.netmask);
93 g_free(element->ipv4.gateway);
94 element->ipv4.gateway = g_strdup(provider->element.ipv4.gateway);
96 g_free(element->ipv4.broadcast);
97 element->ipv4.broadcast = g_strdup(provider->element.ipv4.broadcast);
99 g_free(element->ipv4.pac);
100 element->ipv4.pac = g_strdup(provider->element.ipv4.pac);
102 return connman_element_register(element, &provider->element);
105 struct connman_provider *connman_provider_ref(struct connman_provider *provider)
107 DBG("provider %p", provider);
109 if (connman_element_ref(&provider->element) == NULL)
115 void connman_provider_unref(struct connman_provider *provider)
117 DBG("provider %p", provider);
119 connman_element_unref(&provider->element);
122 static gboolean match_driver(struct connman_provider *provider,
123 struct connman_provider_driver *driver)
125 if (g_strcmp0(driver->name, provider->type) == 0)
131 static int provider_probe(struct connman_provider *provider)
135 DBG("provider %p name %s", provider, provider->name);
137 if (provider->driver != NULL)
140 for (list = driver_list; list; list = list->next) {
141 struct connman_provider_driver *driver = list->data;
143 if (match_driver(provider, driver) == FALSE)
146 DBG("driver %p name %s", driver, driver->name);
148 if (driver->probe != NULL && driver->probe(provider) == 0) {
149 provider->driver = driver;
154 if (provider->driver == NULL)
160 int __connman_provider_disconnect(struct connman_provider *provider)
164 DBG("provider %p", provider);
166 if (provider->driver != NULL && provider->driver->disconnect != NULL)
167 err = provider->driver->disconnect(provider);
171 if (provider->vpn_service != NULL)
172 __connman_service_indicate_state(provider->vpn_service,
173 CONNMAN_SERVICE_STATE_DISCONNECT);
175 if (err != -EINPROGRESS)
184 int __connman_provider_connect(struct connman_provider *provider)
188 DBG("provider %p", provider);
190 g_free(provider->element.ipv4.address);
191 g_free(provider->element.ipv4.peer);
192 g_free(provider->element.ipv4.netmask);
193 g_free(provider->element.ipv4.gateway);
194 g_free(provider->element.ipv4.broadcast);
195 g_free(provider->element.ipv4.pac);
197 provider->element.ipv4.address = NULL;
198 provider->element.ipv4.peer = NULL;
199 provider->element.ipv4.netmask = NULL;
200 provider->element.ipv4.gateway = NULL;
201 provider->element.ipv4.broadcast = NULL;
202 provider->element.ipv4.pac = NULL;
204 if (provider->driver != NULL && provider->driver->connect != NULL)
205 err = provider->driver->connect(provider);
210 if (err != -EINPROGRESS)
213 __connman_service_indicate_state(provider->vpn_service,
214 CONNMAN_SERVICE_STATE_ASSOCIATION);
221 int __connman_provider_remove(const char *path)
223 struct connman_provider *provider;
227 DBG("path %s", path);
229 g_hash_table_iter_init(&iter, provider_hash);
230 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
231 const char *srv_path;
234 if (provider->vpn_service == NULL)
237 srv_path = __connman_service_get_path(provider->vpn_service);
239 if (g_strcmp0(srv_path, path) == 0) {
240 DBG("Removing VPN %s", provider->identifier);
241 g_hash_table_remove(provider_hash,
242 provider->identifier);
250 static int set_connected(struct connman_provider *provider,
251 connman_bool_t connected)
253 struct connman_service *service = provider->vpn_service;
258 if (connected == TRUE) {
259 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
260 struct connman_element *element;
261 char *nameservers = NULL, *name = NULL;
266 __connman_service_indicate_state(provider->vpn_service,
267 CONNMAN_SERVICE_STATE_CONFIGURATION);
269 type = CONNMAN_ELEMENT_TYPE_IPV4;
271 element = connman_element_create(NULL);
275 element->type = type;
276 element->index = provider->element.index;
278 err = connman_provider_setup_vpn_ipv4(provider, element);
280 connman_element_unref(element);
282 __connman_service_indicate_state(service,
283 CONNMAN_SERVICE_STATE_FAILURE);
288 __connman_service_indicate_state(service,
289 CONNMAN_SERVICE_STATE_READY);
291 __connman_service_set_domainname(service, provider->domain);
293 name = connman_inet_ifname(provider->element.index);
295 nameservers = g_strdup(provider->dns);
297 second_ns = strchr(value, ' ');
300 __connman_service_append_nameserver(service, value);
304 char *next = strchr(value, ' ');
308 connman_resolver_append(name, provider->domain, value);
316 connman_element_unregister_children(&provider->element);
317 __connman_service_indicate_state(service,
318 CONNMAN_SERVICE_STATE_IDLE);
324 int connman_provider_set_state(struct connman_provider *provider,
325 enum connman_provider_state state)
327 if (provider == NULL || provider->vpn_service == NULL)
331 case CONNMAN_PROVIDER_STATE_UNKNOWN:
333 case CONNMAN_PROVIDER_STATE_IDLE:
334 return set_connected(provider, FALSE);
335 case CONNMAN_PROVIDER_STATE_CONNECT:
336 return __connman_service_indicate_state(provider->vpn_service,
337 CONNMAN_SERVICE_STATE_ASSOCIATION);
338 case CONNMAN_PROVIDER_STATE_READY:
339 return set_connected(provider, TRUE);
340 case CONNMAN_PROVIDER_STATE_DISCONNECT:
341 return __connman_service_indicate_state(provider->vpn_service,
342 CONNMAN_SERVICE_STATE_DISCONNECT);
343 case CONNMAN_PROVIDER_STATE_FAILURE:
344 return __connman_service_indicate_state(provider->vpn_service,
345 CONNMAN_SERVICE_STATE_FAILURE);
351 static void unregister_provider(gpointer data)
353 struct connman_provider *provider = data;
354 struct connman_service *service = provider->vpn_service;
356 DBG("provider %p", provider);
358 provider->vpn_service = NULL;
359 __connman_service_put(service);
361 connman_element_unregister(&provider->element);
362 connman_provider_unref(provider);
365 static void provider_destruct(struct connman_element *element)
367 struct connman_provider *provider = element->private;
369 DBG("provider %p", provider);
371 g_free(provider->name);
372 g_free(provider->type);
373 g_free(provider->domain);
374 g_free(provider->identifier);
375 g_free(provider->dns);
378 static void provider_initialize(struct connman_provider *provider)
380 DBG("provider %p", provider);
382 __connman_element_initialize(&provider->element);
384 provider->element.private = provider;
385 provider->element.destruct = provider_destruct;
387 provider->element.ipv4.address = NULL;
388 provider->element.ipv4.netmask = NULL;
389 provider->element.ipv4.gateway = NULL;
390 provider->element.ipv4.broadcast = NULL;
391 provider->element.ipv4.pac = NULL;
393 provider->name = NULL;
394 provider->type = NULL;
395 provider->dns = NULL;
396 provider->domain = NULL;
397 provider->identifier = NULL;
400 static struct connman_provider *connman_provider_new(void)
402 struct connman_provider *provider;
404 provider = g_try_new0(struct connman_provider, 1);
405 if (provider == NULL)
408 DBG("provider %p", provider);
409 provider_initialize(provider);
414 static struct connman_provider *connman_provider_get(const char *identifier)
416 struct connman_provider *provider;
418 provider = g_hash_table_lookup(provider_hash, identifier);
419 if (provider != NULL)
422 provider = connman_provider_new();
423 if (provider == NULL)
426 DBG("provider %p", provider);
428 provider->identifier = g_strdup(identifier);
430 g_hash_table_insert(provider_hash, provider->identifier, provider);
432 provider->element.name = g_strdup(identifier);
433 connman_element_register(&provider->element, NULL);
438 static void provider_dbus_ident(char *ident)
440 int i, len = strlen(ident);
442 for (i = 0; i < len; i++) {
443 if (ident[i] >= '0' && ident[i] <= '9')
445 if (ident[i] >= 'a' && ident[i] <= 'z')
447 if (ident[i] >= 'A' && ident[i] <= 'Z')
453 int __connman_provider_create_and_connect(DBusMessage *msg)
455 struct connman_provider *provider;
456 DBusMessageIter iter, array;
457 const char *type = NULL, *name = NULL, *service_path = NULL;
458 const char *host = NULL, *domain = NULL;
460 gboolean created = FALSE;
463 dbus_message_iter_init(msg, &iter);
464 dbus_message_iter_recurse(&iter, &array);
466 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
467 DBusMessageIter entry, value;
470 dbus_message_iter_recurse(&array, &entry);
471 dbus_message_iter_get_basic(&entry, &key);
473 dbus_message_iter_next(&entry);
474 dbus_message_iter_recurse(&entry, &value);
476 switch (dbus_message_iter_get_arg_type(&value)) {
477 case DBUS_TYPE_STRING:
478 if (g_str_equal(key, "Type") == TRUE)
479 dbus_message_iter_get_basic(&value, &type);
480 else if (g_str_equal(key, "Name") == TRUE)
481 dbus_message_iter_get_basic(&value, &name);
482 else if (g_str_equal(key, "Host") == TRUE)
483 dbus_message_iter_get_basic(&value, &host);
484 else if (g_str_equal(key, "VPN.Domain") == TRUE)
485 dbus_message_iter_get_basic(&value, &domain);
489 dbus_message_iter_next(&array);
492 if (host == NULL || domain == NULL) {
497 DBG("Type %s name %s", type, name);
499 if (type == NULL || name == NULL) {
504 ident = g_strdup_printf("%s_%s", host, domain);
505 provider_dbus_ident(ident);
507 DBG("ident %s", ident);
509 provider = connman_provider_lookup(ident);
511 if (provider == NULL) {
513 provider = connman_provider_get(ident);
515 provider->host = g_strdup(host);
516 provider->domain = g_strdup(domain);
517 provider->name = g_strdup(name);
518 provider->type = g_strdup(type);
522 if (provider == NULL) {
523 DBG("can not create provider");
527 dbus_message_iter_init(msg, &iter);
528 dbus_message_iter_recurse(&iter, &array);
530 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
531 DBusMessageIter entry, value;
532 const char *key, *str;
534 dbus_message_iter_recurse(&array, &entry);
535 dbus_message_iter_get_basic(&entry, &key);
537 dbus_message_iter_next(&entry);
538 dbus_message_iter_recurse(&entry, &value);
540 switch (dbus_message_iter_get_arg_type(&value)) {
541 case DBUS_TYPE_STRING:
542 dbus_message_iter_get_basic(&value, &str);
543 connman_provider_set_string(provider, key, str);
547 dbus_message_iter_next(&array);
552 if (provider == NULL) {
558 provider_probe(provider);
560 if (provider->vpn_service == NULL)
561 provider->vpn_service =
562 __connman_service_create_from_provider(provider);
563 if (provider->vpn_service == NULL) {
568 err = __connman_service_connect(provider->vpn_service);
569 if (err < 0 && err != -EINPROGRESS)
572 service_path = __connman_service_get_path(provider->vpn_service);
573 g_dbus_send_reply(connection, msg,
574 DBUS_TYPE_OBJECT_PATH, &service_path,
579 if (provider != NULL && created == TRUE) {
580 DBG("can not connect delete provider");
581 connman_provider_unref(provider);
583 if (provider->vpn_service != NULL) {
584 __connman_service_put(provider->vpn_service);
585 provider->vpn_service = NULL;
592 const char * __connman_provider_get_ident(struct connman_provider *provider)
594 if (provider == NULL)
597 return provider->identifier;
600 int connman_provider_set_string(struct connman_provider *provider,
601 const char *key, const char *value)
603 DBG("provider %p key %s value %s", provider, key, value);
605 if (g_str_equal(key, "Type") == TRUE) {
606 g_free(provider->type);
607 provider->type = g_strdup(value);
608 } else if (g_str_equal(key, "Name") == TRUE) {
609 g_free(provider->name);
610 provider->name = g_strdup(value);
611 } else if (g_str_equal(key, "Gateway") == TRUE) {
612 g_free(provider->element.ipv4.gateway);
613 provider->element.ipv4.gateway = g_strdup(value);
614 } else if (g_str_equal(key, "Address") == TRUE) {
615 g_free(provider->element.ipv4.address);
616 provider->element.ipv4.address = g_strdup(value);
617 } else if (g_str_equal(key, "Peer") == TRUE) {
618 g_free(provider->element.ipv4.peer);
619 provider->element.ipv4.peer = g_strdup(value);
620 } else if (g_str_equal(key, "Netmask") == TRUE) {
621 g_free(provider->element.ipv4.netmask);
622 provider->element.ipv4.netmask = g_strdup(value);
623 } else if (g_str_equal(key, "PAC") == TRUE) {
624 g_free(provider->element.ipv4.pac);
625 provider->element.ipv4.pac = g_strdup(value);
626 __connman_service_set_proxy_autoconfig(provider->vpn_service,
628 } else if (g_str_equal(key, "DNS") == TRUE) {
629 g_free(provider->dns);
630 provider->dns = g_strdup(value);
631 } else if (g_str_equal(key, "Domain") == TRUE) {
632 g_free(provider->domain);
633 provider->domain = g_strdup(value);
636 return connman_element_set_string(&provider->element, key, value);
639 const char *connman_provider_get_string(struct connman_provider *provider,
642 DBG("provider %p key %s", provider, key);
644 if (g_str_equal(key, "Type") == TRUE)
645 return provider->type;
646 else if (g_str_equal(key, "Name") == TRUE)
647 return provider->name;
649 return connman_element_get_string(&provider->element, key);
652 void *connman_provider_get_data(struct connman_provider *provider)
654 return provider->driver_data;
657 void connman_provider_set_data(struct connman_provider *provider, void *data)
659 provider->driver_data = data;
662 void connman_provider_set_index(struct connman_provider *provider, int index)
664 struct connman_service *service = provider->vpn_service;
665 struct connman_ipconfig *ipconfig;
672 ipconfig = __connman_service_get_ipconfig(service);
674 if (ipconfig == NULL) {
675 __connman_service_create_ipconfig(service, index);
677 ipconfig = __connman_service_get_ipconfig(service);
678 if (ipconfig == NULL) {
679 DBG("Couldnt create ipconfig");
684 connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_FIXED);
685 __connman_ipconfig_set_index(ipconfig, index);
689 provider->element.index = index;
692 int connman_provider_get_index(struct connman_provider *provider)
694 return provider->element.index;
697 const char *connman_provider_get_driver_name(struct connman_provider *provider)
699 return provider->driver->name;
702 static gint compare_priority(gconstpointer a, gconstpointer b)
707 static void clean_provider(gpointer key, gpointer value, gpointer user_data)
709 struct connman_provider *provider = value;
711 if (provider->driver != NULL && provider->driver->remove)
712 provider->driver->remove(provider);
715 int connman_provider_driver_register(struct connman_provider_driver *driver)
717 DBG("driver %p name %s", driver, driver->name);
719 driver_list = g_slist_insert_sorted(driver_list, driver,
724 void connman_provider_driver_unregister(struct connman_provider_driver *driver)
726 DBG("driver %p name %s", driver, driver->name);
728 driver_list = g_slist_remove(driver_list, driver);
731 static void provider_remove(gpointer key, gpointer value,
734 struct connman_provider *provider = value;
736 g_hash_table_remove(provider_hash, provider->identifier);
739 static void provider_offline_mode(connman_bool_t enabled)
741 DBG("enabled %d", enabled);
744 g_hash_table_foreach(provider_hash, provider_remove, NULL);
748 static struct connman_notifier provider_notifier = {
750 .offline_mode = provider_offline_mode,
753 int __connman_provider_init(void)
759 connection = connman_dbus_get_connection();
761 provider_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
762 NULL, unregister_provider);
764 err = connman_notifier_register(&provider_notifier);
766 g_hash_table_destroy(provider_hash);
767 dbus_connection_unref(connection);
773 void __connman_provider_cleanup(void)
777 connman_notifier_unregister(&provider_notifier);
779 g_hash_table_foreach(provider_hash, clean_provider, NULL);
781 g_hash_table_destroy(provider_hash);
782 provider_hash = NULL;
784 dbus_connection_unref(connection);