diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2010-05-17 17:32:26 +0200 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2010-05-17 17:32:26 +0200 |
commit | 1e4d4fe0ed499adaf3e61b1e593dccd3c0928158 (patch) | |
tree | b990d40549df8e7609176c7a9b0b024137084d25 | |
parent | 38a7ef119c1ee1637a4f334dd055b8a171cdf148 (diff) |
Add new "Blocked" property to device objects
This patch adds a new "Blocked" property to device objects. It maps
directly to the HCIBLOCKDEV and HCIUNBLOCKDEV ioctl's which enable
control of incoming connection acceptance on the kernel side.
-rw-r--r-- | doc/device-api.txt | 7 | ||||
-rw-r--r-- | src/adapter.c | 38 | ||||
-rw-r--r-- | src/device.c | 213 | ||||
-rw-r--r-- | src/storage.c | 34 | ||||
-rw-r--r-- | src/storage.h | 3 | ||||
-rwxr-xr-x | test/test-device | 20 |
6 files changed, 279 insertions, 36 deletions
diff --git a/doc/device-api.txt b/doc/device-api.txt index efd37660..b8182997 100644 --- a/doc/device-api.txt +++ b/doc/device-api.txt @@ -154,6 +154,13 @@ Properties string Address [readonly] Indicates if the remote is seen as trusted. This setting can be changed by the application. + boolean Blocked [readwrite] + + If set to true any incoming connections from the + device will be immediately rejected. Any device + drivers will also be removed and no new ones will + be probed as long as the device is blocked. + string Alias [readwrite] The name alias for the remote device. The alias can diff --git a/src/adapter.c b/src/adapter.c index f246a792..fb401716 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -2022,6 +2022,23 @@ static void create_stored_device_from_linkkeys(char *key, char *value, } } +static void create_stored_device_from_blocked(char *key, char *value, + void *user_data) +{ + struct btd_adapter *adapter = user_data; + struct btd_device *device; + + if (g_slist_find_custom(adapter->devices, + key, (GCompareFunc) device_address_cmp)) + return; + + device = device_create(connection, adapter, key); + if (device) { + device_set_temporary(device, FALSE); + adapter->devices = g_slist_append(adapter->devices, device); + } +} + static void load_devices(struct btd_adapter *adapter) { char filename[PATH_MAX + 1]; @@ -2036,6 +2053,26 @@ static void load_devices(struct btd_adapter *adapter) create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys"); textfile_foreach(filename, create_stored_device_from_linkkeys, adapter); + + create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked"); + textfile_foreach(filename, create_stored_device_from_blocked, adapter); +} + +static void clear_blocked(struct btd_adapter *adapter) +{ + int dd; + + dd = hci_open_dev(adapter->dev_id); + if (dd < 0) { + error("hci_open_dev(hci%d): %s (%d)", adapter->dev_id, + strerror(errno), errno); + return; + } + + if (ioctl(dd, HCIUNBLOCKADDR, BDADDR_ANY) < 0) + error("ioctl(HCIUNBLOCKADDR): %s (%d)", strerror(errno), errno); + + hci_close_dev(dd); } static void probe_driver(gpointer data, gpointer user_data) @@ -2205,6 +2242,7 @@ proceed: if (adapter->initialized == FALSE) { load_drivers(adapter); + clear_blocked(adapter); load_devices(adapter); /* retrieve the active connections: address the scenario where diff --git a/src/device.c b/src/device.c index 6ba16122..3d91ced1 100644 --- a/src/device.c +++ b/src/device.c @@ -31,6 +31,7 @@ #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> +#include <sys/ioctl.h> #include <errno.h> #include <bluetooth/bluetooth.h> @@ -137,6 +138,7 @@ struct btd_device { gboolean trusted; gboolean paired; + gboolean blocked; gboolean renewed_key; gboolean authorizing; @@ -336,6 +338,10 @@ static DBusMessage *get_properties(DBusConnection *conn, boolean = device_is_trusted(device); dict_append_entry(&dict, "Trusted", DBUS_TYPE_BOOLEAN, &boolean); + /* Blocked */ + boolean = device->blocked; + dict_append_entry(&dict, "Blocked", DBUS_TYPE_BOOLEAN, &boolean); + /* Connected */ boolean = (device->handle != 0); dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, @@ -424,6 +430,156 @@ static DBusMessage *set_trust(DBusConnection *conn, DBusMessage *msg, return dbus_message_new_method_return(msg); } +static void driver_remove(struct btd_driver_data *driver_data, + struct btd_device *device) +{ + struct btd_device_driver *driver = driver_data->driver; + + driver->remove(device); +} + +static void driver_free(struct btd_driver_data *driver_data, + struct btd_device *device) +{ + struct btd_device_driver *driver = driver_data->driver; + + driver->remove(device); + + g_free(driver); + g_free(driver_data); +} + +static gboolean do_disconnect(gpointer user_data) +{ + struct btd_device *device = user_data; + disconnect_cp cp; + int dd; + uint16_t dev_id = adapter_get_dev_id(device->adapter); + + device->disconn_timer = 0; + + dd = hci_open_dev(dev_id); + if (dd < 0) + goto fail; + + memset(&cp, 0, sizeof(cp)); + cp.handle = htobs(device->handle); + cp.reason = HCI_OE_USER_ENDED_CONNECTION; + + hci_send_cmd(dd, OGF_LINK_CTL, OCF_DISCONNECT, + DISCONNECT_CP_SIZE, &cp); + + close(dd); + +fail: + return FALSE; +} + +static int device_block(DBusConnection *conn, struct btd_device *device) +{ + int dev_id, dd, err; + bdaddr_t src; + + if (device->blocked) + return 0; + + dev_id = adapter_get_dev_id(device->adapter); + + dd = hci_open_dev(dev_id); + if (dd < 0) + return -errno; + + if (device->handle) + do_disconnect(device); + + g_slist_foreach(device->drivers, (GFunc) driver_remove, device); + + if (ioctl(dd, HCIBLOCKADDR, &device->bdaddr) < 0) { + err = -errno; + hci_close_dev(dd); + return err; + } + + hci_close_dev(dd); + + device->blocked = TRUE; + + adapter_get_address(device->adapter, &src); + + err = write_blocked(&src, &device->bdaddr, TRUE); + if (err < 0) + error("write_blocked(): %s (%d)", strerror(-err), -err); + + device_set_temporary(device, FALSE); + + emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Blocked", + DBUS_TYPE_BOOLEAN, &device->blocked); + + return 0; +} + +static int device_unblock(DBusConnection *conn, struct btd_device *device) +{ + int dev_id, dd, err; + bdaddr_t src; + + if (!device->blocked) + return 0; + + dev_id = adapter_get_dev_id(device->adapter); + + dd = hci_open_dev(dev_id); + if (dd < 0) + return -errno; + + if (ioctl(dd, HCIUNBLOCKADDR, &device->bdaddr) < 0) { + err = -errno; + hci_close_dev(dd); + return err; + } + + hci_close_dev(dd); + + device->blocked = FALSE; + + adapter_get_address(device->adapter, &src); + + err = write_blocked(&src, &device->bdaddr, FALSE); + if (err < 0) + error("write_blocked(): %s (%d)", strerror(-err), -err); + + emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Blocked", + DBUS_TYPE_BOOLEAN, &device->blocked); + + device_probe_drivers(device, device->uuids); + + return 0; +} + +static DBusMessage *set_blocked(DBusConnection *conn, DBusMessage *msg, + gboolean value, void *data) +{ + struct btd_device *device = data; + int err; + + if (value) + err = device_block(conn, device); + else + err = device_unblock(conn, device); + + switch (-err) { + case 0: + return dbus_message_new_method_return(msg); + case EINVAL: + return g_dbus_create_error(msg, + ERROR_INTERFACE ".NotSupported", + "Kernel lacks blacklist support"); + default: + return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", + "%s", strerror(-err)); + } +} + static inline DBusMessage *invalid_args(DBusMessage *msg) { return g_dbus_create_error(msg, @@ -453,7 +609,6 @@ static DBusMessage *set_property(DBusConnection *conn, if (g_str_equal("Trusted", property)) { dbus_bool_t value; - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) return invalid_args(msg); dbus_message_iter_get_basic(&sub, &value); @@ -467,6 +622,15 @@ static DBusMessage *set_property(DBusConnection *conn, dbus_message_iter_get_basic(&sub, &alias); return set_alias(conn, msg, alias, data); + } else if (g_str_equal("Blocked", property)) { + dbus_bool_t value; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) + return invalid_args(msg); + + dbus_message_iter_get_basic(&sub, &value); + + return set_blocked(conn, msg, value, data); } return invalid_args(msg); @@ -631,32 +795,6 @@ static DBusMessage *cancel_discover(DBusConnection *conn, return dbus_message_new_method_return(msg); } -static gboolean do_disconnect(gpointer user_data) -{ - struct btd_device *device = user_data; - disconnect_cp cp; - int dd; - uint16_t dev_id = adapter_get_dev_id(device->adapter); - - device->disconn_timer = 0; - - dd = hci_open_dev(dev_id); - if (dd < 0) - goto fail; - - memset(&cp, 0, sizeof(cp)); - cp.handle = htobs(device->handle); - cp.reason = HCI_OE_USER_ENDED_CONNECTION; - - hci_send_cmd(dd, OGF_LINK_CTL, OCF_DISCONNECT, - DISCONNECT_CP_SIZE, &cp); - - close(dd); - -fail: - return FALSE; -} - static void bonding_request_cancel(struct bonding_req *bonding) { if (!bonding->io) @@ -898,6 +1036,9 @@ struct btd_device *device_create(DBusConnection *conn, device->alias = g_strdup(alias); device->trusted = read_trust(&src, address, GLOBAL_TRUST); + if (read_blocked(&src, &device->bdaddr)) + device_block(conn, device); + device->auth = 0xff; if (read_link_key(&src, &device->bdaddr, NULL, NULL) == 0) @@ -978,8 +1119,6 @@ static void device_remove_stored(struct btd_device *device) void device_remove(struct btd_device *device, gboolean remove_stored) { - GSList *list; - struct btd_device_driver *driver; debug("Removing device %s", device->path); @@ -995,13 +1134,9 @@ void device_remove(struct btd_device *device, gboolean remove_stored) if (remove_stored) device_remove_stored(device); - for (list = device->drivers; list; list = list->next) { - struct btd_driver_data *driver_data = list->data; - driver = driver_data->driver; - - driver->remove(device); - g_free(driver_data); - } + g_slist_foreach(device->drivers, (GFunc) driver_free, device); + g_slist_free(device->drivers); + device->drivers = NULL; btd_device_unref(device); } @@ -1096,6 +1231,11 @@ void device_probe_drivers(struct btd_device *device, GSList *profiles) GSList *list; int err; + if (device->blocked) { + debug("Skipping drivers for blocked device %s", device->path); + goto add_uuids; + } + debug("Probe drivers for %s", device->path); for (list = device_drivers; list; list = list->next) { @@ -1125,6 +1265,7 @@ void device_probe_drivers(struct btd_device *device, GSList *profiles) g_slist_free(probe_uuids); } +add_uuids: for (list = profiles; list; list = list->next) { GSList *l = g_slist_find_custom(device->uuids, list->data, (GCompareFunc) strcasecmp); diff --git a/src/storage.c b/src/storage.c index 981c7440..ed1e5ec4 100644 --- a/src/storage.c +++ b/src/storage.c @@ -1205,3 +1205,37 @@ int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode) return 0; } + +gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote) +{ + char filename[PATH_MAX + 1], *str, addr[18]; + + create_filename(filename, PATH_MAX, local, "blocked"); + + ba2str(remote, addr); + + str = textfile_caseget(filename, addr); + if (!str) + return FALSE; + + free(str); + + return TRUE; +} + +int write_blocked(const bdaddr_t *local, const bdaddr_t *remote, + gboolean blocked) +{ + char filename[PATH_MAX + 1], addr[18]; + + create_filename(filename, PATH_MAX, local, "blocked"); + + create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + ba2str(remote, addr); + + if (blocked == FALSE) + return textfile_casedel(filename, addr); + + return textfile_caseput(filename, addr, ""); +} diff --git a/src/storage.h b/src/storage.h index ed507342..eee71d39 100644 --- a/src/storage.h +++ b/src/storage.h @@ -75,6 +75,9 @@ int read_device_id(const gchar *src, const gchar *dst, uint16_t *product, uint16_t *version); int write_device_pairable(bdaddr_t *local, gboolean mode); int read_device_pairable(bdaddr_t *local, gboolean *mode); +gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote); +int write_blocked(const bdaddr_t *local, const bdaddr_t *remote, + gboolean blocked); #define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb" diff --git a/test/test-device b/test/test-device index f8f2d14a..2322122c 100755 --- a/test/test-device +++ b/test/test-device @@ -124,5 +124,25 @@ if (sys.argv[1] == "trusted"): device.SetProperty("Trusted", value) sys.exit(0) +if (sys.argv[1] == "blocked"): + if (len(sys.argv) < 3): + print "Need address parameter" + else: + path = adapter.FindDevice(sys.argv[2]) + device = dbus.Interface(bus.get_object("org.bluez", path), + "org.bluez.Device") + if (len(sys.argv) < 4): + properties = device.GetProperties() + print properties["Blocked"] + else: + if (sys.argv[3] == "yes"): + value = dbus.Boolean(1) + elif (sys.argv[3] == "no"): + value = dbus.Boolean(0) + else: + value = dbus.Boolean(sys.argv[3]) + device.SetProperty("Blocked", value) + sys.exit(0) + print "Unknown command" sys.exit(1) |