diff options
-rw-r--r-- | src/adapter.c | 229 | ||||
-rw-r--r-- | src/adapter.h | 1 | ||||
-rw-r--r-- | src/hcid.h | 1 | ||||
-rw-r--r-- | src/main.c | 11 | ||||
-rw-r--r-- | src/main.conf | 5 | ||||
-rw-r--r-- | src/storage.c | 33 | ||||
-rw-r--r-- | src/storage.h | 2 |
7 files changed, 208 insertions, 74 deletions
diff --git a/src/adapter.c b/src/adapter.c index 8d76d4b2..002aa376 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -94,7 +94,9 @@ struct btd_adapter { char *path; /* adapter object path */ bdaddr_t bdaddr; /* adapter Bluetooth Address */ guint discov_timeout_id; /* discoverable timeout id */ - uint32_t discov_timeout; /* discoverable time(msec) */ + uint32_t discov_timeout; /* discoverable time(sec) */ + guint pairable_timeout_id; /* pairable timeout id */ + uint32_t pairable_timeout; /* pairable time(sec) */ uint8_t scan_mode; /* scan mode: SCAN_DISABLED, SCAN_PAGE, SCAN_INQUIRY */ uint8_t mode; /* off, connectable, discoverable, limited */ uint8_t global_mode; /* last valid global mode */ @@ -117,6 +119,9 @@ struct btd_adapter { gboolean pairable; /* pairable state */ }; +static void adapter_set_pairable_timeout(struct btd_adapter *adapter, + guint interval); + static inline DBusMessage *invalid_args(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments", @@ -526,6 +531,71 @@ static uint8_t get_mode(const bdaddr_t *bdaddr, const char *mode) return MODE_UNKNOWN; } +static gboolean discov_timeout_handler(void *data) +{ + struct btd_adapter *adapter = data; + struct hci_request rq; + int dd; + uint8_t scan_enable = adapter->scan_mode; + uint8_t status = 0; + gboolean retval = TRUE; + uint16_t dev_id = adapter->dev_id; + + scan_enable &= ~SCAN_INQUIRY; + + dd = hci_open_dev(dev_id); + if (dd < 0) { + error("HCI device open failed: hci%d", dev_id); + return TRUE; + } + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_WRITE_SCAN_ENABLE; + rq.cparam = &scan_enable; + rq.clen = sizeof(scan_enable); + rq.rparam = &status; + rq.rlen = sizeof(status); + rq.event = EVT_CMD_COMPLETE; + + if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) { + error("Sending write scan enable command to hci%d failed: %s (%d)", + dev_id, strerror(errno), errno); + goto failed; + } + if (status) { + error("Setting scan enable failed with status 0x%02x", status); + goto failed; + } + + set_limited_discoverable(dd, adapter->dev.class, FALSE); + + adapter_remove_discov_timeout(adapter); + retval = FALSE; + +failed: + if (dd >= 0) + hci_close_dev(dd); + + return retval; +} + +static void adapter_set_discov_timeout(struct btd_adapter *adapter, + guint interval) +{ + if (adapter->discov_timeout_id) { + g_source_remove(adapter->discov_timeout_id); + adapter->discov_timeout_id = 0; + } + + if (interval == 0) + return; + + adapter->discov_timeout_id = g_timeout_add_seconds(interval, + discov_timeout_handler, + adapter); +} + static DBusMessage *set_mode(DBusConnection *conn, DBusMessage *msg, uint8_t new_mode, void *data) { @@ -630,7 +700,7 @@ static DBusMessage *set_mode(DBusConnection *conn, DBusMessage *msg, if (!adapter->mode_sessions && adapter->discov_timeout) adapter_set_discov_timeout(adapter, - adapter->discov_timeout * 1000); + adapter->discov_timeout); } } done: @@ -692,13 +762,40 @@ static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg, ADAPTER_INTERFACE, "Pairable", DBUS_TYPE_BOOLEAN, &pairable); + if (pairable && adapter->pairable_timeout) + adapter_set_pairable_timeout(adapter, + adapter->pairable_timeout); + 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); + return msg ? dbus_message_new_method_return(msg) : NULL; +} + +static gboolean pairable_timeout_handler(void *data) +{ + set_pairable(NULL, NULL, FALSE, data); + + return FALSE; +} + +static void adapter_set_pairable_timeout(struct btd_adapter *adapter, + guint interval) +{ + if (adapter->pairable_timeout_id) { + g_source_remove(adapter->pairable_timeout_id); + adapter->pairable_timeout_id = 0; + } + + if (interval == 0) + return; + + adapter->pairable_timeout_id = g_timeout_add_seconds(interval, + pairable_timeout_handler, + adapter); } static struct session_req *find_session(GSList *list, DBusMessage *msg) @@ -887,13 +984,8 @@ static DBusMessage *set_discoverable_timeout(DBusConnection *conn, if (adapter->discov_timeout == timeout && timeout == 0) return dbus_message_new_method_return(msg); - if (adapter->discov_timeout_id) { - g_source_remove(adapter->discov_timeout_id); - adapter->discov_timeout_id = 0; - } - - if ((timeout != 0) && (adapter->scan_mode & SCAN_INQUIRY)) - adapter_set_discov_timeout(adapter, timeout * 1000); + if (adapter->scan_mode & SCAN_INQUIRY) + adapter_set_discov_timeout(adapter, timeout); adapter->discov_timeout = timeout; @@ -908,6 +1000,33 @@ static DBusMessage *set_discoverable_timeout(DBusConnection *conn, return dbus_message_new_method_return(msg); } +static DBusMessage *set_pairable_timeout(DBusConnection *conn, + DBusMessage *msg, + uint32_t timeout, + void *data) +{ + struct btd_adapter *adapter = data; + const char *path; + + if (adapter->pairable_timeout == timeout && timeout == 0) + return dbus_message_new_method_return(msg); + + if (adapter->pairable) + adapter_set_pairable_timeout(adapter, timeout); + + adapter->pairable_timeout = timeout; + + write_pairable_timeout(&adapter->bdaddr, timeout); + + path = dbus_message_get_path(msg); + + emit_property_changed(conn, path, + ADAPTER_INTERFACE, "PairableTimeout", + DBUS_TYPE_UINT32, &timeout); + + return dbus_message_new_method_return(msg); +} + static void update_ext_inquiry_response(int dd, struct hci_dev *dev) { uint8_t fec = 0, data[240]; @@ -1694,6 +1813,11 @@ static DBusMessage *get_properties(DBusConnection *conn, dict_append_entry(&dict, "DiscoverableTimeout", DBUS_TYPE_UINT32, &adapter->discov_timeout); + /* PairableTimeout */ + dict_append_entry(&dict, "PairableTimeout", + DBUS_TYPE_UINT32, &adapter->pairable_timeout); + + if (adapter->state & PERIODIC_INQUIRY || adapter->state & STD_INQUIRY) value = TRUE; else @@ -1802,6 +1926,15 @@ static DBusMessage *set_property(DBusConnection *conn, dbus_message_iter_get_basic(&sub, &pairable); return set_pairable(conn, msg, pairable, data); + } else if (g_str_equal("PairableTimeout", property)) { + uint32_t timeout; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) + return invalid_args(msg); + + dbus_message_iter_get_basic(&sub, &timeout); + + return set_pairable_timeout(conn, msg, timeout, data); } return invalid_args(msg); @@ -2435,6 +2568,16 @@ static int get_discoverable_timeout(const char *src) return main_opts.discovto; } +static int get_pairable_timeout(const char *src) +{ + int timeout; + + if (read_pairable_timeout(src, &timeout) == 0) + return timeout; + + return main_opts.pairto; +} + static void adapter_up(struct btd_adapter *adapter, int dd) { struct hci_conn_list_req *cl = NULL; @@ -2449,6 +2592,7 @@ static void adapter_up(struct btd_adapter *adapter, int dd) adapter->up = 1; adapter->discov_timeout = get_discoverable_timeout(srcaddr); + adapter->pairable_timeout = get_pairable_timeout(srcaddr); adapter->state = DISCOVER_TYPE_NONE; /* Set pairable mode */ @@ -2923,67 +3067,6 @@ void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr) bacpy(bdaddr, &adapter->bdaddr); } -static gboolean discov_timeout_handler(void *data) -{ - struct btd_adapter *adapter = data; - struct hci_request rq; - int dd; - uint8_t scan_enable = adapter->scan_mode; - uint8_t status = 0; - gboolean retval = TRUE; - uint16_t dev_id = adapter->dev_id; - - scan_enable &= ~SCAN_INQUIRY; - - dd = hci_open_dev(dev_id); - if (dd < 0) { - error("HCI device open failed: hci%d", dev_id); - return TRUE; - } - - memset(&rq, 0, sizeof(rq)); - rq.ogf = OGF_HOST_CTL; - rq.ocf = OCF_WRITE_SCAN_ENABLE; - rq.cparam = &scan_enable; - rq.clen = sizeof(scan_enable); - rq.rparam = &status; - rq.rlen = sizeof(status); - rq.event = EVT_CMD_COMPLETE; - - if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) { - error("Sending write scan enable command to hci%d failed: %s (%d)", - dev_id, strerror(errno), errno); - goto failed; - } - if (status) { - error("Setting scan enable failed with status 0x%02x", status); - goto failed; - } - - set_limited_discoverable(dd, adapter->dev.class, FALSE); - - adapter_remove_discov_timeout(adapter); - retval = FALSE; - -failed: - if (dd >= 0) - hci_close_dev(dd); - - return retval; -} - -void adapter_set_discov_timeout(struct btd_adapter *adapter, guint interval) -{ - if (!adapter) - return; - - if (adapter->discov_timeout_id) { - error("Timeout already added for adapter %s", adapter->path); - return; - } - - adapter->discov_timeout_id = g_timeout_add(interval, discov_timeout_handler, adapter); -} void adapter_remove_discov_timeout(struct btd_adapter *adapter) { @@ -3219,14 +3302,14 @@ void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode) } if (adapter->discov_timeout != 0) adapter_set_discov_timeout(adapter, - adapter->discov_timeout * 1000); + adapter->discov_timeout); break; case SCAN_INQUIRY: /* Address the scenario where a low-level application like * hciconfig changed the scan mode */ if (adapter->discov_timeout != 0) adapter_set_discov_timeout(adapter, - adapter->discov_timeout * 1000); + adapter->discov_timeout); /* ignore, this event should not be sent */ default: diff --git a/src/adapter.h b/src/adapter.h index eb206ac6..b6a974f3 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -135,7 +135,6 @@ uint16_t adapter_get_dev_id(struct btd_adapter *adapter); const gchar *adapter_get_path(struct btd_adapter *adapter); void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr); void adapter_remove(struct btd_adapter *adapter); -void adapter_set_discov_timeout(struct btd_adapter *adapter, guint interval); void adapter_remove_discov_timeout(struct btd_adapter *adapter); void adapter_set_scan_mode(struct btd_adapter *adapter, uint8_t scan_mode); uint8_t adapter_get_scan_mode(struct btd_adapter *adapter); @@ -55,6 +55,7 @@ struct main_opts { uint32_t class; uint16_t pageto; uint32_t discovto; + uint32_t pairto; uint16_t link_mode; uint16_t link_policy; @@ -127,6 +127,17 @@ static void parse_config(GKeyFile *config) } val = g_key_file_get_integer(config, "General", + "PairableTimeout", + &err); + if (err) { + debug("%s", err->message); + g_clear_error(&err); + } else { + debug("pairto=%d", val); + main_opts.pairto = val; + } + + val = g_key_file_get_integer(config, "General", "PageTimeout", &err); if (err) { diff --git a/src/main.conf b/src/main.conf index 16d04579..20bac707 100644 --- a/src/main.conf +++ b/src/main.conf @@ -17,6 +17,11 @@ Class = 0x000100 # 0 = disable timer, i.e. stay discoverable forever DiscoverableTimeout = 0 +# How long to stay in pairable mode before going back to non-discoverable +# The value is in seconds. Default is 0. +# 0 = disable timer, i.e. stay pairable forever +PairableTimeout = 0 + # Use some other page timeout than the controller default one # (16384 = 10 seconds) PageTimeout = 8192 diff --git a/src/storage.c b/src/storage.c index 212f7ce2..a97a9992 100644 --- a/src/storage.c +++ b/src/storage.c @@ -120,6 +120,39 @@ int read_discoverable_timeout(const char *src, int *timeout) return 0; } +int write_pairable_timeout(bdaddr_t *bdaddr, int timeout) +{ + char filename[PATH_MAX + 1], str[32]; + + snprintf(str, sizeof(str), "%d", timeout); + + create_filename(filename, PATH_MAX, bdaddr, "config"); + + create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + return textfile_put(filename, "pairto", str); +} + +int read_pairable_timeout(const char *src, int *timeout) +{ + char filename[PATH_MAX + 1], *str; + + create_name(filename, PATH_MAX, STORAGEDIR, src, "config"); + + str = textfile_get(filename, "pairto"); + if (!str) + return -ENOENT; + + if (sscanf(str, "%d", timeout) != 1) { + free(str); + return -ENOENT; + } + + free(str); + + return 0; +} + int write_device_mode(bdaddr_t *bdaddr, const char *mode) { char filename[PATH_MAX + 1]; diff --git a/src/storage.h b/src/storage.h index b6bedbed..ce3a22e5 100644 --- a/src/storage.h +++ b/src/storage.h @@ -25,6 +25,8 @@ int read_device_alias(const char *src, const char *dst, char *alias, size_t size int write_device_alias(const char *src, const char *dst, const char *alias); int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout); int read_discoverable_timeout(const char *src, int *timeout); +int write_pairable_timeout(bdaddr_t *bdaddr, int timeout); +int read_pairable_timeout(const char *src, int *timeout); int write_device_mode(bdaddr_t *bdaddr, const char *mode); int read_device_mode(const char *src, char *mode, int length); int read_on_mode(const char *src, char *mode, int length); |