diff options
-rw-r--r-- | doc/adapter-api.txt | 9 | ||||
-rw-r--r-- | src/adapter.c | 68 | ||||
-rw-r--r-- | src/adapter.h | 2 | ||||
-rw-r--r-- | src/dbus-hci.c | 8 | ||||
-rw-r--r-- | src/storage.c | 30 | ||||
-rw-r--r-- | src/storage.h | 2 |
6 files changed, 117 insertions, 2 deletions
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt index a13273f8..d0adf189 100644 --- a/doc/adapter-api.txt +++ b/doc/adapter-api.txt @@ -266,6 +266,15 @@ Properties string Address [readonly] this property will be updated via a PropertyChanged signal. + boolean Pairable [readwrite] + + Switch an adapter to pairable or non-pairable. This is + a global setting and should only be used by the + settings application. + + Note that this property only affects incoming pairing + requests. + uint32 DiscoverableTimeout [readwrite] The discoverable timeout in seconds. A value of zero diff --git a/src/adapter.c b/src/adapter.c index 1f20cb40..8d76d4b2 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -114,6 +114,7 @@ struct btd_adapter { guint scheduler_id; /* Scheduler handle */ struct hci_dev dev; /* hci info */ + gboolean pairable; /* pairable state */ }; static inline DBusMessage *invalid_args(DBusMessage *msg) @@ -627,7 +628,7 @@ static DBusMessage *set_mode(DBusConnection *conn, DBusMessage *msg, adapter->discov_timeout_id = 0; } - if (!adapter->mode_sessions && !adapter->discov_timeout) + if (!adapter->mode_sessions && adapter->discov_timeout) adapter_set_discov_timeout(adapter, adapter->discov_timeout * 1000); } @@ -666,12 +667,40 @@ static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg, strmode = discoverable ? "discoverable" : "connectable"; mode = get_mode(&adapter->bdaddr, strmode); + if (mode == MODE_DISCOVERABLE && adapter->pairable) + mode = MODE_LIMITED; + if (mode == adapter->mode) return dbus_message_new_method_return(msg); return set_mode(conn, msg, mode, data); } +static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg, + gboolean pairable, void *data) +{ + struct btd_adapter *adapter = data; + + if (pairable == adapter->pairable) + goto done; + + adapter->pairable = pairable; + + write_device_pairable(&adapter->bdaddr, pairable); + + emit_property_changed(connection, adapter->path, + ADAPTER_INTERFACE, "Pairable", + DBUS_TYPE_BOOLEAN, &pairable); + + if (adapter->scan_mode & SCAN_INQUIRY) { + uint8_t mode = pairable ? MODE_LIMITED : MODE_DISCOVERABLE; + return set_mode(conn, msg, mode, data); + } + +done: + return dbus_message_new_method_return(msg); +} + static struct session_req *find_session(GSList *list, DBusMessage *msg) { GSList *l; @@ -1657,6 +1686,10 @@ static DBusMessage *get_properties(DBusConnection *conn, value = adapter->scan_mode & SCAN_INQUIRY ? TRUE : FALSE; dict_append_entry(&dict, "Discoverable", DBUS_TYPE_BOOLEAN, &value); + /* Pairable */ + dict_append_entry(&dict, "Pairable", DBUS_TYPE_BOOLEAN, + &adapter->pairable); + /* DiscoverableTimeout */ dict_append_entry(&dict, "DiscoverableTimeout", DBUS_TYPE_UINT32, &adapter->discov_timeout); @@ -1760,6 +1793,15 @@ static DBusMessage *set_property(DBusConnection *conn, dbus_message_iter_get_basic(&sub, &timeout); return set_discoverable_timeout(conn, msg, timeout, data); + } else if (g_str_equal("Pairable", property)) { + gboolean pairable; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) + return invalid_args(msg); + + dbus_message_iter_get_basic(&sub, &pairable); + + return set_pairable(conn, msg, pairable, data); } return invalid_args(msg); @@ -2409,6 +2451,10 @@ static void adapter_up(struct btd_adapter *adapter, int dd) adapter->discov_timeout = get_discoverable_timeout(srcaddr); adapter->state = DISCOVER_TYPE_NONE; + /* Set pairable mode */ + if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0) + adapter->pairable = TRUE; + /* Set scan mode */ if (read_device_mode(srcaddr, mode, sizeof(mode)) == 0) { if (!strcmp(mode, "off")) { @@ -2437,7 +2483,8 @@ static void adapter_up(struct btd_adapter *adapter, int dd) } else if (!strcmp(mode, "discoverable")) { /* Set discoverable only if timeout is 0 */ if (adapter->discov_timeout == 0) { - adapter->mode = MODE_DISCOVERABLE; + adapter->mode = adapter->pairable ? + MODE_LIMITED : MODE_DISCOVERABLE; adapter->scan_mode = SCAN_PAGE | SCAN_INQUIRY; } else { adapter->mode = MODE_CONNECTABLE; @@ -2497,6 +2544,10 @@ static void adapter_up(struct btd_adapter *adapter, int dd) ADAPTER_INTERFACE, "Discoverable", DBUS_TYPE_BOOLEAN, &discoverable); + emit_property_changed(connection, adapter->path, + ADAPTER_INTERFACE, "Pairable", + DBUS_TYPE_BOOLEAN, &adapter->pairable); + load_drivers(adapter); load_devices(adapter); } @@ -3496,3 +3547,16 @@ void btd_adapter_any_release_path(void) g_free(adapter_any_path); adapter_any_path = NULL; } + +gboolean adapter_is_pairable(struct btd_adapter *adapter) +{ + return adapter->pairable; +} + +gboolean adapter_pairing_initiator(struct btd_adapter *adapter, bdaddr_t *bda) +{ + if (!adapter->bonding) + return FALSE; + + return (bacmp(&adapter->bonding->bdaddr, bda) == 0); +} diff --git a/src/adapter.h b/src/adapter.h index 7d666a5b..eb206ac6 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -184,3 +184,5 @@ const char *adapter_any_get_path(void); const char *btd_adapter_any_request_path(void); void btd_adapter_any_release_path(void); +gboolean adapter_is_pairable(struct btd_adapter *adapter); +gboolean adapter_pairing_initiator(struct btd_adapter *adapter, bdaddr_t *bda); diff --git a/src/dbus-hci.c b/src/dbus-hci.c index 5b0a1f96..6f9f1bc5 100644 --- a/src/dbus-hci.c +++ b/src/dbus-hci.c @@ -239,6 +239,10 @@ int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci) return -1; } + if (!adapter_pairing_initiator(adapter, sba) && + !adapter_is_pairable(adapter)) + return -EPERM; + ba2str(&ci->bdaddr, addr); device = adapter_find_device(adapter, addr); @@ -1466,6 +1470,10 @@ int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote, if (get_auth_requirements(local, remote, auth) < 0) return -1; + if (!adapter_pairing_initiator(adapter, remote) && + !adapter_is_pairable(adapter)) + return -EPERM; + ba2str(remote, addr); /* For CreatePairedDevice use dedicated bonding */ diff --git a/src/storage.c b/src/storage.c index ac1ec5bd..212f7ce2 100644 --- a/src/storage.c +++ b/src/storage.c @@ -1028,3 +1028,33 @@ int read_device_id(const gchar *srcaddr, const gchar *dstaddr, return 0; } + +int write_device_pairable(bdaddr_t *bdaddr, gboolean mode) +{ + char filename[PATH_MAX + 1]; + + create_filename(filename, PATH_MAX, bdaddr, "config"); + + create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + return textfile_put(filename, "pairable", mode ? "yes" : "no"); +} + +int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode) +{ + char filename[PATH_MAX + 1], *str; + + create_filename(filename, PATH_MAX, bdaddr, "config"); + + create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + str = textfile_get(filename, "pairable"); + if (!str) + return -ENOENT; + + *mode = strcmp(str, "yes") == 0 ? TRUE : FALSE; + + free(str); + + return 0; +} diff --git a/src/storage.h b/src/storage.h index 29f08d80..b6bedbed 100644 --- a/src/storage.h +++ b/src/storage.h @@ -68,6 +68,8 @@ int store_device_id(const gchar *src, const gchar *dst, int read_device_id(const gchar *src, const gchar *dst, uint16_t *source, uint16_t *vendor, uint16_t *product, uint16_t *version); +int write_device_pairable(bdaddr_t *local, gboolean mode); +int read_device_pairable(bdaddr_t *local, gboolean *mode); #define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb" |