5 * Copyright (C) 2007-2012 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
33 static DBusConnection *connection;
35 static GSList *technology_list = NULL;
38 * List of devices with no technology associated with them either because of
39 * no compiled in support or the driver is not yet loaded.
41 static GSList *techless_device_list = NULL;
42 static GHashTable *rfkill_list;
44 static connman_bool_t global_offlinemode;
46 struct connman_rfkill {
48 enum connman_service_type type;
49 connman_bool_t softblock;
50 connman_bool_t hardblock;
53 struct connman_technology {
55 enum connman_service_type type;
58 connman_bool_t enabled;
60 connman_bool_t connected;
62 connman_bool_t tethering;
63 char *tethering_ident;
64 char *tethering_passphrase;
66 connman_bool_t enable_persistent; /* Save the tech state */
70 DBusMessage *pending_reply;
71 guint pending_timeout;
75 connman_bool_t rfkill_driven;
76 connman_bool_t softblocked;
77 connman_bool_t hardblocked;
78 connman_bool_t dbus_registered;
81 static GSList *driver_list = NULL;
83 static gint compare_priority(gconstpointer a, gconstpointer b)
85 const struct connman_technology_driver *driver1 = a;
86 const struct connman_technology_driver *driver2 = b;
88 return driver2->priority - driver1->priority;
91 static void rfkill_check(gpointer key, gpointer value, gpointer user_data)
93 struct connman_rfkill *rfkill = value;
94 enum connman_service_type type = GPOINTER_TO_INT(user_data);
96 /* Calling _technology_rfkill_add will update the tech. */
97 if (rfkill->type == type)
98 __connman_technology_add_rfkill(rfkill->index, type,
99 rfkill->softblock, rfkill->hardblock);
103 * connman_technology_driver_register:
104 * @driver: Technology driver definition
106 * Register a new technology driver
108 * Returns: %0 on success
110 int connman_technology_driver_register(struct connman_technology_driver *driver)
113 struct connman_device *device;
114 enum connman_service_type type;
116 DBG("Registering %s driver", driver->name);
118 driver_list = g_slist_insert_sorted(driver_list, driver,
122 * Check for technology less devices if this driver
123 * can service any of them.
125 for (list = techless_device_list; list != NULL; list = list->next) {
128 type = __connman_device_get_service_type(device);
129 if (type != driver->type)
132 techless_device_list = g_slist_remove(techless_device_list,
135 __connman_technology_add_device(device);
138 /* Check for orphaned rfkill switches. */
139 g_hash_table_foreach(rfkill_list, rfkill_check,
140 GINT_TO_POINTER(driver->type));
146 * connman_technology_driver_unregister:
147 * @driver: Technology driver definition
149 * Remove a previously registered technology driver
151 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
153 GSList *list, *tech_drivers;
154 struct connman_technology *technology;
155 struct connman_technology_driver *current;
157 DBG("Unregistering driver %p name %s", driver, driver->name);
159 for (list = technology_list; list; list = list->next) {
160 technology = list->data;
162 for (tech_drivers = technology->driver_list;
163 tech_drivers != NULL;
164 tech_drivers = g_slist_next(tech_drivers)) {
166 current = tech_drivers->data;
167 if (driver != current)
170 if (driver->remove != NULL)
171 driver->remove(technology);
173 technology->driver_list =
174 g_slist_remove(technology->driver_list, driver);
180 driver_list = g_slist_remove(driver_list, driver);
183 static void tethering_changed(struct connman_technology *technology)
185 connman_bool_t tethering = technology->tethering;
187 connman_dbus_property_changed_basic(technology->path,
188 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
189 DBUS_TYPE_BOOLEAN, &tethering);
192 void connman_technology_tethering_notify(struct connman_technology *technology,
193 connman_bool_t enabled)
197 DBG("technology %p enabled %u", technology, enabled);
199 if (technology->tethering == enabled)
202 technology->tethering = enabled;
204 tethering_changed(technology);
207 __connman_tethering_set_enabled();
209 for (list = technology_list; list; list = list->next) {
210 struct connman_technology *other_tech = list->data;
211 if (other_tech->tethering == TRUE)
215 __connman_tethering_set_disabled();
219 static int set_tethering(struct connman_technology *technology,
220 connman_bool_t enabled)
222 int result = -EOPNOTSUPP;
224 const char *ident, *passphrase, *bridge;
225 GSList *tech_drivers;
227 ident = technology->tethering_ident;
228 passphrase = technology->tethering_passphrase;
230 __sync_synchronize();
231 if (technology->enabled == FALSE)
234 bridge = __connman_tethering_get_bridge();
238 if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
239 (ident == NULL || passphrase == NULL))
242 for (tech_drivers = technology->driver_list; tech_drivers != NULL;
243 tech_drivers = g_slist_next(tech_drivers)) {
244 struct connman_technology_driver *driver = tech_drivers->data;
246 if (driver == NULL || driver->set_tethering == NULL)
249 err = driver->set_tethering(technology, ident, passphrase,
252 if (result == -EINPROGRESS)
255 if (err == -EINPROGRESS || err == 0) {
264 void connman_technology_regdom_notify(struct connman_technology *technology,
270 connman_error("Failed to set regulatory domain");
272 DBG("Regulatory domain set to %s", alpha2);
274 g_free(technology->regdom);
275 technology->regdom = g_strdup(alpha2);
278 static int set_regdom_by_device(struct connman_technology *technology,
283 for (list = technology->device_list; list; list = list->next) {
284 struct connman_device *device = list->data;
286 if (connman_device_set_regdom(device, alpha2) != 0)
293 int connman_technology_set_regdom(const char *alpha2)
295 GSList *list, *tech_drivers;
297 for (list = technology_list; list; list = list->next) {
298 struct connman_technology *technology = list->data;
300 if (set_regdom_by_device(technology, alpha2) != 0) {
302 for (tech_drivers = technology->driver_list;
303 tech_drivers != NULL;
304 tech_drivers = g_slist_next(tech_drivers)) {
306 struct connman_technology_driver *driver =
309 if (driver->set_regdom != NULL)
310 driver->set_regdom(technology, alpha2);
318 static void free_rfkill(gpointer data)
320 struct connman_rfkill *rfkill = data;
325 static const char *get_name(enum connman_service_type type)
328 case CONNMAN_SERVICE_TYPE_UNKNOWN:
329 case CONNMAN_SERVICE_TYPE_SYSTEM:
330 case CONNMAN_SERVICE_TYPE_GPS:
331 case CONNMAN_SERVICE_TYPE_VPN:
332 case CONNMAN_SERVICE_TYPE_GADGET:
334 case CONNMAN_SERVICE_TYPE_ETHERNET:
336 case CONNMAN_SERVICE_TYPE_WIFI:
338 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
340 case CONNMAN_SERVICE_TYPE_CELLULAR:
347 static void technology_save(struct connman_technology *technology)
352 DBG("technology %p", technology);
354 keyfile = __connman_storage_load_global();
356 keyfile = g_key_file_new();
358 identifier = g_strdup_printf("%s", get_name(technology->type));
359 if (identifier == NULL)
362 g_key_file_set_boolean(keyfile, identifier, "Enable",
363 technology->enable_persistent);
365 if (technology->tethering_ident != NULL)
366 g_key_file_set_string(keyfile, identifier,
367 "Tethering.Identifier",
368 technology->tethering_ident);
370 if (technology->tethering_passphrase != NULL)
371 g_key_file_set_string(keyfile, identifier,
372 "Tethering.Passphrase",
373 technology->tethering_passphrase);
378 __connman_storage_save_global(keyfile);
380 g_key_file_free(keyfile);
385 static void technology_load(struct connman_technology *technology)
389 GError *error = NULL;
390 connman_bool_t enable;
392 DBG("technology %p", technology);
394 keyfile = __connman_storage_load_global();
395 /* Fallback on disabling technology if file not found. */
396 if (keyfile == NULL) {
397 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
398 /* We enable ethernet by default */
399 technology->enable_persistent = TRUE;
401 technology->enable_persistent = FALSE;
405 identifier = g_strdup_printf("%s", get_name(technology->type));
406 if (identifier == NULL)
409 enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
411 technology->enable_persistent = enable;
413 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
414 technology->enable_persistent = TRUE;
416 technology->enable_persistent = FALSE;
418 technology_save(technology);
419 g_clear_error(&error);
422 technology->tethering_ident = g_key_file_get_string(keyfile,
423 identifier, "Tethering.Identifier", NULL);
425 technology->tethering_passphrase = g_key_file_get_string(keyfile,
426 identifier, "Tethering.Passphrase", NULL);
430 g_key_file_free(keyfile);
435 connman_bool_t __connman_technology_get_offlinemode(void)
437 return global_offlinemode;
440 static void connman_technology_save_offlinemode()
444 keyfile = __connman_storage_load_global();
446 keyfile = g_key_file_new();
448 g_key_file_set_boolean(keyfile, "global",
449 "OfflineMode", global_offlinemode);
451 __connman_storage_save_global(keyfile);
453 g_key_file_free(keyfile);
458 static connman_bool_t connman_technology_load_offlinemode()
461 GError *error = NULL;
462 connman_bool_t offlinemode;
464 /* If there is a error, we enable offlinemode */
465 keyfile = __connman_storage_load_global();
469 offlinemode = g_key_file_get_boolean(keyfile, "global",
470 "OfflineMode", &error);
473 g_clear_error(&error);
476 g_key_file_free(keyfile);
481 static void append_properties(DBusMessageIter *iter,
482 struct connman_technology *technology)
484 DBusMessageIter dict;
487 connman_dbus_dict_open(iter, &dict);
489 str = get_name(technology->type);
491 connman_dbus_dict_append_basic(&dict, "Name",
492 DBUS_TYPE_STRING, &str);
494 str = __connman_service_type2string(technology->type);
496 connman_dbus_dict_append_basic(&dict, "Type",
497 DBUS_TYPE_STRING, &str);
499 __sync_synchronize();
500 connman_dbus_dict_append_basic(&dict, "Powered",
502 &technology->enabled);
504 connman_dbus_dict_append_basic(&dict, "Connected",
506 &technology->connected);
508 connman_dbus_dict_append_basic(&dict, "Tethering",
510 &technology->tethering);
512 if (technology->tethering_ident != NULL)
513 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
515 &technology->tethering_ident);
517 if (technology->tethering_passphrase != NULL)
518 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
520 &technology->tethering_passphrase);
522 connman_dbus_dict_close(iter, &dict);
525 static void technology_added_signal(struct connman_technology *technology)
528 DBusMessageIter iter;
530 signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
531 CONNMAN_MANAGER_INTERFACE, "TechnologyAdded");
535 dbus_message_iter_init_append(signal, &iter);
536 dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
538 append_properties(&iter, technology);
540 dbus_connection_send(connection, signal, NULL);
541 dbus_message_unref(signal);
544 static void technology_removed_signal(struct connman_technology *technology)
546 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
547 CONNMAN_MANAGER_INTERFACE, "TechnologyRemoved",
548 DBUS_TYPE_OBJECT_PATH, &technology->path,
552 static DBusMessage *get_properties(DBusConnection *conn,
553 DBusMessage *message, void *user_data)
555 struct connman_technology *technology = user_data;
557 DBusMessageIter iter;
559 reply = dbus_message_new_method_return(message);
563 dbus_message_iter_init_append(reply, &iter);
564 append_properties(&iter, technology);
569 void __connman_technology_list_struct(DBusMessageIter *array)
572 DBusMessageIter entry;
574 for (list = technology_list; list; list = list->next) {
575 struct connman_technology *technology = list->data;
577 if (technology->path == NULL ||
578 (technology->rfkill_driven == TRUE &&
579 technology->hardblocked == TRUE))
582 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
584 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
586 append_properties(&entry, technology);
587 dbus_message_iter_close_container(array, &entry);
591 static gboolean technology_pending_reply(gpointer user_data)
593 struct connman_technology *technology = user_data;
596 /* Power request timedout, send ETIMEDOUT. */
597 if (technology->pending_reply != NULL) {
598 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
600 g_dbus_send_message(connection, reply);
602 dbus_message_unref(technology->pending_reply);
603 technology->pending_reply = NULL;
604 technology->pending_timeout = 0;
610 static int technology_affect_devices(struct connman_technology *technology,
611 connman_bool_t enable_device)
616 for (list = technology->device_list; list; list = list->next) {
617 struct connman_device *device = list->data;
619 if (enable_device == TRUE)
620 err = __connman_device_enable(device);
622 err = __connman_device_disable(device);
628 static int technology_enable(struct connman_technology *technology)
633 DBG("technology %p enable", technology);
635 __sync_synchronize();
636 if (technology->enabled == TRUE)
639 if (technology->pending_reply != NULL)
642 if (technology->rfkill_driven == TRUE)
643 err = __connman_rfkill_block(technology->type, FALSE);
645 err_dev = technology_affect_devices(technology, TRUE);
647 if (technology->rfkill_driven == FALSE)
653 static int technology_disable(struct connman_technology *technology)
657 DBG("technology %p disable", technology);
659 __sync_synchronize();
660 if (technology->enabled == FALSE)
663 if (technology->pending_reply != NULL)
666 if (technology->tethering == TRUE)
667 set_tethering(technology, FALSE);
669 err = technology_affect_devices(technology, FALSE);
671 if (technology->rfkill_driven == TRUE)
672 err = __connman_rfkill_block(technology->type, TRUE);
677 static DBusMessage *set_powered(struct connman_technology *technology,
678 DBusMessage *msg, connman_bool_t powered)
680 DBusMessage *reply = NULL;
683 if (technology->rfkill_driven && technology->hardblocked == TRUE) {
689 err = technology_enable(technology);
691 err = technology_disable(technology);
694 technology->enable_persistent = powered;
695 technology_save(technology);
699 if (err == -EINPROGRESS) {
700 technology->pending_reply = dbus_message_ref(msg);
701 technology->pending_timeout = g_timeout_add_seconds(10,
702 technology_pending_reply, technology);
703 } else if (err == -EALREADY) {
705 reply = __connman_error_already_enabled(msg);
707 reply = __connman_error_already_disabled(msg);
709 reply = __connman_error_failed(msg, -err);
711 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
716 static DBusMessage *set_property(DBusConnection *conn,
717 DBusMessage *msg, void *data)
719 struct connman_technology *technology = data;
720 DBusMessageIter iter, value;
724 DBG("conn %p", conn);
726 if (dbus_message_iter_init(msg, &iter) == FALSE)
727 return __connman_error_invalid_arguments(msg);
729 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
730 return __connman_error_invalid_arguments(msg);
732 dbus_message_iter_get_basic(&iter, &name);
733 dbus_message_iter_next(&iter);
735 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
736 return __connman_error_invalid_arguments(msg);
738 dbus_message_iter_recurse(&iter, &value);
740 type = dbus_message_iter_get_arg_type(&value);
742 DBG("property %s", name);
744 if (g_str_equal(name, "Tethering") == TRUE) {
746 connman_bool_t tethering;
748 if (type != DBUS_TYPE_BOOLEAN)
749 return __connman_error_invalid_arguments(msg);
751 dbus_message_iter_get_basic(&value, &tethering);
753 if (technology->tethering == tethering) {
754 if (tethering == FALSE)
755 return __connman_error_already_disabled(msg);
757 return __connman_error_already_enabled(msg);
760 err = set_tethering(technology, tethering);
762 return __connman_error_failed(msg, -err);
764 } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
767 dbus_message_iter_get_basic(&value, &str);
769 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
770 return __connman_error_not_supported(msg);
772 if (strlen(str) < 1 || strlen(str) > 32)
773 return __connman_error_invalid_arguments(msg);
775 if (g_strcmp0(technology->tethering_ident, str) != 0) {
776 g_free(technology->tethering_ident);
777 technology->tethering_ident = g_strdup(str);
778 technology_save(technology);
780 connman_dbus_property_changed_basic(technology->path,
781 CONNMAN_TECHNOLOGY_INTERFACE,
782 "TetheringIdentifier",
784 &technology->tethering_ident);
786 } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
789 dbus_message_iter_get_basic(&value, &str);
791 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
792 return __connman_error_not_supported(msg);
794 if (strlen(str) < 8 || strlen(str) > 63)
795 return __connman_error_passphrase_required(msg);
797 if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
798 g_free(technology->tethering_passphrase);
799 technology->tethering_passphrase = g_strdup(str);
800 technology_save(technology);
802 connman_dbus_property_changed_basic(technology->path,
803 CONNMAN_TECHNOLOGY_INTERFACE,
804 "TetheringPassphrase",
806 &technology->tethering_passphrase);
808 } else if (g_str_equal(name, "Powered") == TRUE) {
809 connman_bool_t enable;
811 if (type != DBUS_TYPE_BOOLEAN)
812 return __connman_error_invalid_arguments(msg);
814 dbus_message_iter_get_basic(&value, &enable);
816 return set_powered(technology, msg, enable);
818 return __connman_error_invalid_property(msg);
820 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
823 static struct connman_technology *technology_find(enum connman_service_type type)
827 DBG("type %d", type);
829 for (list = technology_list; list; list = list->next) {
830 struct connman_technology *technology = list->data;
832 if (technology->type == type)
839 static void reply_scan_pending(struct connman_technology *technology, int err)
843 DBG("technology %p err %d", technology, err);
845 while (technology->scan_pending != NULL) {
846 DBusMessage *msg = technology->scan_pending->data;
848 DBG("reply to %s", dbus_message_get_sender(msg));
851 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
853 reply = __connman_error_failed(msg, -err);
854 g_dbus_send_message(connection, reply);
855 dbus_message_unref(msg);
857 technology->scan_pending =
858 g_slist_delete_link(technology->scan_pending,
859 technology->scan_pending);
863 void __connman_technology_scan_started(struct connman_device *device)
865 DBG("device %p", device);
868 void __connman_technology_scan_stopped(struct connman_device *device)
871 struct connman_technology *technology;
872 enum connman_service_type type;
875 type = __connman_device_get_service_type(device);
876 technology = technology_find(type);
878 DBG("technology %p device %p", technology, device);
880 if (technology == NULL)
883 for (list = technology->device_list; list != NULL; list = list->next) {
884 struct connman_device *other_device = list->data;
886 if (device == other_device)
889 if (__connman_device_get_service_type(other_device) != type)
892 if (connman_device_get_scanning(other_device) == TRUE)
897 reply_scan_pending(technology, 0);
900 void __connman_technology_notify_regdom_by_device(struct connman_device *device,
901 int result, const char *alpha2)
903 connman_bool_t regdom_set = FALSE;
904 struct connman_technology *technology;
905 enum connman_service_type type;
906 GSList *tech_drivers;
908 type = __connman_device_get_service_type(device);
909 technology = technology_find(type);
911 if (technology == NULL)
916 for (tech_drivers = technology->driver_list;
917 tech_drivers != NULL;
918 tech_drivers = g_slist_next(tech_drivers)) {
919 struct connman_technology_driver *driver =
922 if (driver->set_regdom != NULL) {
923 driver->set_regdom(technology, alpha2);
929 if (regdom_set == FALSE)
933 connman_technology_regdom_notify(technology, alpha2);
936 static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
938 struct connman_technology *technology = data;
941 DBG ("technology %p request from %s", technology,
942 dbus_message_get_sender(msg));
944 dbus_message_ref(msg);
945 technology->scan_pending =
946 g_slist_prepend(technology->scan_pending, msg);
948 err = __connman_device_request_scan(technology->type);
950 reply_scan_pending(technology, err);
955 static const GDBusMethodTable technology_methods[] = {
956 { GDBUS_DEPRECATED_METHOD("GetProperties",
957 NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
959 { GDBUS_ASYNC_METHOD("SetProperty",
960 GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
961 NULL, set_property) },
962 { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
966 static const GDBusSignalTable technology_signals[] = {
967 { GDBUS_SIGNAL("PropertyChanged",
968 GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
972 static gboolean technology_dbus_register(struct connman_technology *technology)
974 if (technology->dbus_registered == TRUE ||
975 (technology->rfkill_driven == TRUE &&
976 technology->hardblocked == TRUE))
979 if (g_dbus_register_interface(connection, technology->path,
980 CONNMAN_TECHNOLOGY_INTERFACE,
981 technology_methods, technology_signals,
982 NULL, technology, NULL) == FALSE) {
983 connman_error("Failed to register %s", technology->path);
987 technology_added_signal(technology);
988 technology->dbus_registered = TRUE;
993 static struct connman_technology *technology_get(enum connman_service_type type)
995 GSList *tech_drivers = NULL;
996 struct connman_technology_driver *driver;
997 struct connman_technology *technology;
1001 DBG("type %d", type);
1003 str = __connman_service_type2string(type);
1007 technology = technology_find(type);
1008 if (technology != NULL) {
1009 __sync_fetch_and_add(&technology->refcount, 1);
1013 /* First check if we have a driver for this technology type */
1014 for (list = driver_list; list; list = list->next) {
1015 driver = list->data;
1017 if (driver->type == type) {
1018 DBG("technology %p driver %p", technology, driver);
1019 tech_drivers = g_slist_append(tech_drivers, driver);
1023 if (tech_drivers == NULL) {
1024 DBG("No matching drivers found for %s.",
1025 __connman_service_type2string(type));
1029 technology = g_try_new0(struct connman_technology, 1);
1030 if (technology == NULL)
1033 technology->refcount = 1;
1035 technology->rfkill_driven = FALSE;
1036 technology->softblocked = FALSE;
1037 technology->hardblocked = FALSE;
1039 technology->type = type;
1040 technology->path = g_strdup_printf("%s/technology/%s",
1043 technology->device_list = NULL;
1045 technology->pending_reply = NULL;
1047 technology_load(technology);
1049 if (technology_dbus_register(technology) == FALSE) {
1054 technology_list = g_slist_prepend(technology_list, technology);
1056 technology->driver_list = tech_drivers;
1058 for (list = tech_drivers; list != NULL; list = g_slist_next(list)) {
1059 driver = list->data;
1061 if (driver->probe != NULL && driver->probe(technology) < 0)
1062 DBG("Driver probe failed for technology %p",
1066 DBG("technology %p", technology);
1071 static void technology_dbus_unregister(struct connman_technology *technology)
1073 if (technology->dbus_registered == FALSE)
1076 technology_removed_signal(technology);
1077 g_dbus_unregister_interface(connection, technology->path,
1078 CONNMAN_TECHNOLOGY_INTERFACE);
1080 technology->dbus_registered = FALSE;
1083 static void technology_put(struct connman_technology *technology)
1085 DBG("technology %p", technology);
1087 if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
1090 reply_scan_pending(technology, -EINTR);
1092 while (technology->driver_list != NULL) {
1093 struct connman_technology_driver *driver;
1095 driver = technology->driver_list->data;
1097 if (driver->remove != NULL)
1098 driver->remove(technology);
1100 technology->driver_list =
1101 g_slist_delete_link(technology->driver_list,
1102 technology->driver_list);
1105 technology_list = g_slist_remove(technology_list, technology);
1107 technology_dbus_unregister(technology);
1109 g_slist_free(technology->device_list);
1111 g_free(technology->path);
1112 g_free(technology->regdom);
1113 g_free(technology->tethering_ident);
1114 g_free(technology->tethering_passphrase);
1118 void __connman_technology_add_interface(enum connman_service_type type,
1119 int index, const char *name, const char *ident)
1121 struct connman_technology *technology;
1122 GSList *tech_drivers;
1123 struct connman_technology_driver *driver;
1126 case CONNMAN_SERVICE_TYPE_UNKNOWN:
1127 case CONNMAN_SERVICE_TYPE_SYSTEM:
1129 case CONNMAN_SERVICE_TYPE_ETHERNET:
1130 case CONNMAN_SERVICE_TYPE_WIFI:
1131 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1132 case CONNMAN_SERVICE_TYPE_CELLULAR:
1133 case CONNMAN_SERVICE_TYPE_GPS:
1134 case CONNMAN_SERVICE_TYPE_VPN:
1135 case CONNMAN_SERVICE_TYPE_GADGET:
1139 connman_info("Adding interface %s [ %s ]", name,
1140 __connman_service_type2string(type));
1142 technology = technology_find(type);
1144 if (technology == NULL)
1147 for (tech_drivers = technology->driver_list; tech_drivers != NULL;
1148 tech_drivers = g_slist_next(tech_drivers)) {
1149 driver = tech_drivers->data;
1151 if(driver->add_interface != NULL)
1152 driver->add_interface(technology, index, name, ident);
1156 void __connman_technology_remove_interface(enum connman_service_type type,
1157 int index, const char *name, const char *ident)
1159 struct connman_technology *technology;
1160 GSList *tech_drivers;
1161 struct connman_technology_driver *driver;
1164 case CONNMAN_SERVICE_TYPE_UNKNOWN:
1165 case CONNMAN_SERVICE_TYPE_SYSTEM:
1167 case CONNMAN_SERVICE_TYPE_ETHERNET:
1168 case CONNMAN_SERVICE_TYPE_WIFI:
1169 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1170 case CONNMAN_SERVICE_TYPE_CELLULAR:
1171 case CONNMAN_SERVICE_TYPE_GPS:
1172 case CONNMAN_SERVICE_TYPE_VPN:
1173 case CONNMAN_SERVICE_TYPE_GADGET:
1177 connman_info("Remove interface %s [ %s ]", name,
1178 __connman_service_type2string(type));
1180 technology = technology_find(type);
1182 if (technology == NULL)
1185 for (tech_drivers = technology->driver_list; tech_drivers != NULL;
1186 tech_drivers = g_slist_next(tech_drivers)) {
1187 driver = tech_drivers->data;
1189 if(driver->remove_interface != NULL)
1190 driver->remove_interface(technology, index);
1194 int __connman_technology_add_device(struct connman_device *device)
1196 struct connman_technology *technology;
1197 enum connman_service_type type;
1199 DBG("device %p", device);
1201 type = __connman_device_get_service_type(device);
1203 technology = technology_get(type);
1204 if (technology == NULL) {
1206 * Since no driver can be found for this device at the moment we
1207 * add it to the techless device list.
1209 techless_device_list = g_slist_prepend(techless_device_list,
1215 __sync_synchronize();
1216 if (technology->rfkill_driven == TRUE) {
1217 if (technology->enabled == TRUE)
1218 __connman_device_enable(device);
1220 __connman_device_disable(device);
1225 if (technology->enable_persistent == TRUE &&
1226 global_offlinemode == FALSE) {
1227 int err = __connman_device_enable(device);
1229 * connman_technology_add_device() calls __connman_device_enable()
1230 * but since the device is already enabled, the calls does not
1231 * propagate through to connman_technology_enabled via
1232 * connman_device_set_powered.
1234 if (err == -EALREADY)
1235 __connman_technology_enabled(type);
1237 /* if technology persistent state is offline */
1238 if (technology->enable_persistent == FALSE)
1239 __connman_device_disable(device);
1242 technology->device_list = g_slist_prepend(technology->device_list,
1248 int __connman_technology_remove_device(struct connman_device *device)
1250 struct connman_technology *technology;
1251 enum connman_service_type type;
1253 DBG("device %p", device);
1255 type = __connman_device_get_service_type(device);
1257 technology = technology_find(type);
1258 if (technology == NULL) {
1259 techless_device_list = g_slist_remove(techless_device_list,
1264 technology->device_list = g_slist_remove(technology->device_list,
1266 technology_put(technology);
1271 static void powered_changed(struct connman_technology *technology)
1273 if (technology->dbus_registered == FALSE)
1276 if (technology->pending_reply != NULL) {
1277 g_dbus_send_reply(connection,
1278 technology->pending_reply, DBUS_TYPE_INVALID);
1279 dbus_message_unref(technology->pending_reply);
1280 technology->pending_reply = NULL;
1282 g_source_remove(technology->pending_timeout);
1283 technology->pending_timeout = 0;
1286 __sync_synchronize();
1287 connman_dbus_property_changed_basic(technology->path,
1288 CONNMAN_TECHNOLOGY_INTERFACE, "Powered",
1289 DBUS_TYPE_BOOLEAN, &technology->enabled);
1292 static int technology_enabled(struct connman_technology *technology)
1294 __sync_synchronize();
1295 if (technology->enabled == TRUE)
1298 technology->enabled = TRUE;
1300 powered_changed(technology);
1305 int __connman_technology_enabled(enum connman_service_type type)
1307 struct connman_technology *technology;
1309 technology = technology_find(type);
1310 if (technology == NULL)
1313 if (technology->rfkill_driven == TRUE)
1316 return technology_enabled(technology);
1319 static int technology_disabled(struct connman_technology *technology)
1321 __sync_synchronize();
1322 if (technology->enabled == FALSE)
1325 technology->enabled = FALSE;
1327 powered_changed(technology);
1332 int __connman_technology_disabled(enum connman_service_type type)
1334 struct connman_technology *technology;
1337 technology = technology_find(type);
1338 if (technology == NULL)
1341 if (technology->rfkill_driven == TRUE)
1344 for (list = technology->device_list; list != NULL; list = list->next) {
1345 struct connman_device *device = list->data;
1347 if (connman_device_get_powered(device) == TRUE)
1351 return technology_disabled(technology);
1354 int __connman_technology_set_offlinemode(connman_bool_t offlinemode)
1359 if (global_offlinemode == offlinemode)
1362 DBG("offlinemode %s", offlinemode ? "On" : "Off");
1365 * This is a bit tricky. When you set offlinemode, there is no
1366 * way to differentiate between attempting offline mode and
1367 * resuming offlinemode from last saved profile. We need that
1368 * information in rfkill_update, otherwise it falls back on the
1369 * technology's persistent state. Hence we set the offline mode here
1370 * but save it & call the notifier only if its successful.
1373 global_offlinemode = offlinemode;
1375 /* Traverse technology list, enable/disable each technology. */
1376 for (list = technology_list; list; list = list->next) {
1377 struct connman_technology *technology = list->data;
1380 err = technology_disable(technology);
1382 if (!offlinemode && technology->enable_persistent)
1383 err = technology_enable(technology);
1386 if (err == 0 || err == -EINPROGRESS || err == -EALREADY) {
1387 connman_technology_save_offlinemode();
1388 __connman_notifier_offlinemode(offlinemode);
1390 global_offlinemode = connman_technology_load_offlinemode();
1395 void __connman_technology_set_connected(enum connman_service_type type,
1396 connman_bool_t connected)
1398 struct connman_technology *technology;
1400 technology = technology_find(type);
1401 if (technology == NULL)
1404 DBG("technology %p connected %d", technology, connected);
1406 technology->connected = connected;
1408 connman_dbus_property_changed_basic(technology->path,
1409 CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
1410 DBUS_TYPE_BOOLEAN, &connected);
1413 static connman_bool_t technology_apply_rfkill_change(struct connman_technology *technology,
1414 connman_bool_t softblock,
1415 connman_bool_t hardblock,
1416 connman_bool_t new_rfkill)
1418 gboolean hardblock_changed = FALSE;
1419 gboolean apply = TRUE;
1420 GList *start, *list;
1422 DBG("technology %p --> %d/%d vs %d/%d",
1423 technology, softblock, hardblock,
1424 technology->softblocked, technology->hardblocked);
1426 if (technology->hardblocked == hardblock)
1427 goto softblock_change;
1429 if (!(new_rfkill == TRUE && hardblock == FALSE)) {
1430 start = g_hash_table_get_values(rfkill_list);
1432 for (list = start; list != NULL; list = list->next) {
1433 struct connman_rfkill *rfkill = list->data;
1435 if (rfkill->type != technology->type)
1438 if (rfkill->hardblock != hardblock)
1446 goto softblock_change;
1448 technology->hardblocked = hardblock;
1449 hardblock_changed = TRUE;
1452 if (apply == FALSE && technology->softblocked != softblock)
1456 return technology->hardblocked;
1458 technology->softblocked = softblock;
1460 if (technology->hardblocked == TRUE ||
1461 technology->softblocked == TRUE) {
1462 if (technology_disabled(technology) != -EALREADY)
1463 technology_affect_devices(technology, FALSE);
1464 } else if (technology->hardblocked == FALSE &&
1465 technology->softblocked == FALSE) {
1466 if (technology_enabled(technology) != -EALREADY)
1467 technology_affect_devices(technology, TRUE);
1470 if (hardblock_changed == TRUE) {
1471 if (technology->hardblocked == TRUE) {
1472 DBG("%s is switched off.", get_name(technology->type));
1473 technology_dbus_unregister(technology);
1475 technology_dbus_register(technology);
1478 return technology->hardblocked;
1481 int __connman_technology_add_rfkill(unsigned int index,
1482 enum connman_service_type type,
1483 connman_bool_t softblock,
1484 connman_bool_t hardblock)
1486 struct connman_technology *technology;
1487 struct connman_rfkill *rfkill;
1489 DBG("index %u type %d soft %u hard %u", index, type,
1490 softblock, hardblock);
1492 rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1496 rfkill = g_try_new0(struct connman_rfkill, 1);
1500 rfkill->index = index;
1501 rfkill->type = type;
1502 rfkill->softblock = softblock;
1503 rfkill->hardblock = hardblock;
1505 g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
1508 technology = technology_get(type);
1509 /* If there is no driver for this type, ignore it. */
1510 if (technology == NULL)
1513 technology->rfkill_driven = TRUE;
1515 /* If hardblocked, there is no need to handle softblocked state */
1516 if (technology_apply_rfkill_change(technology,
1517 softblock, hardblock, TRUE) == TRUE)
1521 * Depending on softblocked state we unblock/block according to
1522 * offlinemode and persistente state.
1524 if (technology->softblocked == TRUE &&
1525 global_offlinemode == FALSE &&
1526 technology->enable_persistent == TRUE)
1527 return __connman_rfkill_block(type, FALSE);
1528 else if (technology->softblocked == FALSE &&
1529 (global_offlinemode == TRUE ||
1530 technology->enable_persistent == FALSE))
1531 return __connman_rfkill_block(type, TRUE);
1536 int __connman_technology_update_rfkill(unsigned int index,
1537 enum connman_service_type type,
1538 connman_bool_t softblock,
1539 connman_bool_t hardblock)
1541 struct connman_technology *technology;
1542 struct connman_rfkill *rfkill;
1544 DBG("index %u soft %u hard %u", index, softblock, hardblock);
1546 rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1550 if (rfkill->softblock == softblock &&
1551 rfkill->hardblock == hardblock)
1554 rfkill->softblock = softblock;
1555 rfkill->hardblock = hardblock;
1557 technology = technology_find(type);
1558 /* If there is no driver for this type, ignore it. */
1559 if (technology == NULL)
1562 /* If hardblocked, there is no need to handle softblocked state */
1563 if (technology_apply_rfkill_change(technology,
1564 softblock, hardblock, FALSE) == TRUE)
1567 if (global_offlinemode == TRUE)
1571 * Depending on softblocked state we unblock/block according to
1574 if (technology->softblocked == TRUE &&
1575 technology->enable_persistent == TRUE)
1576 return __connman_rfkill_block(type, FALSE);
1577 else if (technology->softblocked == FALSE &&
1578 technology->enable_persistent == FALSE)
1579 return __connman_rfkill_block(type, TRUE);
1584 int __connman_technology_remove_rfkill(unsigned int index,
1585 enum connman_service_type type)
1587 struct connman_technology *technology;
1588 struct connman_rfkill *rfkill;
1590 DBG("index %u", index);
1592 rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1596 g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
1598 technology = technology_find(type);
1599 if (technology == NULL)
1602 technology_apply_rfkill_change(technology,
1603 technology->softblocked, !technology->hardblocked, FALSE);
1605 technology_put(technology);
1610 int __connman_technology_init(void)
1614 connection = connman_dbus_get_connection();
1616 rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1619 global_offlinemode = connman_technology_load_offlinemode();
1621 /* This will create settings file if it is missing */
1622 connman_technology_save_offlinemode();
1627 void __connman_technology_cleanup(void)
1631 g_hash_table_destroy(rfkill_list);
1633 dbus_connection_unref(connection);