mirror of
https://github.com/torvalds/linux
synced 2024-10-08 04:12:40 +00:00
Bluetooth: Add support for adv instance timeout
This patch implements support for the timeout parameter of the Add Advertising command. Signed-off-by: Arman Uguray <armansito@chromium.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
4117ed70a5
commit
912098a630
|
@ -156,8 +156,10 @@ struct oob_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct adv_info {
|
struct adv_info {
|
||||||
|
struct delayed_work timeout_exp;
|
||||||
__u8 instance;
|
__u8 instance;
|
||||||
__u32 flags;
|
__u32 flags;
|
||||||
|
__u16 timeout;
|
||||||
__u16 adv_data_len;
|
__u16 adv_data_len;
|
||||||
__u8 adv_data[HCI_MAX_AD_LENGTH];
|
__u8 adv_data[HCI_MAX_AD_LENGTH];
|
||||||
__u16 scan_rsp_len;
|
__u16 scan_rsp_len;
|
||||||
|
|
|
@ -1336,6 +1336,49 @@ static bool hci_stop_discovery(struct hci_request *req)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void advertising_added(struct sock *sk, struct hci_dev *hdev,
|
||||||
|
u8 instance)
|
||||||
|
{
|
||||||
|
struct mgmt_ev_advertising_added ev;
|
||||||
|
|
||||||
|
ev.instance = instance;
|
||||||
|
|
||||||
|
mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
|
||||||
|
u8 instance)
|
||||||
|
{
|
||||||
|
struct mgmt_ev_advertising_removed ev;
|
||||||
|
|
||||||
|
ev.instance = instance;
|
||||||
|
|
||||||
|
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_adv_instance(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
struct hci_request req;
|
||||||
|
|
||||||
|
if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (hdev->adv_instance.timeout)
|
||||||
|
cancel_delayed_work(&hdev->adv_instance.timeout_exp);
|
||||||
|
|
||||||
|
memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
|
||||||
|
advertising_removed(NULL, hdev, 1);
|
||||||
|
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
|
||||||
|
|
||||||
|
if (!hdev_is_powered(hdev) ||
|
||||||
|
hci_dev_test_flag(hdev, HCI_ADVERTISING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
hci_req_init(&req, hdev);
|
||||||
|
disable_advertising(&req);
|
||||||
|
hci_req_run(&req, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int clean_up_hci_state(struct hci_dev *hdev)
|
static int clean_up_hci_state(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct hci_request req;
|
struct hci_request req;
|
||||||
|
@ -1351,6 +1394,9 @@ static int clean_up_hci_state(struct hci_dev *hdev)
|
||||||
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdev->adv_instance.timeout)
|
||||||
|
clear_adv_instance(hdev);
|
||||||
|
|
||||||
if (hci_dev_test_flag(hdev, HCI_LE_ADV))
|
if (hci_dev_test_flag(hdev, HCI_LE_ADV))
|
||||||
disable_advertising(&req);
|
disable_advertising(&req);
|
||||||
|
|
||||||
|
@ -6468,26 +6514,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void advertising_added(struct sock *sk, struct hci_dev *hdev,
|
|
||||||
u8 instance)
|
|
||||||
{
|
|
||||||
struct mgmt_ev_advertising_added ev;
|
|
||||||
|
|
||||||
ev.instance = instance;
|
|
||||||
|
|
||||||
mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
|
|
||||||
u8 instance)
|
|
||||||
{
|
|
||||||
struct mgmt_ev_advertising_removed ev;
|
|
||||||
|
|
||||||
ev.instance = instance;
|
|
||||||
|
|
||||||
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_advertising_complete(struct hci_dev *hdev, u8 status,
|
static void add_advertising_complete(struct hci_dev *hdev, u8 status,
|
||||||
u16 opcode)
|
u16 opcode)
|
||||||
{
|
{
|
||||||
|
@ -6524,6 +6550,18 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void adv_timeout_expired(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct hci_dev *hdev = container_of(work, struct hci_dev,
|
||||||
|
adv_instance.timeout_exp.work);
|
||||||
|
|
||||||
|
hdev->adv_instance.timeout = 0;
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
clear_adv_instance(hdev);
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
|
}
|
||||||
|
|
||||||
static int add_advertising(struct sock *sk, struct hci_dev *hdev,
|
static int add_advertising(struct sock *sk, struct hci_dev *hdev,
|
||||||
void *data, u16 data_len)
|
void *data, u16 data_len)
|
||||||
{
|
{
|
||||||
|
@ -6531,6 +6569,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
|
||||||
struct mgmt_rp_add_advertising rp;
|
struct mgmt_rp_add_advertising rp;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
u8 status;
|
u8 status;
|
||||||
|
u16 timeout;
|
||||||
int err;
|
int err;
|
||||||
struct mgmt_pending_cmd *cmd;
|
struct mgmt_pending_cmd *cmd;
|
||||||
struct hci_request req;
|
struct hci_request req;
|
||||||
|
@ -6543,6 +6582,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
|
||||||
status);
|
status);
|
||||||
|
|
||||||
flags = __le32_to_cpu(cp->flags);
|
flags = __le32_to_cpu(cp->flags);
|
||||||
|
timeout = __le16_to_cpu(cp->timeout);
|
||||||
|
|
||||||
/* The current implementation only supports adding one instance and
|
/* The current implementation only supports adding one instance and
|
||||||
* doesn't support flags.
|
* doesn't support flags.
|
||||||
|
@ -6553,6 +6593,12 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
|
||||||
|
|
||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
if (timeout && !hdev_is_powered(hdev)) {
|
||||||
|
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
|
||||||
|
MGMT_STATUS_REJECTED);
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
|
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
|
||||||
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
|
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
|
||||||
pending_find(MGMT_OP_SET_LE, hdev)) {
|
pending_find(MGMT_OP_SET_LE, hdev)) {
|
||||||
|
@ -6569,6 +6615,8 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
|
||||||
|
|
||||||
hdev->adv_instance.flags = flags;
|
hdev->adv_instance.flags = flags;
|
||||||
hdev->adv_instance.adv_data_len = cp->adv_data_len;
|
hdev->adv_instance.adv_data_len = cp->adv_data_len;
|
||||||
hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
|
hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
|
||||||
|
@ -6580,6 +6628,16 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
|
||||||
memcpy(hdev->adv_instance.scan_rsp_data,
|
memcpy(hdev->adv_instance.scan_rsp_data,
|
||||||
cp->data + cp->adv_data_len, cp->scan_rsp_len);
|
cp->data + cp->adv_data_len, cp->scan_rsp_len);
|
||||||
|
|
||||||
|
if (hdev->adv_instance.timeout)
|
||||||
|
cancel_delayed_work(&hdev->adv_instance.timeout_exp);
|
||||||
|
|
||||||
|
hdev->adv_instance.timeout = timeout;
|
||||||
|
|
||||||
|
if (timeout)
|
||||||
|
queue_delayed_work(hdev->workqueue,
|
||||||
|
&hdev->adv_instance.timeout_exp,
|
||||||
|
msecs_to_jiffies(timeout * 1000));
|
||||||
|
|
||||||
if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
|
if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
|
||||||
advertising_added(sk, hdev, 1);
|
advertising_added(sk, hdev, 1);
|
||||||
|
|
||||||
|
@ -6682,6 +6740,9 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdev->adv_instance.timeout)
|
||||||
|
cancel_delayed_work(&hdev->adv_instance.timeout_exp);
|
||||||
|
|
||||||
memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
|
memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
|
||||||
|
|
||||||
advertising_removed(sk, hdev, 1);
|
advertising_removed(sk, hdev, 1);
|
||||||
|
|
Loading…
Reference in a new issue