[Bluetooth] Add automatic sniff mode support

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>
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 99c53f6..b2bdb1a 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -101,9 +101,10 @@
 #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
@@ -145,7 +146,7 @@
 #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
@@ -160,13 +161,21 @@
 #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
@@ -192,7 +201,7 @@
 } __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));
@@ -376,17 +385,32 @@
 } __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;
@@ -407,7 +431,7 @@
 	__le16   policy;
 } __attribute__ ((packed));
 
-#define OCF_SWITCH_ROLE	0x000B
+#define OCF_SWITCH_ROLE		0x000B
 struct hci_cp_switch_role {
 	bdaddr_t bdaddr;
 	__u8     role;
@@ -423,6 +447,14 @@
 	__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
 
@@ -582,15 +614,15 @@
 	__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;
@@ -611,6 +643,16 @@
 	__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 {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index bb9f81d..f685270 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -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;
@@ -81,6 +78,10 @@
 	__u16		link_policy;
 	__u16		link_mode;
 
+	__u32		idle_timeout;
+	__u16		sniff_min_interval;
+	__u16		sniff_max_interval;
+
 	unsigned long	quirks;
 
 	atomic_t	cmd_cnt;
@@ -145,18 +146,24 @@
 	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;
@@ -211,7 +218,8 @@
 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)
@@ -286,31 +294,27 @@
 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);
 	}
 }
 
@@ -411,8 +415,10 @@
 #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 {