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;
43 enum connman_provider_state state;
44 enum connman_provider_error error;
51 struct connman_provider_driver *driver;
55 static const char *state2string(enum connman_provider_state state)
58 case CONNMAN_PROVIDER_STATE_UNKNOWN:
60 case CONNMAN_PROVIDER_STATE_IDLE:
62 case CONNMAN_PROVIDER_STATE_CONNECT:
64 case CONNMAN_PROVIDER_STATE_READY:
66 case CONNMAN_PROVIDER_STATE_DISCONNECT:
68 case CONNMAN_PROVIDER_STATE_FAILURE:
74 static const char *error2string(enum connman_provider_error error)
77 case CONNMAN_PROVIDER_ERROR_UNKNOWN:
79 case CONNMAN_PROVIDER_ERROR_CONNECT_FAILED:
80 return "connect-failed";
86 static void append_path(gpointer key, gpointer value, gpointer user_data)
88 struct connman_provider *provider = value;
89 DBusMessageIter *iter = user_data;
91 DBG("add provider path");
92 if (provider->path == NULL)
95 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
99 void __connman_provider_list(DBusMessageIter *iter, void *user_data)
101 g_hash_table_foreach(provider_hash, append_path, iter);
104 static struct connman_provider *connman_provider_lookup(const char *identifier)
106 struct connman_provider *provider = NULL;
108 provider = g_hash_table_lookup(provider_hash, identifier);
113 static void connman_provider_setup_vpn_ipv4(struct connman_provider *provider,
114 struct connman_element *element)
116 if (element == NULL || provider == NULL)
119 DBG("set vpn type %d", element->type);
121 if (provider == NULL)
124 g_free(element->ipv4.address);
125 element->ipv4.address = g_strdup(provider->element.ipv4.address);
127 g_free(element->ipv4.netmask);
128 element->ipv4.netmask = g_strdup(provider->element.ipv4.netmask);
130 g_free(element->ipv4.gateway);
131 element->ipv4.gateway = g_strdup(provider->element.ipv4.gateway);
133 g_free(element->ipv4.broadcast);
134 element->ipv4.broadcast = g_strdup(provider->element.ipv4.broadcast);
136 g_free(element->ipv4.pac);
137 element->ipv4.pac = g_strdup(provider->element.ipv4.pac);
142 struct connman_provider *connman_provider_ref(struct connman_provider *provider)
144 DBG("provider %p", provider);
146 if (connman_element_ref(&provider->element) == NULL)
152 void connman_provider_unref(struct connman_provider *provider)
154 DBG("provider %p", provider);
156 connman_element_unref(&provider->element);
159 static gboolean match_driver(struct connman_provider *provider,
160 struct connman_provider_driver *driver)
162 if (g_strcmp0(driver->name, provider->type) == 0)
168 static int provider_probe(struct connman_provider *provider)
172 DBG("provider %p name %s", provider, provider->name);
174 if (provider->driver != NULL)
177 for (list = driver_list; list; list = list->next) {
178 struct connman_provider_driver *driver = list->data;
180 if (match_driver(provider, driver) == FALSE)
183 DBG("driver %p name %s", driver, driver->name);
185 if (driver->probe != NULL && driver->probe(provider) == 0) {
186 provider->driver = driver;
191 if (provider->driver == NULL)
197 static void state_changed(struct connman_provider *provider)
201 str = state2string(provider->state);
205 connman_dbus_property_changed_basic(provider->path,
206 CONNMAN_PROVIDER_INTERFACE, "State",
207 DBUS_TYPE_STRING, &str);
210 static void reply_pending(struct connman_provider *provider, int error)
212 if (provider->timeout > 0) {
213 g_source_remove(provider->timeout);
214 provider->timeout = 0;
217 if (provider->pending != NULL) {
221 reply = __connman_error_failed(provider->pending,
224 g_dbus_send_message(connection, reply);
226 g_dbus_send_reply(connection, provider->pending,
229 dbus_message_unref(provider->pending);
230 provider->pending = NULL;
234 static int connman_provider_disconnect(struct connman_provider *provider)
238 DBG("provider %p", provider);
240 reply_pending(provider, ECONNABORTED);
242 if (provider->driver != NULL && provider->driver->disconnect != NULL)
243 err = provider->driver->disconnect(provider);
247 __connman_provider_indicate_state(provider,
248 CONNMAN_PROVIDER_STATE_DISCONNECT);
250 __connman_service_indicate_state(provider->vpn_service,
251 CONNMAN_SERVICE_STATE_DISCONNECT);
253 if (err != -EINPROGRESS)
262 int __connman_provider_indicate_state(struct connman_provider *provider,
263 enum connman_provider_state state)
265 DBG("provider %p state %d", provider, state);
267 if (provider == NULL)
270 if (provider->state == state)
273 if (provider->state == CONNMAN_PROVIDER_STATE_FAILURE &&
274 state == CONNMAN_PROVIDER_STATE_IDLE)
277 if (provider->state == CONNMAN_PROVIDER_STATE_IDLE &&
278 state == CONNMAN_PROVIDER_STATE_DISCONNECT)
281 if (state == CONNMAN_PROVIDER_STATE_IDLE &&
282 provider->state != CONNMAN_PROVIDER_STATE_DISCONNECT) {
283 provider->state = CONNMAN_PROVIDER_STATE_DISCONNECT;
284 state_changed(provider);
286 connman_provider_disconnect(provider);
289 provider->state = state;
290 state_changed(provider);
292 if (state == CONNMAN_PROVIDER_STATE_READY)
293 reply_pending(provider, 0);
295 if (state == CONNMAN_PROVIDER_STATE_FAILURE)
296 reply_pending(provider, EIO);
298 provider->error = CONNMAN_PROVIDER_ERROR_UNKNOWN;
303 int __connman_provider_indicate_error(struct connman_provider *provider,
304 enum connman_provider_error error)
306 DBG("provider %p error %d", provider, error);
308 if (provider == NULL)
311 provider->error = error;
313 return __connman_provider_indicate_state(provider,
314 CONNMAN_PROVIDER_STATE_FAILURE);
317 static gboolean connect_timeout(gpointer user_data)
319 struct connman_provider *provider = user_data;
321 DBG("provider %p", provider);
323 provider->timeout = 0;
325 if (provider->pending != NULL) {
328 reply = __connman_error_operation_timeout(provider->pending);
330 g_dbus_send_message(connection, reply);
332 dbus_message_unref(provider->pending);
333 provider->pending = NULL;
336 __connman_provider_indicate_error(provider,
337 CONNMAN_PROVIDER_ERROR_CONNECT_FAILED);
342 static connman_bool_t is_connecting(struct connman_provider *provider)
344 switch (provider->state) {
345 case CONNMAN_PROVIDER_STATE_UNKNOWN:
346 case CONNMAN_PROVIDER_STATE_IDLE:
347 case CONNMAN_PROVIDER_STATE_FAILURE:
348 case CONNMAN_PROVIDER_STATE_DISCONNECT:
349 case CONNMAN_PROVIDER_STATE_READY:
351 case CONNMAN_PROVIDER_STATE_CONNECT:
358 static int connman_provider_connect(struct connman_provider *provider)
362 DBG("provider %p", provider);
364 if (provider->state == CONNMAN_PROVIDER_STATE_READY)
367 if (is_connecting(provider) == TRUE)
370 g_free(provider->element.ipv4.address);
371 g_free(provider->element.ipv4.netmask);
372 g_free(provider->element.ipv4.gateway);
373 g_free(provider->element.ipv4.broadcast);
374 g_free(provider->element.ipv4.pac);
376 provider->element.ipv4.address = NULL;
377 provider->element.ipv4.netmask = NULL;
378 provider->element.ipv4.gateway = NULL;
379 provider->element.ipv4.broadcast = NULL;
380 provider->element.ipv4.pac = NULL;
382 if (provider->driver != NULL && provider->driver->connect != NULL)
383 err = provider->driver->connect(provider);
388 if (err != -EINPROGRESS)
391 provider->timeout = g_timeout_add_seconds(60,
392 connect_timeout, provider);
394 __connman_provider_indicate_state(provider,
395 CONNMAN_PROVIDER_STATE_CONNECT);
402 int __connman_provider_remove(const char *path)
404 struct connman_provider *provider;
406 DBG("path %s", path);
408 provider = g_hash_table_lookup(provider_hash, path);
409 if (provider == NULL) {
410 DBG("patch %s not found", path);
414 g_hash_table_remove(provider_hash, path);
419 static DBusMessage *get_properties(DBusConnection *conn,
420 DBusMessage *msg, void *user_data)
422 struct connman_provider *provider = user_data;
424 DBusMessageIter array, dict;
425 dbus_bool_t required;
428 DBG("provider %p", provider);
430 reply = dbus_message_new_method_return(msg);
434 dbus_message_iter_init_append(reply, &array);
436 connman_dbus_dict_open(&array, &dict);
438 if (provider->name != NULL)
439 connman_dbus_dict_append_basic(&dict, "Name",
440 DBUS_TYPE_STRING, &provider->name);
443 connman_dbus_dict_append_basic(&dict, "Type",
447 str = state2string(provider->state);
449 connman_dbus_dict_append_basic(&dict, "State",
450 DBUS_TYPE_STRING, &str);
452 str = error2string(provider->error);
454 connman_dbus_dict_append_basic(&dict, "Error",
455 DBUS_TYPE_STRING, &str);
458 connman_dbus_dict_append_basic(&dict, "PassphraseRequired",
459 DBUS_TYPE_BOOLEAN, &required);
461 connman_dbus_dict_close(&array, &dict);
466 static GDBusMethodTable provider_methods[] = {
467 { "GetProperties", "", "a{sv}", get_properties },
471 static GDBusSignalTable provider_signals[] = {
472 { "PropertyChanged", "sv" },
476 int connman_provider_set_connected(struct connman_provider *provider,
477 connman_bool_t connected)
479 if (connected == TRUE) {
480 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
481 struct connman_element *element;
483 type = CONNMAN_ELEMENT_TYPE_IPV4;
485 element = connman_element_create(NULL);
486 if (element != NULL) {
487 element->type = type;
488 element->index = provider->element.index;
490 connman_provider_setup_vpn_ipv4(provider, element);
492 if (connman_element_register(element,
493 &provider->element) < 0)
494 connman_element_unref(element);
496 char *nameservers = NULL;
501 nameservers = g_strdup(provider->dns);
503 name = connman_inet_ifname(
504 provider->element.index);
506 char *next = strchr(value, ' ');
510 connman_resolver_append(name,
521 __connman_provider_indicate_state(provider,
522 CONNMAN_PROVIDER_STATE_READY);
523 __connman_service_indicate_state(provider->vpn_service,
524 CONNMAN_SERVICE_STATE_READY);
526 reply_pending(provider, ECONNABORTED);
527 connman_element_unregister_children(&provider->element);
528 __connman_provider_indicate_state(provider,
529 CONNMAN_PROVIDER_STATE_DISCONNECT);
530 __connman_service_indicate_state(provider->vpn_service,
531 CONNMAN_SERVICE_STATE_DISCONNECT);
537 static void provider_free(gpointer user_data)
539 struct connman_provider *provider = user_data;
540 char *path = provider->path;
542 DBG("provider %p", provider);
544 reply_pending(provider, ENOENT);
545 provider->path = NULL;
548 g_dbus_unregister_interface(connection, path,
549 CONNMAN_PROVIDER_INTERFACE);
553 g_free(provider->name);
554 g_free(provider->type);
555 g_free(provider->domain);
556 g_free(provider->identifier);
557 g_free(provider->dns);
558 __connman_service_put(provider->vpn_service);
561 static void unregister_provider(gpointer data)
563 struct connman_provider *provider = data;
565 DBG("provider %p", provider);
567 connman_provider_disconnect(provider);
569 connman_element_unregister(&provider->element);
570 connman_provider_unref(provider);
573 static void provider_destruct(struct connman_element *element)
575 struct connman_provider *provider = element->private;
577 DBG("provider %p", provider);
579 provider_free(provider);
582 static void __connman_provider_initialize(struct connman_provider *provider)
584 DBG("provider %p", provider);
586 provider->state = CONNMAN_PROVIDER_STATE_UNKNOWN;
588 __connman_element_initialize(&provider->element);
590 provider->element.private = provider;
591 provider->element.destruct = provider_destruct;
593 provider->element.ipv4.address = NULL;
594 provider->element.ipv4.netmask = NULL;
595 provider->element.ipv4.gateway = NULL;
596 provider->element.ipv4.broadcast = NULL;
597 provider->element.ipv4.pac = NULL;
599 provider->name = NULL;
600 provider->type = NULL;
601 provider->dns = NULL;
602 provider->domain = NULL;
603 provider->identifier = NULL;
604 provider->path = NULL;
605 provider->pending = NULL;
608 static struct connman_provider *connman_provider_new(void)
610 struct connman_provider *provider;
612 provider = g_try_new0(struct connman_provider, 1);
613 if (provider == NULL)
616 DBG("provider %p", provider);
617 __connman_provider_initialize(provider);
622 static int provider_register(struct connman_provider *provider)
624 const char *path = "/provider";
626 DBG("provider %p", provider);
628 if (provider->path != NULL)
631 provider->path = g_strdup_printf("%s/%s", path, provider->identifier);
633 DBG("path %s", provider->path);
635 g_dbus_register_interface(connection, provider->path,
636 CONNMAN_PROVIDER_INTERFACE,
637 provider_methods, provider_signals,
638 NULL, provider, NULL);
643 static struct connman_provider *connman_provider_get(const char *identifier)
645 struct connman_provider *provider;
647 provider = g_hash_table_lookup(provider_hash, identifier);
648 if (provider != NULL)
651 provider = connman_provider_new();
652 if (provider == NULL)
655 DBG("provider %p", provider);
657 provider->identifier = g_strdup(identifier);
659 g_hash_table_insert(provider_hash, provider->identifier, provider);
661 provider->element.name = g_strdup(identifier);
662 connman_element_register(&provider->element, NULL);
667 static struct connman_provider *connman_provider_create(const char *name)
669 struct connman_provider *provider;
671 provider = connman_provider_get(name);
673 if (provider == NULL)
676 if (provider->path != NULL)
679 provider_register(provider);
684 int __connman_provider_create_and_connect(DBusMessage *msg)
686 struct connman_provider *provider;
687 DBusMessageIter iter, array;
688 const char *type = NULL, *name = NULL;
690 gboolean created = FALSE;
693 dbus_message_iter_init(msg, &iter);
694 dbus_message_iter_recurse(&iter, &array);
696 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
697 DBusMessageIter entry, value;
700 dbus_message_iter_recurse(&array, &entry);
701 dbus_message_iter_get_basic(&entry, &key);
703 dbus_message_iter_next(&entry);
704 dbus_message_iter_recurse(&entry, &value);
706 switch (dbus_message_iter_get_arg_type(&value)) {
707 case DBUS_TYPE_STRING:
708 if (g_str_equal(key, "Type") == TRUE)
709 dbus_message_iter_get_basic(&value, &type);
710 else if (g_str_equal(key, "Name") == TRUE)
711 dbus_message_iter_get_basic(&value, &name);
715 if (type != NULL && name != NULL)
718 dbus_message_iter_next(&array);
721 DBG("Type %s name %s", type, name);
723 if (type == NULL || name == NULL) {
728 ident = g_strdup_printf("%s_%s", type, name);
730 provider = connman_provider_lookup(ident);
732 if (provider == NULL) {
734 provider = connman_provider_create(ident);
736 provider->name = g_strdup(name);
737 provider->type = g_strdup(type);
741 if (provider == NULL) {
742 DBG("can not create provider");
746 dbus_message_iter_init(msg, &iter);
747 dbus_message_iter_recurse(&iter, &array);
749 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
750 DBusMessageIter entry, value;
751 const char *key, *str;
753 dbus_message_iter_recurse(&array, &entry);
754 dbus_message_iter_get_basic(&entry, &key);
756 dbus_message_iter_next(&entry);
757 dbus_message_iter_recurse(&entry, &value);
759 switch (dbus_message_iter_get_arg_type(&value)) {
760 case DBUS_TYPE_STRING:
761 dbus_message_iter_get_basic(&value, &str);
762 connman_provider_set_string(provider, key, str);
766 dbus_message_iter_next(&array);
771 if (provider == NULL) {
777 provider_probe(provider);
779 err = connman_provider_connect(provider);
780 if (err < 0 && err != -EINPROGRESS)
783 g_dbus_send_reply(connection, msg,
784 DBUS_TYPE_OBJECT_PATH, &provider->path,
787 provider->vpn_service =
788 __connman_service_create_from_provider(provider);
793 if (provider != NULL && created == TRUE) {
794 DBG("can not connect delete provider");
795 connman_provider_unref(provider);
801 const char * __connman_provider_get_ident(struct connman_provider *provider)
803 if (provider == NULL)
806 return provider->identifier;
809 int connman_provider_set_string(struct connman_provider *provider,
810 const char *key, const char *value)
812 DBG("provider %p key %s value %s", provider, key, value);
814 if (g_str_equal(key, "Type") == TRUE) {
815 g_free(provider->type);
816 provider->type = g_strdup(value);
817 } else if (g_str_equal(key, "Name") == TRUE) {
818 g_free(provider->name);
819 provider->name = g_strdup(value);
820 } else if (g_str_equal(key, "Gateway") == TRUE) {
821 g_free(provider->element.ipv4.gateway);
822 provider->element.ipv4.gateway = g_strdup(value);
823 } else if (g_str_equal(key, "Address") == TRUE) {
824 g_free(provider->element.ipv4.address);
825 provider->element.ipv4.address = g_strdup(value);
826 } else if (g_str_equal(key, "Netmask") == TRUE) {
827 g_free(provider->element.ipv4.netmask);
828 provider->element.ipv4.netmask = g_strdup(value);
829 } else if (g_str_equal(key, "PAC") == TRUE) {
830 g_free(provider->element.ipv4.pac);
831 provider->element.ipv4.pac = g_strdup(value);
832 } else if (g_str_equal(key, "DNS") == TRUE) {
833 g_free(provider->dns);
834 provider->dns = g_strdup(value);
835 } else if (g_str_equal(key, "Domain") == TRUE) {
836 g_free(provider->domain);
837 provider->domain = g_strdup(value);
840 return connman_element_set_string(&provider->element, key, value);
843 const char *connman_provider_get_string(struct connman_provider *provider,
846 DBG("provider %p key %s", provider, key);
848 if (g_str_equal(key, "Type") == TRUE)
849 return provider->type;
850 else if (g_str_equal(key, "Name") == TRUE)
851 return provider->name;
853 return connman_element_get_string(&provider->element, key);
856 void *connman_provider_get_data(struct connman_provider *provider)
858 return provider->driver_data;
861 void connman_provider_set_data(struct connman_provider *provider, void *data)
863 provider->driver_data = data;
866 void connman_provider_set_index(struct connman_provider *provider, int index)
868 provider->element.index = index;
871 int connman_provider_get_index(struct connman_provider *provider)
873 return provider->element.index;
876 static gint compare_priority(gconstpointer a, gconstpointer b)
881 static void clean_provider(gpointer key, gpointer value, gpointer user_data)
883 struct connman_provider *provider = value;
885 if (provider->driver != NULL && provider->driver->remove)
886 provider->driver->remove(provider);
889 int connman_provider_driver_register(struct connman_provider_driver *driver)
891 DBG("driver %p name %s", driver, driver->name);
893 driver_list = g_slist_insert_sorted(driver_list, driver,
898 void connman_provider_driver_unregister(struct connman_provider_driver *driver)
900 DBG("driver %p name %s", driver, driver->name);
902 driver_list = g_slist_remove(driver_list, driver);
905 int __connman_provider_init(void)
909 connection = connman_dbus_get_connection();
911 provider_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
912 NULL, unregister_provider);
916 void __connman_provider_cleanup(void)
920 g_hash_table_foreach(provider_hash, clean_provider, NULL);
922 g_hash_table_destroy(provider_hash);
923 provider_hash = NULL;
925 dbus_connection_unref(connection);