Skip to content

Commit

Permalink
[Bluetooth] Add automatic sniff mode support
Browse files Browse the repository at this point in the history
This patch introduces the automatic sniff mode feature. This allows
the host to switch idle connections into sniff mode to safe power.

Signed-off-by: Ulisses Furquim <ulissesf@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
  • Loading branch information
holtmann authored and David S. Miller committed Jul 4, 2006
1 parent da1f519 commit 04837f6
Show file tree
Hide file tree
Showing 7 changed files with 454 additions and 86 deletions.
70 changes: 56 additions & 14 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,10 @@ enum {
#define HCIINQUIRY _IOR('H', 240, int)

/* HCI timeouts */
#define HCI_CONN_TIMEOUT (HZ * 40)
#define HCI_DISCONN_TIMEOUT (HZ * 2)
#define HCI_CONN_IDLE_TIMEOUT (HZ * 60)
#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */
#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */

/* HCI Packet types */
#define HCI_COMMAND_PKT 0x01
Expand Down Expand Up @@ -145,7 +146,7 @@ enum {
#define LMP_TACCURACY 0x10
#define LMP_RSWITCH 0x20
#define LMP_HOLD 0x40
#define LMP_SNIF 0x80
#define LMP_SNIFF 0x80

#define LMP_PARK 0x01
#define LMP_RSSI 0x02
Expand All @@ -160,13 +161,21 @@ enum {
#define LMP_PSCHEME 0x02
#define LMP_PCONTROL 0x04

#define LMP_SNIFF_SUBR 0x02

/* Connection modes */
#define HCI_CM_ACTIVE 0x0000
#define HCI_CM_HOLD 0x0001
#define HCI_CM_SNIFF 0x0002
#define HCI_CM_PARK 0x0003

/* Link policies */
#define HCI_LP_RSWITCH 0x0001
#define HCI_LP_HOLD 0x0002
#define HCI_LP_SNIFF 0x0004
#define HCI_LP_PARK 0x0008

/* Link mode */
/* Link modes */
#define HCI_LM_ACCEPT 0x8000
#define HCI_LM_MASTER 0x0001
#define HCI_LM_AUTH 0x0002
Expand All @@ -192,7 +201,7 @@ struct hci_rp_read_loc_version {
} __attribute__ ((packed));

#define OCF_READ_LOCAL_FEATURES 0x0003
struct hci_rp_read_loc_features {
struct hci_rp_read_local_features {
__u8 status;
__u8 features[8];
} __attribute__ ((packed));
Expand Down Expand Up @@ -376,17 +385,32 @@ struct hci_cp_change_conn_link_key {
} __attribute__ ((packed));

#define OCF_READ_REMOTE_FEATURES 0x001B
struct hci_cp_read_rmt_features {
struct hci_cp_read_remote_features {
__le16 handle;
} __attribute__ ((packed));

#define OCF_READ_REMOTE_VERSION 0x001D
struct hci_cp_read_rmt_version {
struct hci_cp_read_remote_version {
__le16 handle;
} __attribute__ ((packed));

/* Link Policy */
#define OGF_LINK_POLICY 0x02
#define OGF_LINK_POLICY 0x02

#define OCF_SNIFF_MODE 0x0003
struct hci_cp_sniff_mode {
__le16 handle;
__le16 max_interval;
__le16 min_interval;
__le16 attempt;
__le16 timeout;
} __attribute__ ((packed));

#define OCF_EXIT_SNIFF_MODE 0x0004
struct hci_cp_exit_sniff_mode {
__le16 handle;
} __attribute__ ((packed));

#define OCF_ROLE_DISCOVERY 0x0009
struct hci_cp_role_discovery {
__le16 handle;
Expand All @@ -407,7 +431,7 @@ struct hci_rp_read_link_policy {
__le16 policy;
} __attribute__ ((packed));

#define OCF_SWITCH_ROLE 0x000B
#define OCF_SWITCH_ROLE 0x000B
struct hci_cp_switch_role {
bdaddr_t bdaddr;
__u8 role;
Expand All @@ -423,6 +447,14 @@ struct hci_rp_write_link_policy {
__le16 handle;
} __attribute__ ((packed));

#define OCF_SNIFF_SUBRATE 0x0011
struct hci_cp_sniff_subrate {
__le16 handle;
__le16 max_latency;
__le16 min_remote_timeout;
__le16 min_local_timeout;
} __attribute__ ((packed));

/* Status params */
#define OGF_STATUS_PARAM 0x05

Expand Down Expand Up @@ -582,15 +614,15 @@ struct hci_ev_link_key_notify {
__u8 key_type;
} __attribute__ ((packed));

#define HCI_EV_RMT_FEATURES 0x0B
struct hci_ev_rmt_features {
#define HCI_EV_REMOTE_FEATURES 0x0B
struct hci_ev_remote_features {
__u8 status;
__le16 handle;
__u8 features[8];
} __attribute__ ((packed));

#define HCI_EV_RMT_VERSION 0x0C
struct hci_ev_rmt_version {
#define HCI_EV_REMOTE_VERSION 0x0C
struct hci_ev_remote_version {
__u8 status;
__le16 handle;
__u8 lmp_ver;
Expand All @@ -611,6 +643,16 @@ struct hci_ev_pscan_rep_mode {
__u8 pscan_rep_mode;
} __attribute__ ((packed));

#define HCI_EV_SNIFF_SUBRATE 0x2E
struct hci_ev_sniff_subrate {
__u8 status;
__le16 handle;
__le16 max_tx_latency;
__le16 max_rx_latency;
__le16 max_remote_timeout;
__le16 max_local_timeout;
} __attribute__ ((packed));

/* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xFD
struct hci_ev_stack_internal {
Expand Down
54 changes: 30 additions & 24 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1

#define HCI_INIT_TIMEOUT (HZ * 10)

/* HCI Core structures */

struct inquiry_data {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
Expand Down Expand Up @@ -81,6 +78,10 @@ struct hci_dev {
__u16 link_policy;
__u16 link_mode;

__u32 idle_timeout;
__u16 sniff_min_interval;
__u16 sniff_max_interval;

unsigned long quirks;

atomic_t cmd_cnt;
Expand Down Expand Up @@ -145,18 +146,24 @@ struct hci_conn {
bdaddr_t dst;
__u16 handle;
__u16 state;
__u8 mode;
__u8 type;
__u8 out;
__u8 dev_class[3];
__u8 features[8];
__u16 interval;
__u16 link_policy;
__u32 link_mode;
__u8 power_save;
unsigned long pend;

unsigned int sent;

struct sk_buff_head data_q;

struct timer_list timer;

struct timer_list disc_timer;
struct timer_list idle_timer;

struct hci_dev *hdev;
void *l2cap_data;
void *sco_data;
Expand Down Expand Up @@ -211,7 +218,8 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data);
enum {
HCI_CONN_AUTH_PEND,
HCI_CONN_ENCRYPT_PEND,
HCI_CONN_RSWITCH_PEND
HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND,
};

static inline void hci_conn_hash_init(struct hci_dev *hdev)
Expand Down Expand Up @@ -286,31 +294,27 @@ int hci_conn_encrypt(struct hci_conn *conn);
int hci_conn_change_link_key(struct hci_conn *conn);
int hci_conn_switch_role(struct hci_conn *conn, uint8_t role);

static inline void hci_conn_set_timer(struct hci_conn *conn, unsigned long timeout)
{
mod_timer(&conn->timer, jiffies + timeout);
}

static inline void hci_conn_del_timer(struct hci_conn *conn)
{
del_timer(&conn->timer);
}
void hci_conn_enter_active_mode(struct hci_conn *conn);
void hci_conn_enter_sniff_mode(struct hci_conn *conn);

static inline void hci_conn_hold(struct hci_conn *conn)
{
atomic_inc(&conn->refcnt);
hci_conn_del_timer(conn);
del_timer(&conn->disc_timer);
}

static inline void hci_conn_put(struct hci_conn *conn)
{
if (atomic_dec_and_test(&conn->refcnt)) {
unsigned long timeo;
if (conn->type == ACL_LINK) {
unsigned long timeo = (conn->out) ?
HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2;
hci_conn_set_timer(conn, timeo);
timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
if (!conn->out)
timeo *= 2;
del_timer(&conn->idle_timer);
} else
hci_conn_set_timer(conn, HZ / 100);
timeo = msecs_to_jiffies(10);
mod_timer(&conn->disc_timer, jiffies + timeo);
}
}

Expand Down Expand Up @@ -411,8 +415,10 @@ void hci_unregister_sysfs(struct hci_dev *hdev);
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->class_dev.dev = (pdev))

/* ----- LMP capabilities ----- */
#define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT)
#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)

/* ----- HCI protocols ----- */
struct hci_proto {
Expand Down
2 changes: 1 addition & 1 deletion net/bluetooth/af_bluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#define BT_DBG(D...)
#endif

#define VERSION "2.8"
#define VERSION "2.9"

/* Bluetooth sockets */
#define BT_MAX_PROTO 8
Expand Down
Loading

0 comments on commit 04837f6

Please sign in to comment.