Bluetooth: BR: Support limited discoverable mode
Add a Kconfig BT_LIMITED_DISCOVERABLE_DURATION to set the timeout for limited discoverable mode. Add a argument `limited` to function `bt_br_set_discoverable()` to support the limited discoverable mode. When enabling discoverable mode with `limited` is true, both write LIAC and GIAC to controller and set the bit 13 of COD in function `bt_br_set_discoverable()`. And start a delay worker with the timeout CONFIG_BT_LIMITED_DISCOVERABLE_DURATION to disable the discoverable mode. When disabling discoverable mode, only set GIAC to controller and clear bit 13 of COD. Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
This commit is contained in:
parent
51bfb50b66
commit
c0f7aefe55
@ -175,12 +175,17 @@ int bt_br_oob_get_local(struct bt_br_oob *oob);
|
||||
* to devices making general inquiry. To enable this state it's mandatory
|
||||
* to first be in connectable state.
|
||||
*
|
||||
* If the device enters limited discoverable mode, the controller will leave from discoverable
|
||||
* mode after the duration of @kconfig{BT_LIMITED_DISCOVERABLE_DURATION} seconds in the limited
|
||||
* discoverable mode.
|
||||
*
|
||||
* @param enable Value allowing/disallowing controller to become discoverable.
|
||||
* @param limited Value allowing/disallowing controller to enter limited discoverable mode.
|
||||
*
|
||||
* @return Negative if fail set to requested state or requested state has been
|
||||
* already set. Zero if done successfully.
|
||||
*/
|
||||
int bt_br_set_discoverable(bool enable);
|
||||
int bt_br_set_discoverable(bool enable, bool limited);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable set controller in connectable state.
|
||||
|
||||
@ -100,7 +100,7 @@ static void bt_ready(int err)
|
||||
printk("BR/EDR set/rest connectable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
err = bt_br_set_discoverable(true);
|
||||
err = bt_br_set_discoverable(true, false);
|
||||
if (err) {
|
||||
printk("BR/EDR set discoverable failed (err %d)\n", err);
|
||||
return;
|
||||
|
||||
@ -18,6 +18,14 @@ config BT_CLASSIC
|
||||
This option enables Bluetooth BR/EDR support
|
||||
|
||||
if BT_CLASSIC
|
||||
config BT_LIMITED_DISCOVERABLE_DURATION
|
||||
int "Maximum duration that a device is in limited discoverable mode in seconds"
|
||||
default 60
|
||||
range 31 60
|
||||
help
|
||||
This option sets the maximum duration that a device is in limited discoverable mode in
|
||||
seconds.
|
||||
|
||||
config BT_BR_MIN_ENC_KEY_SIZE
|
||||
int
|
||||
prompt "Minimum encryption key size accepted in octets" if !BT_SMP_SC_ONLY
|
||||
|
||||
@ -1057,8 +1057,128 @@ int bt_br_set_connectable(bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
int bt_br_set_discoverable(bool enable)
|
||||
#define BT_LIAC 0x9e8b00
|
||||
#define BT_GIAC 0x9e8b33
|
||||
|
||||
static int bt_br_write_current_iac_lap(bool limited)
|
||||
{
|
||||
struct bt_hci_cp_write_current_iac_lap *iac_lap;
|
||||
struct net_buf *buf;
|
||||
uint8_t param_len;
|
||||
uint8_t num_current_iac = limited ? 2 : 1;
|
||||
|
||||
LOG_DBG("limited discoverable mode? %s", limited ? "Yes" : "No");
|
||||
|
||||
param_len = sizeof(*iac_lap) + (num_current_iac * sizeof(struct bt_hci_iac_lap));
|
||||
|
||||
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_CURRENT_IAC_LAP, param_len);
|
||||
if (!buf) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
iac_lap = net_buf_add(buf, param_len);
|
||||
iac_lap->num_current_iac = num_current_iac;
|
||||
sys_put_le24(BT_GIAC, iac_lap->lap[0].iac);
|
||||
if (num_current_iac > 1) {
|
||||
sys_put_le24(BT_LIAC, iac_lap->lap[1].iac);
|
||||
}
|
||||
|
||||
return bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_CURRENT_IAC_LAP, buf, NULL);
|
||||
}
|
||||
|
||||
#define BT_COD_MAJOR_SVC_CLASS_LIMITED_DISCOVER BIT(13)
|
||||
|
||||
static int bt_br_read_cod(uint32_t *cod)
|
||||
{
|
||||
struct net_buf *rsp;
|
||||
struct bt_hci_rp_read_class_of_device *rp;
|
||||
int err;
|
||||
|
||||
LOG_DBG("Read COD");
|
||||
|
||||
/* Read Class of device */
|
||||
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_CLASS_OF_DEVICE, NULL, &rsp);
|
||||
if (err) {
|
||||
LOG_WRN("Fail to read COD");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!rsp || (rsp->len < sizeof(*rp))) {
|
||||
LOG_WRN("Invalid response");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rp = (void *)rsp->data;
|
||||
*cod = sys_get_le24(rp->class_of_device);
|
||||
|
||||
LOG_DBG("Current COD %06x", *cod);
|
||||
|
||||
net_buf_unref(rsp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt_br_write_cod(uint32_t cod)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
||||
/* Set Class of device */
|
||||
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_CLASS_OF_DEVICE,
|
||||
sizeof(struct bt_hci_cp_write_class_of_device));
|
||||
if (!buf) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
net_buf_add_le24(buf, cod);
|
||||
|
||||
return bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_CLASS_OF_DEVICE, buf, NULL);
|
||||
}
|
||||
|
||||
static int bt_br_update_cod(bool limited)
|
||||
{
|
||||
int err;
|
||||
uint32_t cod;
|
||||
|
||||
LOG_DBG("Update COD");
|
||||
|
||||
err = bt_br_read_cod(&cod);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (limited) {
|
||||
cod |= BT_COD_MAJOR_SVC_CLASS_LIMITED_DISCOVER;
|
||||
} else {
|
||||
cod &= ~BT_COD_MAJOR_SVC_CLASS_LIMITED_DISCOVER;
|
||||
}
|
||||
|
||||
err = bt_br_write_cod(cod);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bt_br_limited_discoverable_timeout_handler(struct k_work *work)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!atomic_test_bit(bt_dev.flags, BT_DEV_LIMITED_DISCOVERABLE_MODE)) {
|
||||
LOG_INF("Limited discoverable mode has been disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_br_set_discoverable(false, false);
|
||||
if (err) {
|
||||
LOG_WRN("Disable discoverable failure (err %d)", err);
|
||||
}
|
||||
}
|
||||
|
||||
/* Work used for limited discoverable mode time span */
|
||||
static K_WORK_DELAYABLE_DEFINE(bt_br_limited_discoverable_timeout,
|
||||
bt_br_limited_discoverable_timeout_handler);
|
||||
|
||||
int bt_br_set_discoverable(bool enable, bool limited)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (enable) {
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) {
|
||||
return -EALREADY;
|
||||
@ -1068,12 +1188,48 @@ int bt_br_set_discoverable(bool enable)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return write_scan_enable(BT_BREDR_SCAN_INQUIRY | BT_BREDR_SCAN_PAGE);
|
||||
} else {
|
||||
if (!atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) {
|
||||
return -EALREADY;
|
||||
err = bt_br_write_current_iac_lap(limited);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return write_scan_enable(BT_BREDR_SCAN_PAGE);
|
||||
err = bt_br_update_cod(limited);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = write_scan_enable(BT_BREDR_SCAN_INQUIRY | BT_BREDR_SCAN_PAGE);
|
||||
if (!err && (limited == true)) {
|
||||
atomic_set_bit(bt_dev.flags, BT_DEV_LIMITED_DISCOVERABLE_MODE);
|
||||
k_work_reschedule(&bt_br_limited_discoverable_timeout,
|
||||
K_SECONDS(CONFIG_BT_LIMITED_DISCOVERABLE_DURATION));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
err = write_scan_enable(BT_BREDR_SCAN_PAGE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_LIMITED_DISCOVERABLE_MODE)) {
|
||||
err = bt_br_write_current_iac_lap(false);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_br_update_cod(false);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_LIMITED_DISCOVERABLE_MODE);
|
||||
k_work_cancel_delayable(&bt_br_limited_discoverable_timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -297,20 +297,21 @@ static int cmd_l2cap_register(const struct shell *sh,
|
||||
static int cmd_discoverable(const struct shell *sh,
|
||||
size_t argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
const char *action;
|
||||
int err = 0;
|
||||
bool enable;
|
||||
bool limited = false;
|
||||
|
||||
action = argv[1];
|
||||
|
||||
if (!strcmp(action, "on")) {
|
||||
err = bt_br_set_discoverable(true);
|
||||
} else if (!strcmp(action, "off")) {
|
||||
err = bt_br_set_discoverable(false);
|
||||
} else {
|
||||
enable = shell_strtobool(argv[1], 10, &err);
|
||||
if (err) {
|
||||
shell_help(sh);
|
||||
return SHELL_CMD_HELP_PRINTED;
|
||||
}
|
||||
|
||||
if (argc > 2 && !strcmp(argv[2], "limited")) {
|
||||
limited = true;
|
||||
}
|
||||
|
||||
err = bt_br_set_discoverable(enable, limited);
|
||||
if (err) {
|
||||
shell_print(sh, "BR/EDR set/reset discoverable failed "
|
||||
"(err %d)", err);
|
||||
@ -544,7 +545,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(br_cmds,
|
||||
SHELL_CMD_ARG(discovery, NULL,
|
||||
"<value: on, off> [length: 1-48] [mode: limited]",
|
||||
cmd_discovery, 2, 2),
|
||||
SHELL_CMD_ARG(iscan, NULL, "<value: on, off>", cmd_discoverable, 2, 0),
|
||||
SHELL_CMD_ARG(iscan, NULL, "<value: on, off> [mode: limited]",
|
||||
cmd_discoverable, 2, 1),
|
||||
SHELL_CMD_ARG(l2cap-register, NULL, "<psm>", cmd_l2cap_register, 2, 0),
|
||||
SHELL_CMD_ARG(oob, NULL, NULL, cmd_oob, 1, 0),
|
||||
SHELL_CMD_ARG(pscan, NULL, "<value: on, off>", cmd_connectable, 2, 0),
|
||||
|
||||
@ -74,6 +74,7 @@ enum {
|
||||
BT_DEV_ISCAN,
|
||||
BT_DEV_PSCAN,
|
||||
BT_DEV_INQUIRY,
|
||||
BT_DEV_LIMITED_DISCOVERABLE_MODE,
|
||||
#endif /* CONFIG_BT_CLASSIC */
|
||||
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user