Skip to content

Commit

Permalink
Bluetooth: BR: Support limited discoverable mode
Browse files Browse the repository at this point in the history
Add a Kconfig BT_LIMITED_DISCOVERABLE_TIME_SPAN 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_TIME_SPAN 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 <[email protected]>
  • Loading branch information
lylezhu2012 committed Jan 23, 2025
1 parent 838c011 commit 1738e46
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 18 deletions.
7 changes: 6 additions & 1 deletion include/zephyr/bluetooth/classic/classic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_TIME_SPAN} 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.
Expand Down
2 changes: 1 addition & 1 deletion samples/bluetooth/handsfree/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions subsys/bluetooth/host/classic/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ config BT_CLASSIC
This option enables Bluetooth BR/EDR support

if BT_CLASSIC
config BT_LIMITED_DISCOVERABLE_TIME_SPAN
int "Maximum time span that a device is in limited discoverable mode in seconds"
default 60
range 31 60
help
This option sets the maximum time span 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
Expand Down
177 changes: 171 additions & 6 deletions subsys/bluetooth/host/classic/br.c
Original file line number Diff line number Diff line change
Expand Up @@ -1055,8 +1055,137 @@ 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 = 1;

LOG_DBG("limited discoverable mode? %s", limited ? "Yes" : "No");

param_len = sizeof(*iac_lap) + sizeof(struct bt_hci_iac_lap);
if (limited) {
param_len += sizeof(struct bt_hci_iac_lap);
num_current_iac += 1;
}

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 *buf;
struct net_buf *rsp;
struct bt_hci_rp_read_class_of_device *rp;
int err;

LOG_DBG("Read COD");
/* Set Class of device */
buf = bt_hci_cmd_create(BT_HCI_OP_READ_CLASS_OF_DEVICE, 0);
if (!buf) {
return -ENOBUFS;
}

err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_CLASS_OF_DEVICE, buf, &rsp);
if (err) {
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;
struct bt_hci_cp_write_class_of_device *cp;

/* Set Class of device */
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_CLASS_OF_DEVICE, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}

cp = net_buf_add(buf, sizeof(*cp));
sys_put_le24(cod, cp->class_of_device);

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(limited_discoverable_time_span,
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;
Expand All @@ -1066,12 +1195,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;
}

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(&limited_discoverable_time_span,
K_SECONDS(CONFIG_BT_LIMITED_DISCOVERABLE_TIME_SPAN));
}
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;
}

return write_scan_enable(BT_BREDR_SCAN_PAGE);
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(&limited_discoverable_time_span);
}

return 0;
}
22 changes: 12 additions & 10 deletions subsys/bluetooth/host/classic/shell/bredr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions subsys/bluetooth/host/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,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 */
Expand Down

0 comments on commit 1738e46

Please sign in to comment.