Bluetooth: Add timeout field to mgmt_set_discoverable
authorJohan Hedberg <johan.hedberg@intel.com>
Mon, 7 Nov 2011 20:16:02 +0000 (22:16 +0200)
committerGustavo F. Padovan <padovan@profusion.mobi>
Tue, 8 Nov 2011 14:54:09 +0000 (12:54 -0200)
Based on the revised mgmt API set_discoverable has a timeout parameter
to specify how long the adapter will remain discoverable. A value of 0
means "indefinitively".

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>

include/net/bluetooth/hci_core.h
include/net/bluetooth/mgmt.h
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/mgmt.c

index 20db034..5803c1e 100644 (file)
@@ -196,6 +196,9 @@ struct hci_dev {
        struct work_struct      power_off;
        struct timer_list       off_timer;
 
+       __u16                   discov_timeout;
+       struct delayed_work     discov_off;
+
        struct timer_list       cmd_timer;
        struct tasklet_struct   cmd_task;
        struct tasklet_struct   rx_task;
index 3062fd3..b5320aa 100644 (file)
@@ -69,6 +69,10 @@ struct mgmt_mode {
 #define MGMT_OP_SET_POWERED            0x0005
 
 #define MGMT_OP_SET_DISCOVERABLE       0x0006
+struct mgmt_cp_set_discoverable {
+       __u8 val;
+       __u16 timeout;
+} __packed;
 
 #define MGMT_OP_SET_CONNECTABLE                0x0007
 
index 6a4bd2d..2da3f90 100644 (file)
@@ -595,6 +595,11 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        tasklet_kill(&hdev->rx_task);
        tasklet_kill(&hdev->tx_task);
 
+       if (hdev->discov_timeout > 0) {
+               cancel_delayed_work_sync(&hdev->discov_off);
+               hdev->discov_timeout = 0;
+       }
+
        hci_dev_lock_bh(hdev);
        inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
@@ -968,6 +973,24 @@ void hci_del_off_timer(struct hci_dev *hdev)
        del_timer(&hdev->off_timer);
 }
 
+static void hci_discov_off(struct work_struct *work)
+{
+       struct hci_dev *hdev;
+       u8 scan = SCAN_PAGE;
+
+       hdev = container_of(work, struct hci_dev, discov_off.work);
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock_bh(hdev);
+
+       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
+
+       hdev->discov_timeout = 0;
+
+       hci_dev_unlock_bh(hdev);
+}
+
 int hci_uuids_clear(struct hci_dev *hdev)
 {
        struct list_head *p, *n;
@@ -1485,6 +1508,8 @@ int hci_register_dev(struct hci_dev *hdev)
        INIT_WORK(&hdev->power_off, hci_power_off);
        setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
 
+       INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
+
        memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
        atomic_set(&hdev->promisc, 0);
index 0c11203..cf99265 100644 (file)
@@ -292,6 +292,11 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
                set_bit(HCI_ISCAN, &hdev->flags);
                if (!old_iscan)
                        mgmt_discoverable(hdev->id, 1);
+               if (hdev->discov_timeout > 0) {
+                       int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
+                       queue_delayed_work(hdev->workqueue, &hdev->discov_off,
+                                                                       to);
+               }
        } else if (old_iscan)
                mgmt_discoverable(hdev->id, 0);
 
index 0f9ef94..724d4fe 100644 (file)
@@ -350,7 +350,7 @@ failed:
 static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                                                                        u16 len)
 {
-       struct mgmt_mode *cp;
+       struct mgmt_cp_set_discoverable *cp;
        struct hci_dev *hdev;
        struct pending_cmd *cmd;
        u8 scan;
@@ -396,11 +396,16 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
 
        if (cp->val)
                scan |= SCAN_INQUIRY;
+       else
+               cancel_delayed_work_sync(&hdev->discov_off);
 
        err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
+       if (cp->val)
+               hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
+
 failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);