diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2011-12-14 23:47:39 +0100 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-12-18 20:41:04 +0100 |
commit | 7d78525dcf5c6fe5e6e73d22776ed5f960e3153e (patch) | |
tree | be4ab2f2c9b140733a685e6ac6da2c7e409b3618 /net | |
parent | Bluetooth: Move EIR and CoD update functions to a better position (diff) | |
download | linux-7d78525dcf5c6fe5e6e73d22776ed5f960e3153e.tar.xz linux-7d78525dcf5c6fe5e6e73d22776ed5f960e3153e.zip |
Bluetooth: Add timer for automatically disabling the service cache
We do not want the service cache to be enabled indefinitely after
mgmt_read_info is called. To solve this a timer is added which will
automatically disable the cache if mgmt_set_dev_class isn't called
within 5 seconds of calling mgmt_read_info.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/hci_core.c | 3 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 40 |
2 files changed, 38 insertions, 5 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 82d1d9e6b7c6..b5ba42db0561 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -598,6 +598,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) cancel_delayed_work(&hdev->power_off); + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + cancel_delayed_work(&hdev->service_cache); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cc4ea392ac6a..6cb8c7f708b5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,6 +35,8 @@ #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ +#define SERVICE_CACHE_TIMEOUT (5 * 1000) + struct pending_cmd { struct list_head list; u16 opcode; @@ -472,6 +474,32 @@ static int update_class(struct hci_dev *hdev) return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); } +static void service_cache_off(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, + service_cache.work); + + if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + return; + + hci_dev_lock(hdev); + + update_eir(hdev); + update_class(hdev); + + hci_dev_unlock(hdev); +} + +static void mgmt_init_hdev(struct hci_dev *hdev) +{ + if (!test_and_set_bit(HCI_MGMT, &hdev->flags)) + INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); + + if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags)) + schedule_delayed_work(&hdev->service_cache, + msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); +} + static int read_controller_info(struct sock *sk, u16 index) { struct mgmt_rp_read_info rp; @@ -489,10 +517,8 @@ static int read_controller_info(struct sock *sk, u16 index) hci_dev_lock(hdev); - if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) { - set_bit(HCI_MGMT, &hdev->flags); - set_bit(HCI_SERVICE_CACHE, &hdev->flags); - } + if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) + mgmt_init_hdev(hdev); memset(&rp, 0, sizeof(rp)); @@ -992,8 +1018,12 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, hdev->major_class = cp->major; hdev->minor_class = cp->minor; - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) { + hci_dev_unlock(hdev); + cancel_delayed_work_sync(&hdev->service_cache); + hci_dev_lock(hdev); update_eir(hdev); + } err = update_class(hdev); |