linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv2 0/5] EWS: extended window size and extended control field support
@ 2011-09-16 13:39 Emeltchenko Andrei
  2011-09-16 13:39 ` [PATCHv2 1/5] Bluetooth: EWS: extended window size option support Emeltchenko Andrei
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Emeltchenko Andrei @ 2011-09-16 13:39 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Adds support for extended window size option (EWS) and extended control
field. Code partly based on Atheros patches sent a year ago by Haijun Liu
http://marc.info/?a=128277503500005&r=1&w=2
and Qualcomm code git://codeaurora.org/kernel/msm.git.

To decode EWS option and extended control field please apply patch to hcidump
which I sent to linux-bluetooth.

Changes:
	* RFCv1: rebase and using l2cap_chan flag for ext control
	* PATCHv1: small fix for tx_seq u8->u16
	* PATCHv2: use enable_hs instead of disable_extwindow,
		code style fixes, fix pdu calculation and remove magic
		numbers.

Andrei Emeltchenko (5):
  Bluetooth: EWS: extended window size option support
  Bluetooth: EWS: l2cap extended control field support
  Bluetooth: EWS: support extended seq numbers
  Bluetooth: EWS: remove magic numbers in l2cap
  Bluetooth: EWS: fix max_pdu calculation

 include/net/bluetooth/bluetooth.h |    2 +-
 include/net/bluetooth/l2cap.h     |  295 ++++++++++++++++++++----
 net/bluetooth/l2cap_core.c        |  461 ++++++++++++++++++++++---------------
 net/bluetooth/l2cap_sock.c        |   10 +-
 4 files changed, 532 insertions(+), 236 deletions(-)

-- 
1.7.4.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCHv2 1/5] Bluetooth: EWS: extended window size option support
  2011-09-16 13:39 [PATCHv2 0/5] EWS: extended window size and extended control field support Emeltchenko Andrei
@ 2011-09-16 13:39 ` Emeltchenko Andrei
  2011-10-06 18:05   ` Gustavo Padovan
  2011-09-16 13:39 ` [PATCHv2 2/5] Bluetooth: EWS: l2cap extended control field support Emeltchenko Andrei
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Emeltchenko Andrei @ 2011-09-16 13:39 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Adds support for EWS option. Code partly based on Qualcomm and Atheros
patches sent upstream a year ago.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |   11 ++++++--
 net/bluetooth/l2cap_core.c    |   53 +++++++++++++++++++++++++++++++++++++---
 net/bluetooth/l2cap_sock.c    |   10 ++++----
 3 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 1f26a39..92eac16 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -31,7 +31,7 @@
 #define L2CAP_DEFAULT_MTU		672
 #define L2CAP_DEFAULT_MIN_MTU		48
 #define L2CAP_DEFAULT_FLUSH_TO		0xffff
-#define L2CAP_DEFAULT_TX_WINDOW		63
+#define L2CAP_DEFAULT_MAX_TX_WINDOW	63
 #define L2CAP_DEFAULT_MAX_TX		3
 #define L2CAP_DEFAULT_RETRANS_TO	2000    /* 2 seconds */
 #define L2CAP_DEFAULT_MONITOR_TO	12000   /* 12 seconds */
@@ -42,6 +42,8 @@
 #define L2CAP_DEFAULT_SDU_ARRIVAL_TIME	0xFFFFFFFF
 #define L2CAP_DEFAULT_ACCESS_LATENCY	0xFFFFFFFF
 
+#define L2CAP_DEFAULT_MAX_EXT_WINDOW	0x3FFF
+
 #define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
 #define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
 
@@ -240,6 +242,7 @@ struct l2cap_conf_opt {
 #define L2CAP_CONF_RFC		0x04
 #define L2CAP_CONF_FCS		0x05
 #define L2CAP_CONF_EFS		0x06
+#define L2CAP_CONF_EWS		0x07
 
 #define L2CAP_CONF_MAX_SIZE	22
 
@@ -357,7 +360,7 @@ struct l2cap_chan {
 
 	__u8		fcs;
 
-	__u8		tx_win;
+	__u16		tx_win;
 	__u8		max_tx;
 	__u16		retrans_timeout;
 	__u16		monitor_timeout;
@@ -381,7 +384,7 @@ struct l2cap_chan {
 	struct sk_buff	*sdu;
 	struct sk_buff	*sdu_last_frag;
 
-	__u8		remote_tx_win;
+	__u16		remote_tx_win;
 	__u8		remote_max_tx;
 	__u16		remote_mps;
 
@@ -488,6 +491,7 @@ enum {
 	CONF_STATE2_DEVICE,
 	CONF_LOCAL_PEND,
 	CONF_REMOTE_PEND,
+	CONF_EWS_RECV,
 };
 
 #define L2CAP_CONF_MAX_CONF_REQ 2
@@ -508,6 +512,7 @@ enum {
 /* Definitions for flags in l2cap_chan */
 enum {
 	FLAG_EFS_ENABLE,
+	FLAG_EXT_CTRL,
 };
 
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7aad856..69e974a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1906,6 +1906,22 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
 	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
 }
 
+static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
+{
+	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
+}
+
+static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
+{
+	if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW &&
+						__l2cap_ews_supported(chan))
+		/* use extended control field */
+		set_bit(FLAG_EXT_CTRL, &chan->flags);
+	else
+		chan->tx_win = min_t(u16, chan->tx_win,
+						L2CAP_DEFAULT_MAX_TX_WINDOW);
+}
+
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
 {
 	struct l2cap_conf_req *req = data;
@@ -1957,7 +1973,6 @@ done:
 
 	case L2CAP_MODE_ERTM:
 		rfc.mode            = L2CAP_MODE_ERTM;
-		rfc.txwin_size      = chan->tx_win;
 		rfc.max_transmit    = chan->max_tx;
 		rfc.retrans_timeout = 0;
 		rfc.monitor_timeout = 0;
@@ -1965,6 +1980,11 @@ done:
 		if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
 			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
 
+		l2cap_txwin_setup(chan);
+
+		rfc.txwin_size = min_t(u16, chan->tx_win,
+						L2CAP_DEFAULT_MAX_TX_WINDOW);
+
 		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
 							(unsigned long) &rfc);
 
@@ -1996,6 +2016,10 @@ done:
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
 		}
 
+		if (__l2cap_ews_supported(chan) &&
+				test_bit(FLAG_EXT_CTRL, &chan->flags))
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+					chan->tx_win);
 		break;
 
 	case L2CAP_MODE_STREAMING:
@@ -2033,7 +2057,10 @@ done:
 			chan->fcs = L2CAP_FCS_NONE;
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
 		}
-
+		
+		if (__l2cap_ews_supported(chan) &&
+				test_bit(FLAG_EXT_CTRL, &chan->flags))
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, 0);
 		break;
 	}
 
@@ -2093,6 +2120,12 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 				memcpy(&efs, (void *) val, olen);
 			break;
 
+		case L2CAP_CONF_EWS:
+			set_bit(FLAG_EXT_CTRL, &chan->flags);
+			chan->remote_tx_win = val;
+			set_bit(CONF_EWS_RECV, &chan->conf_state);
+			break;
+
 		default:
 			if (hint)
 				break;
@@ -2183,7 +2216,11 @@ done:
 			break;
 
 		case L2CAP_MODE_ERTM:
-			chan->remote_tx_win = rfc.txwin_size;
+			if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
+				chan->remote_tx_win = rfc.txwin_size;
+			else
+				rfc.txwin_size = L2CAP_DEFAULT_MAX_TX_WINDOW;
+
 			chan->remote_max_tx = rfc.max_transmit;
 
 			if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
@@ -2304,6 +2341,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
 					sizeof(efs), (unsigned long) &efs);
 			break;
+
+		case L2CAP_CONF_EWS:
+			chan->tx_win = val < L2CAP_DEFAULT_MAX_EXT_WINDOW ?
+				val : L2CAP_DEFAULT_MAX_EXT_WINDOW;
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS,
+							2, chan->tx_win);
+			break;
 		}
 	}
 
@@ -2943,7 +2987,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
 			feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
 							 | L2CAP_FEAT_FCS;
 		if (enable_hs)
-			feat_mask |= L2CAP_FEAT_EXT_FLOW;
+			feat_mask |= L2CAP_FEAT_EXT_FLOW
+						| L2CAP_FEAT_EXT_WINDOW;
 
 		put_unaligned_le32(feat_mask, rsp->data);
 		l2cap_send_cmd(conn, cmd->ident,
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 61f1f62..d6a4f63 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -331,7 +331,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
 		opts.mode     = chan->mode;
 		opts.fcs      = chan->fcs;
 		opts.max_tx   = chan->max_tx;
-		opts.txwin_size = (__u16)chan->tx_win;
+		opts.txwin_size = chan->tx_win;
 
 		len = min_t(unsigned int, len, sizeof(opts));
 		if (copy_to_user(optval, (char *) &opts, len))
@@ -500,7 +500,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 		opts.mode     = chan->mode;
 		opts.fcs      = chan->fcs;
 		opts.max_tx   = chan->max_tx;
-		opts.txwin_size = (__u16)chan->tx_win;
+		opts.txwin_size = chan->tx_win;
 
 		len = min_t(unsigned int, sizeof(opts), optlen);
 		if (copy_from_user((char *) &opts, optval, len)) {
@@ -508,7 +508,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 			break;
 		}
 
-		if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+		if (opts.txwin_size > L2CAP_DEFAULT_MAX_EXT_WINDOW) {
 			err = -EINVAL;
 			break;
 		}
@@ -532,7 +532,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 		chan->omtu = opts.omtu;
 		chan->fcs  = opts.fcs;
 		chan->max_tx = opts.max_tx;
-		chan->tx_win = (__u8)opts.txwin_size;
+		chan->tx_win = opts.txwin_size;
 		break;
 
 	case L2CAP_LM:
@@ -958,7 +958,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 		}
 		chan->max_tx = L2CAP_DEFAULT_MAX_TX;
 		chan->fcs  = L2CAP_FCS_CRC16;
-		chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+		chan->tx_win = L2CAP_DEFAULT_MAX_TX_WINDOW;
 		chan->sec_level = BT_SECURITY_LOW;
 		chan->role_switch = 0;
 		chan->force_reliable = 0;
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCHv2 2/5] Bluetooth: EWS: l2cap extended control field support
  2011-09-16 13:39 [PATCHv2 0/5] EWS: extended window size and extended control field support Emeltchenko Andrei
  2011-09-16 13:39 ` [PATCHv2 1/5] Bluetooth: EWS: extended window size option support Emeltchenko Andrei
@ 2011-09-16 13:39 ` Emeltchenko Andrei
  2011-10-06 18:19   ` Gustavo Padovan
  2011-09-16 13:39 ` [PATCHv2 3/5] Bluetooth: EWS: support extended seq numbers Emeltchenko Andrei
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Emeltchenko Andrei @ 2011-09-16 13:39 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Adds support for parsing extended control field. Extended control
field may be used for ERTM and streaming mode (if EWS specified).
u32 control is used for standard, enhanced and extended control
fields. Flag in l2cap chan specifies which format is in use.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |  267 +++++++++++++++++++++++++++++++++------
 net/bluetooth/l2cap_core.c    |  282 ++++++++++++++++++++++-------------------
 2 files changed, 381 insertions(+), 168 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 92eac16..ca3e02f 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -27,6 +27,8 @@
 #ifndef __L2CAP_H
 #define __L2CAP_H
 
+#include <asm/unaligned.h>
+
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU		672
 #define L2CAP_DEFAULT_MIN_MTU		48
@@ -113,36 +115,52 @@ struct l2cap_conninfo {
 #define L2CAP_FCS_CRC16		0x01
 
 /* L2CAP Control Field bit masks */
-#define L2CAP_CTRL_SAR               0xC000
-#define L2CAP_CTRL_REQSEQ            0x3F00
-#define L2CAP_CTRL_TXSEQ             0x007E
-#define L2CAP_CTRL_RETRANS           0x0080
-#define L2CAP_CTRL_FINAL             0x0080
-#define L2CAP_CTRL_POLL              0x0010
-#define L2CAP_CTRL_SUPERVISE         0x000C
-#define L2CAP_CTRL_FRAME_TYPE        0x0001 /* I- or S-Frame */
-
-#define L2CAP_CTRL_TXSEQ_SHIFT      1
-#define L2CAP_CTRL_REQSEQ_SHIFT     8
-#define L2CAP_CTRL_SAR_SHIFT       14
+#define L2CAP_CTRL_SAR			0xC000
+#define L2CAP_CTRL_REQSEQ		0x3F00
+#define L2CAP_CTRL_TXSEQ		0x007E
+#define L2CAP_CTRL_SUPERVISE		0x000C
+
+#define L2CAP_CTRL_RETRANS		0x0080
+#define L2CAP_CTRL_FINAL		0x0080
+#define L2CAP_CTRL_POLL			0x0010
+#define L2CAP_CTRL_FRAME_TYPE		0x0001 /* I- or S-Frame */
+
+#define L2CAP_CTRL_TXSEQ_SHIFT		1
+#define L2CAP_CTRL_SUPER_SHIFT		2
+#define L2CAP_CTRL_REQSEQ_SHIFT		8
+#define L2CAP_CTRL_SAR_SHIFT		14
+
+/* L2CAP Extended Control Field bit mask */
+#define L2CAP_EXT_CTRL_TXSEQ		0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR		0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE	0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ		0x0000FFFC
+
+#define L2CAP_EXT_CTRL_POLL		0x00040000
+#define L2CAP_EXT_CTRL_FINAL		0x00000002
+#define L2CAP_EXT_CTRL_FRAME_TYPE	0x00000001 /* I- or S-Frame */
+
+#define L2CAP_EXT_CTRL_REQSEQ_SHIFT	2
+#define L2CAP_EXT_CTRL_SAR_SHIFT	16
+#define L2CAP_EXT_CTRL_SUPER_SHIFT	16
+#define L2CAP_EXT_CTRL_TXSEQ_SHIFT	18
 
 /* L2CAP Supervisory Function */
-#define L2CAP_SUPER_RCV_READY           0x0000
-#define L2CAP_SUPER_REJECT              0x0004
-#define L2CAP_SUPER_RCV_NOT_READY       0x0008
-#define L2CAP_SUPER_SELECT_REJECT       0x000C
+#define L2CAP_SUPER_RR		0x00
+#define L2CAP_SUPER_REJ		0x01
+#define L2CAP_SUPER_RNR		0x02
+#define L2CAP_SUPER_SREJ	0x03
 
 /* L2CAP Segmentation and Reassembly */
-#define L2CAP_SDU_UNSEGMENTED       0x0000
-#define L2CAP_SDU_START             0x4000
-#define L2CAP_SDU_END               0x8000
-#define L2CAP_SDU_CONTINUE          0xC000
+#define L2CAP_SAR_UNSEGMENTED	0x00
+#define L2CAP_SAR_START		0x01
+#define L2CAP_SAR_END		0x02
+#define L2CAP_SAR_CONTINUE	0x03
 
 /* L2CAP Command rej. reasons */
-#define L2CAP_REJ_NOT_UNDERSTOOD      0x0000
-#define L2CAP_REJ_MTU_EXCEEDED        0x0001
-#define L2CAP_REJ_INVALID_CID         0x0002
-
+#define L2CAP_REJ_NOT_UNDERSTOOD	0x0000
+#define L2CAP_REJ_MTU_EXCEEDED		0x0001
+#define L2CAP_REJ_INVALID_CID		0x0002
 
 /* L2CAP structures */
 struct l2cap_hdr {
@@ -150,6 +168,11 @@ struct l2cap_hdr {
 	__le16     cid;
 } __packed;
 #define L2CAP_HDR_SIZE		4
+#define L2CAP_ENHANCED_HDR_SIZE	6
+#define L2CAP_EXTENDED_HDR_SIZE	8
+
+#define L2CAP_FCS_SIZE		2
+#define L2CAP_SDULEN_SIZE	2
 
 struct l2cap_cmd_hdr {
 	__u8       code;
@@ -320,7 +343,7 @@ struct l2cap_conn_param_update_rsp {
 
 /* ----- L2CAP channels and connections ----- */
 struct srej_list {
-	__u8	tx_seq;
+	__u16	tx_seq;
 	struct list_head list;
 };
 
@@ -370,16 +393,16 @@ struct l2cap_chan {
 	unsigned long	conn_state;
 	unsigned long	flags;
 
-	__u8		next_tx_seq;
-	__u8		expected_ack_seq;
-	__u8		expected_tx_seq;
-	__u8		buffer_seq;
-	__u8		buffer_seq_srej;
-	__u8		srej_save_reqseq;
-	__u8		frames_sent;
-	__u8		unacked_frames;
+	__u16		next_tx_seq;
+	__u16		expected_ack_seq;
+	__u16		expected_tx_seq;
+	__u16		buffer_seq;
+	__u16		buffer_seq_srej;
+	__u16		srej_save_reqseq;
+	__u16		frames_sent;
+	__u16		unacked_frames;
 	__u8		retry_count;
-	__u8		num_acked;
+	__u16		num_acked;
 	__u16		sdu_len;
 	struct sk_buff	*sdu;
 	struct sk_buff	*sdu_last_frag;
@@ -539,11 +562,177 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 	return sub == ch->remote_tx_win;
 }
 
-#define __get_txseq(ctrl)	(((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
-#define __get_reqseq(ctrl)	(((ctrl) & L2CAP_CTRL_REQSEQ) >> 8)
-#define __is_iframe(ctrl)	(!((ctrl) & L2CAP_CTRL_FRAME_TYPE))
-#define __is_sframe(ctrl)	((ctrl) & L2CAP_CTRL_FRAME_TYPE)
-#define __is_sar_start(ctrl)	(((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
+static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >>
+						L2CAP_EXT_CTRL_REQSEQ_SHIFT;
+	else
+		return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
+}
+
+static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
+							L2CAP_EXT_CTRL_REQSEQ;
+	else
+		return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
+}
+
+static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
+						L2CAP_EXT_CTRL_TXSEQ_SHIFT;
+	else
+		return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
+}
+
+static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
+							L2CAP_EXT_CTRL_TXSEQ;
+	else
+		return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
+}
+
+static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
+	else
+		return ctrl & L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u32 __set_sframe(struct l2cap_chan *chan)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return L2CAP_EXT_CTRL_FRAME_TYPE;
+	else
+		return L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
+	else
+		return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
+}
+
+static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
+	else
+		return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
+}
+
+static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
+{
+	return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
+}
+
+static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return L2CAP_EXT_CTRL_SAR;
+	else
+		return L2CAP_CTRL_SAR;
+}
+
+static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
+						L2CAP_EXT_CTRL_SUPER_SHIFT;
+	else
+		return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
+}
+
+static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
+						L2CAP_EXT_CTRL_SUPERVISE;
+	else
+		return (super << L2CAP_CTRL_SUPER_SHIFT) &
+							L2CAP_CTRL_SUPERVISE;
+}
+
+static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return L2CAP_EXT_CTRL_FINAL;
+	else
+		return L2CAP_CTRL_FINAL;
+}
+
+static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return ctrl & L2CAP_EXT_CTRL_FINAL;
+	else
+		return ctrl & L2CAP_CTRL_FINAL;
+}
+
+static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return L2CAP_EXT_CTRL_POLL;
+	else
+		return L2CAP_CTRL_POLL;
+}
+
+static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return ctrl & L2CAP_EXT_CTRL_POLL;
+	else
+		return ctrl & L2CAP_CTRL_POLL;
+}
+
+static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return get_unaligned_le32(p);
+	else
+		return get_unaligned_le16(p);
+}
+
+static inline __u32 __get_control_pull(struct l2cap_chan *chan,
+		struct sk_buff *skb, void *p)
+{
+	__u32 ctrl;
+
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
+		ctrl = get_unaligned_le32(p);
+		skb_pull(skb, 4);
+	} else {
+		ctrl = get_unaligned_le16(p);
+		skb_pull(skb, 2);
+	}
+
+	return ctrl;
+}
+
+static inline void __put_control(struct l2cap_chan *chan, __u32 control, void *p)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return put_unaligned_le32(control, p);
+	else
+		return put_unaligned_le16(control, p);
+}
+
+static inline void __put_control_put(struct l2cap_chan *chan, __u32 control, void *p)
+{
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		return put_unaligned_le32(control, skb_put(p, 4));
+	else
+		return put_unaligned_le16(control, skb_put(p, 2));
+}
 
 extern int disable_ertm;
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 69e974a..b387710 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -567,30 +567,36 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
 	hci_send_acl(conn->hcon, skb, flags);
 }
 
-static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
+static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
 {
 	struct sk_buff *skb;
 	struct l2cap_hdr *lh;
 	struct l2cap_conn *conn = chan->conn;
-	int count, hlen = L2CAP_HDR_SIZE + 2;
+	int count, hlen;
 	u8 flags;
 
 	if (chan->state != BT_CONNECTED)
 		return;
 
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		hlen = L2CAP_EXTENDED_HDR_SIZE;
+	else
+		hlen = L2CAP_ENHANCED_HDR_SIZE;
+
 	if (chan->fcs == L2CAP_FCS_CRC16)
 		hlen += 2;
 
-	BT_DBG("chan %p, control 0x%2.2x", chan, control);
+	BT_DBG("chan %p, control 0x%8.8x", chan, control);
 
 	count = min_t(unsigned int, conn->mtu, hlen);
-	control |= L2CAP_CTRL_FRAME_TYPE;
+
+	control |= __set_sframe(chan);
 
 	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-		control |= L2CAP_CTRL_FINAL;
+		control |= __set_ctrl_final(chan);
 
 	if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
-		control |= L2CAP_CTRL_POLL;
+		control |= __set_ctrl_poll(chan);
 
 	skb = bt_skb_alloc(count, GFP_ATOMIC);
 	if (!skb)
@@ -599,7 +605,8 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
 	lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
 	lh->cid = cpu_to_le16(chan->dcid);
-	put_unaligned_le16(control, skb_put(skb, 2));
+
+	__put_control_put(chan, control, skb);
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
 		u16 fcs = crc16(0, (u8 *)lh, count - 2);
@@ -616,15 +623,15 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
 	hci_send_acl(chan->conn->hcon, skb, flags);
 }
 
-static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
+static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
 {
 	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		control |= L2CAP_SUPER_RCV_NOT_READY;
+		control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
 		set_bit(CONN_RNR_SENT, &chan->conn_state);
 	} else
-		control |= L2CAP_SUPER_RCV_READY;
+		control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 
-	control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= __set_reqseq(chan, chan->buffer_seq);
 
 	l2cap_send_sframe(chan, control);
 }
@@ -1271,12 +1278,13 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
 static void l2cap_streaming_send(struct l2cap_chan *chan)
 {
 	struct sk_buff *skb;
-	u16 control, fcs;
+	u32 control;
+	u16 fcs;
 
 	while ((skb = skb_dequeue(&chan->tx_q))) {
-		control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
-		control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
-		put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
+		control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
+		control |= __set_txseq(chan, chan->next_tx_seq);
+		__put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
 
 		if (chan->fcs == L2CAP_FCS_CRC16) {
 			fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
@@ -1289,10 +1297,11 @@ static void l2cap_streaming_send(struct l2cap_chan *chan)
 	}
 }
 
-static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
 {
 	struct sk_buff *skb, *tx_skb;
-	u16 control, fcs;
+	u16 fcs;
+	u32 control;
 
 	skb = skb_peek(&chan->tx_q);
 	if (!skb)
@@ -1315,16 +1324,17 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 
 	tx_skb = skb_clone(skb, GFP_ATOMIC);
 	bt_cb(skb)->retries++;
-	control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-	control &= L2CAP_CTRL_SAR;
+
+	control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
+	control &= __get_sar_mask(chan);
 
 	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-		control |= L2CAP_CTRL_FINAL;
+		control |= __set_ctrl_final(chan);
 
-	control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-			| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+	control |= __set_reqseq(chan, chan->buffer_seq);
+	control |= __set_txseq(chan, tx_seq);
 
-	put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+	__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
 		fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
@@ -1337,7 +1347,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 static int l2cap_ertm_send(struct l2cap_chan *chan)
 {
 	struct sk_buff *skb, *tx_skb;
-	u16 control, fcs;
+	u16 fcs;
+	u32 control;
 	int nsent = 0;
 
 	if (chan->state != BT_CONNECTED)
@@ -1355,16 +1366,16 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 
 		bt_cb(skb)->retries++;
 
-		control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-		control &= L2CAP_CTRL_SAR;
+		control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
+		control &= __get_sar_mask(chan);
 
 		if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-			control |= L2CAP_CTRL_FINAL;
+			control |= __set_ctrl_final(chan);
 
-		control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-				| (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
-		put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+		control |= __set_reqseq(chan, chan->buffer_seq);
+		control |= __set_txseq(chan, chan->next_tx_seq);
 
+		__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
 		if (chan->fcs == L2CAP_FCS_CRC16) {
 			fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
@@ -1408,12 +1419,12 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan)
 
 static void l2cap_send_ack(struct l2cap_chan *chan)
 {
-	u16 control = 0;
+	u32 control = 0;
 
-	control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= __set_reqseq(chan, chan->buffer_seq);
 
 	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		control |= L2CAP_SUPER_RCV_NOT_READY;
+		control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
 		set_bit(CONN_RNR_SENT, &chan->conn_state);
 		l2cap_send_sframe(chan, control);
 		return;
@@ -1422,20 +1433,20 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
 	if (l2cap_ertm_send(chan) > 0)
 		return;
 
-	control |= L2CAP_SUPER_RCV_READY;
+	control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 	l2cap_send_sframe(chan, control);
 }
 
 static void l2cap_send_srejtail(struct l2cap_chan *chan)
 {
 	struct srej_list *tail;
-	u16 control;
+	u32 control;
 
-	control = L2CAP_SUPER_SELECT_REJECT;
-	control |= L2CAP_CTRL_FINAL;
+	control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+	control |= __set_ctrl_final(chan);
 
 	tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
-	control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= __set_reqseq(chan, tail->tx_seq);
 
 	l2cap_send_sframe(chan, control);
 }
@@ -1531,12 +1542,12 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
 	return skb;
 }
 
-static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
+static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 control, u16 sdulen)
 {
 	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = chan->conn;
 	struct sk_buff *skb;
-	int err, count, hlen = L2CAP_HDR_SIZE + 2;
+	int err, count, hlen;
 	struct l2cap_hdr *lh;
 
 	BT_DBG("sk %p len %d", sk, (int)len);
@@ -1544,6 +1555,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 	if (!conn)
 		return ERR_PTR(-ENOTCONN);
 
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		hlen = L2CAP_EXTENDED_HDR_SIZE;
+	else
+		hlen = L2CAP_ENHANCED_HDR_SIZE;
+
 	if (sdulen)
 		hlen += 2;
 
@@ -1560,7 +1576,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
 	lh->cid = cpu_to_le16(chan->dcid);
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-	put_unaligned_le16(control, skb_put(skb, 2));
+
+	__put_control_put(chan, control, skb);
+
 	if (sdulen)
 		put_unaligned_le16(sdulen, skb_put(skb, 2));
 
@@ -1581,11 +1599,11 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
 {
 	struct sk_buff *skb;
 	struct sk_buff_head sar_queue;
-	u16 control;
+	u32 control;
 	size_t size = 0;
 
 	skb_queue_head_init(&sar_queue);
-	control = L2CAP_SDU_START;
+	control = __set_ctrl_sar(chan, L2CAP_SAR_START);
 	skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
@@ -1598,10 +1616,10 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
 		size_t buflen;
 
 		if (len > chan->remote_mps) {
-			control = L2CAP_SDU_CONTINUE;
+			control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
 			buflen = chan->remote_mps;
 		} else {
-			control = L2CAP_SDU_END;
+			control = __set_ctrl_sar(chan, L2CAP_SAR_END);
 			buflen = len;
 		}
 
@@ -1625,7 +1643,7 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
 {
 	struct sk_buff *skb;
-	u16 control;
+	u32 control;
 	int err;
 
 	/* Connectionless channel */
@@ -1657,7 +1675,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
 	case L2CAP_MODE_STREAMING:
 		/* Entire SDU fits into one PDU */
 		if (len <= chan->remote_mps) {
-			control = L2CAP_SDU_UNSEGMENTED;
+			control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
 			skb = l2cap_create_iframe_pdu(chan, msg, len, control,
 									0);
 			if (IS_ERR(skb))
@@ -3255,7 +3273,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 {
 	u16 our_fcs, rcv_fcs;
-	int hdr_size = L2CAP_HDR_SIZE + 2;
+	int hdr_size;
+
+	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+		hdr_size = L2CAP_EXTENDED_HDR_SIZE;
+	else
+		hdr_size = L2CAP_ENHANCED_HDR_SIZE;
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
 		skb_trim(skb, skb->len - 2);
@@ -3270,14 +3293,14 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 
 static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 {
-	u16 control = 0;
+	u32 control = 0;
 
 	chan->frames_sent = 0;
 
-	control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= __set_reqseq(chan, chan->buffer_seq);
 
 	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		control |= L2CAP_SUPER_RCV_NOT_READY;
+		control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
 		l2cap_send_sframe(chan, control);
 		set_bit(CONN_RNR_SENT, &chan->conn_state);
 	}
@@ -3289,12 +3312,12 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 
 	if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
 			chan->frames_sent == 0) {
-		control |= L2CAP_SUPER_RCV_READY;
+		control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 		l2cap_send_sframe(chan, control);
 	}
 }
 
-static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
+static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
 {
 	struct sk_buff *next_skb;
 	int tx_seq_offset, next_tx_seq_offset;
@@ -3355,19 +3378,19 @@ static void append_skb_frag(struct sk_buff *skb,
 	skb->truesize += new_frag->truesize;
 }
 
-static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
+static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
 {
 	int err = -EINVAL;
 
-	switch (control & L2CAP_CTRL_SAR) {
-	case L2CAP_SDU_UNSEGMENTED:
+	switch (__get_ctrl_sar(chan, control)) {
+	case L2CAP_SAR_UNSEGMENTED:
 		if (chan->sdu)
 			break;
 
 		err = chan->ops->recv(chan->data, skb);
 		break;
 
-	case L2CAP_SDU_START:
+	case L2CAP_SAR_START:
 		if (chan->sdu)
 			break;
 
@@ -3389,7 +3412,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
 		err = 0;
 		break;
 
-	case L2CAP_SDU_CONTINUE:
+	case L2CAP_SAR_CONTINUE:
 		if (!chan->sdu)
 			break;
 
@@ -3403,7 +3426,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
 		err = 0;
 		break;
 
-	case L2CAP_SDU_END:
+	case L2CAP_SAR_END:
 		if (!chan->sdu)
 			break;
 
@@ -3438,14 +3461,14 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
 
 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 {
-	u16 control;
+	u32 control;
 
 	BT_DBG("chan %p, Enter local busy", chan);
 
 	set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 
-	control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-	control |= L2CAP_SUPER_RCV_NOT_READY;
+	control = __set_reqseq(chan, chan->buffer_seq);
+	control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
 	l2cap_send_sframe(chan, control);
 
 	set_bit(CONN_RNR_SENT, &chan->conn_state);
@@ -3455,13 +3478,14 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 
 static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
 {
-	u16 control;
+	u32 control;
 
 	if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
 		goto done;
 
-	control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-	control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+	control = __set_reqseq(chan, chan->buffer_seq);
+	control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
+	control |= __set_ctrl_poll(chan);
 	l2cap_send_sframe(chan, control);
 	chan->retry_count = 1;
 
@@ -3487,10 +3511,10 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
 	}
 }
 
-static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
 {
 	struct sk_buff *skb;
-	u16 control;
+	u32 control;
 
 	while ((skb = skb_peek(&chan->srej_q)) &&
 			!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
@@ -3500,7 +3524,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
 			break;
 
 		skb = skb_dequeue(&chan->srej_q);
-		control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+		control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
 		err = l2cap_reassemble_sdu(chan, skb, control);
 
 		if (err < 0) {
@@ -3514,10 +3538,10 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
 	}
 }
 
-static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
 	struct srej_list *l, *tmp;
-	u16 control;
+	u32 control;
 
 	list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
 		if (l->tx_seq == tx_seq) {
@@ -3525,22 +3549,22 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
 			kfree(l);
 			return;
 		}
-		control = L2CAP_SUPER_SELECT_REJECT;
-		control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+		control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+		control |= __set_reqseq(chan, l->tx_seq);
 		l2cap_send_sframe(chan, control);
 		list_del(&l->list);
 		list_add_tail(&l->list, &chan->srej_l);
 	}
 }
 
-static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
 	struct srej_list *new;
-	u16 control;
+	u32 control;
 
 	while (tx_seq != chan->expected_tx_seq) {
-		control = L2CAP_SUPER_SELECT_REJECT;
-		control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+		control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+		control |= __set_reqseq(chan, chan->expected_tx_seq);
 		l2cap_send_sframe(chan, control);
 
 		new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
@@ -3551,19 +3575,19 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
 	chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
 }
 
-static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 {
-	u8 tx_seq = __get_txseq(rx_control);
-	u8 req_seq = __get_reqseq(rx_control);
-	u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
+	u16 tx_seq = __get_txseq(chan, rx_control);
+	u16 req_seq = __get_reqseq(chan, rx_control);
+	u8 sar = __get_ctrl_sar(chan, rx_control);
 	int tx_seq_offset, expected_tx_seq_offset;
 	int num_to_ack = (chan->tx_win/6) + 1;
 	int err = 0;
 
-	BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
+	BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
 							tx_seq, rx_control);
 
-	if (L2CAP_CTRL_FINAL & rx_control &&
+	if (__is_ctrl_final(chan, rx_control) &&
 			test_bit(CONN_WAIT_F, &chan->conn_state)) {
 		__clear_monitor_timer(chan);
 		if (chan->unacked_frames > 0)
@@ -3668,7 +3692,7 @@ expected:
 		return err;
 	}
 
-	if (rx_control & L2CAP_CTRL_FINAL) {
+	if (__is_ctrl_final(chan, rx_control)) {
 		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
 			l2cap_retransmit_frames(chan);
 	}
@@ -3686,15 +3710,15 @@ drop:
 	return 0;
 }
 
-static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
 {
-	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
-						rx_control);
+	BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
+				__get_reqseq(chan, rx_control), rx_control);
 
-	chan->expected_ack_seq = __get_reqseq(rx_control);
+	chan->expected_ack_seq = __get_reqseq(chan, rx_control);
 	l2cap_drop_acked_frames(chan);
 
-	if (rx_control & L2CAP_CTRL_POLL) {
+	if (__is_ctrl_poll(chan, rx_control)) {
 		set_bit(CONN_SEND_FBIT, &chan->conn_state);
 		if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
 			if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
@@ -3707,7 +3731,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
 			l2cap_send_i_or_rr_or_rnr(chan);
 		}
 
-	} else if (rx_control & L2CAP_CTRL_FINAL) {
+	} else if (__is_ctrl_final(chan, rx_control)) {
 		clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
 		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
@@ -3726,9 +3750,9 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
 	}
 }
 
-static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
 {
-	u8 tx_seq = __get_reqseq(rx_control);
+	u16 tx_seq = __get_reqseq(chan, rx_control);
 
 	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
 
@@ -3737,7 +3761,7 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c
 	chan->expected_ack_seq = tx_seq;
 	l2cap_drop_acked_frames(chan);
 
-	if (rx_control & L2CAP_CTRL_FINAL) {
+	if (__is_ctrl_final(chan, rx_control)) {
 		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
 			l2cap_retransmit_frames(chan);
 	} else {
@@ -3747,15 +3771,15 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c
 			set_bit(CONN_REJ_ACT, &chan->conn_state);
 	}
 }
-static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
 {
-	u8 tx_seq = __get_reqseq(rx_control);
+	u16 tx_seq = __get_reqseq(chan, rx_control);
 
-	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+	BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
 	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-	if (rx_control & L2CAP_CTRL_POLL) {
+	if (__is_ctrl_poll(chan, rx_control)) {
 		chan->expected_ack_seq = tx_seq;
 		l2cap_drop_acked_frames(chan);
 
@@ -3768,7 +3792,7 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
 			chan->srej_save_reqseq = tx_seq;
 			set_bit(CONN_SREJ_ACT, &chan->conn_state);
 		}
-	} else if (rx_control & L2CAP_CTRL_FINAL) {
+	} else if (__is_ctrl_final(chan, rx_control)) {
 		if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
 				chan->srej_save_reqseq == tx_seq)
 			clear_bit(CONN_SREJ_ACT, &chan->conn_state);
@@ -3783,37 +3807,39 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
 	}
 }
 
-static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
 {
-	u8 tx_seq = __get_reqseq(rx_control);
+	u16 tx_seq = __get_reqseq(chan, rx_control);
 
-	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+	BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
 	set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 	chan->expected_ack_seq = tx_seq;
 	l2cap_drop_acked_frames(chan);
 
-	if (rx_control & L2CAP_CTRL_POLL)
+	if (__is_ctrl_poll(chan, rx_control))
 		set_bit(CONN_SEND_FBIT, &chan->conn_state);
 
 	if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
 		__clear_retrans_timer(chan);
-		if (rx_control & L2CAP_CTRL_POLL)
+		if (__is_ctrl_poll(chan, rx_control))
 			l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
 		return;
 	}
 
-	if (rx_control & L2CAP_CTRL_POLL)
+	if (__is_ctrl_poll(chan, rx_control)) {
 		l2cap_send_srejtail(chan);
-	else
-		l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
+	} else {
+		rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
+		l2cap_send_sframe(chan, rx_control);
+	}
 }
 
-static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 {
-	BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
+	BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
 
-	if (L2CAP_CTRL_FINAL & rx_control &&
+	if (__is_ctrl_final(chan, rx_control) &&
 			test_bit(CONN_WAIT_F, &chan->conn_state)) {
 		__clear_monitor_timer(chan);
 		if (chan->unacked_frames > 0)
@@ -3821,20 +3847,20 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
 		clear_bit(CONN_WAIT_F, &chan->conn_state);
 	}
 
-	switch (rx_control & L2CAP_CTRL_SUPERVISE) {
-	case L2CAP_SUPER_RCV_READY:
+	switch (__get_ctrl_super(chan, rx_control)) {
+	case L2CAP_SUPER_RR:
 		l2cap_data_channel_rrframe(chan, rx_control);
 		break;
 
-	case L2CAP_SUPER_REJECT:
+	case L2CAP_SUPER_REJ:
 		l2cap_data_channel_rejframe(chan, rx_control);
 		break;
 
-	case L2CAP_SUPER_SELECT_REJECT:
+	case L2CAP_SUPER_SREJ:
 		l2cap_data_channel_srejframe(chan, rx_control);
 		break;
 
-	case L2CAP_SUPER_RCV_NOT_READY:
+	case L2CAP_SUPER_RNR:
 		l2cap_data_channel_rnrframe(chan, rx_control);
 		break;
 	}
@@ -3846,12 +3872,11 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 {
 	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-	u16 control;
-	u8 req_seq;
+	u32 control;
+	u16 req_seq;
 	int len, next_tx_seq_offset, req_seq_offset;
 
-	control = get_unaligned_le16(skb->data);
-	skb_pull(skb, 2);
+	control = __get_control_pull(chan, skb, skb->data);
 	len = skb->len;
 
 	/*
@@ -3862,8 +3887,8 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 	if (l2cap_check_fcs(chan, skb))
 		goto drop;
 
-	if (__is_sar_start(control) && __is_iframe(control))
-		len -= 2;
+	if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
+		len -= L2CAP_SDULEN_SIZE;
 
 	if (chan->fcs == L2CAP_FCS_CRC16)
 		len -= 2;
@@ -3873,7 +3898,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 		goto drop;
 	}
 
-	req_seq = __get_reqseq(control);
+	req_seq = __get_reqseq(chan, control);
 	req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
 	if (req_seq_offset < 0)
 		req_seq_offset += 64;
@@ -3889,7 +3914,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 		goto drop;
 	}
 
-	if (__is_iframe(control)) {
+	if (!__is_sframe(chan, control)) {
 		if (len < 0) {
 			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 			goto drop;
@@ -3917,8 +3942,8 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 {
 	struct l2cap_chan *chan;
 	struct sock *sk = NULL;
-	u16 control;
-	u8 tx_seq;
+	u32 control;
+	u16 tx_seq;
 	int len;
 
 	chan = l2cap_get_chan_by_scid(conn, cid);
@@ -3959,23 +3984,22 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 		goto done;
 
 	case L2CAP_MODE_STREAMING:
-		control = get_unaligned_le16(skb->data);
-		skb_pull(skb, 2);
+		control = __get_control_pull(chan, skb, skb->data);
 		len = skb->len;
 
 		if (l2cap_check_fcs(chan, skb))
 			goto drop;
 
-		if (__is_sar_start(control))
-			len -= 2;
+		if (__is_sar_start(chan, control))
+			len -= L2CAP_SDULEN_SIZE;
 
 		if (chan->fcs == L2CAP_FCS_CRC16)
 			len -= 2;
 
-		if (len > chan->mps || len < 0 || __is_sframe(control))
+		if (len > chan->mps || len < 0 || __is_sframe(chan, control))
 			goto drop;
 
-		tx_seq = __get_txseq(control);
+		tx_seq = __get_txseq(chan, control);
 
 		if (chan->expected_tx_seq != tx_seq) {
 			/* Frame(s) missing - must discard partial SDU */
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCHv2 3/5] Bluetooth: EWS: support extended seq numbers
  2011-09-16 13:39 [PATCHv2 0/5] EWS: extended window size and extended control field support Emeltchenko Andrei
  2011-09-16 13:39 ` [PATCHv2 1/5] Bluetooth: EWS: extended window size option support Emeltchenko Andrei
  2011-09-16 13:39 ` [PATCHv2 2/5] Bluetooth: EWS: l2cap extended control field support Emeltchenko Andrei
@ 2011-09-16 13:39 ` Emeltchenko Andrei
  2011-09-16 13:39 ` [PATCHv2 4/5] Bluetooth: EWS: remove magic numbers in l2cap Emeltchenko Andrei
  2011-09-16 13:39 ` [PATCHv2 5/5] Bluetooth: EWS: fix max_pdu calculation Emeltchenko Andrei
  4 siblings, 0 replies; 11+ messages in thread
From: Emeltchenko Andrei @ 2011-09-16 13:39 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Adds support for extended sequence numbers found in
extended control fields.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/bluetooth.h |    2 +-
 include/net/bluetooth/l2cap.h     |   17 ++++++++++
 net/bluetooth/l2cap_core.c        |   63 +++++++++++++++++-------------------
 3 files changed, 48 insertions(+), 34 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index e727555..fb1acb3 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -158,7 +158,7 @@ struct bt_skb_cb {
 	__u8 pkt_type;
 	__u8 incoming;
 	__u16 expect;
-	__u8 tx_seq;
+	__u16 tx_seq;
 	__u8 retries;
 	__u8 sar;
 	unsigned short channel;
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index ca3e02f..772877f 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -384,6 +384,7 @@ struct l2cap_chan {
 	__u8		fcs;
 
 	__u16		tx_win;
+	__u16		tx_win_max;
 	__u8		max_tx;
 	__u16		retrans_timeout;
 	__u16		monitor_timeout;
@@ -550,6 +551,22 @@ enum {
 		L2CAP_DEFAULT_ACK_TO);
 #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
 
+static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
+{
+	int offset;
+
+	offset = (seq1 - seq2) % (chan->tx_win_max + 1);
+	if (offset < 0)
+		offset += (chan->tx_win_max + 1);
+
+	return offset;
+}
+
+static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
+{
+	return (seq + 1) % (chan->tx_win_max + 1);
+}
+
 static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 {
 	int sub;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b387710..091c188 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1293,7 +1293,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan)
 
 		l2cap_do_send(chan, skb);
 
-		chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
+		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 	}
 }
 
@@ -1387,7 +1387,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 		__set_retrans_timer(chan);
 
 		bt_cb(skb)->tx_seq = chan->next_tx_seq;
-		chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
+
+		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 
 		if (bt_cb(skb)->retries == 1)
 			chan->unacked_frames++;
@@ -1932,12 +1933,15 @@ static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
 static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
 {
 	if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW &&
-						__l2cap_ews_supported(chan))
+						__l2cap_ews_supported(chan)) {
 		/* use extended control field */
 		set_bit(FLAG_EXT_CTRL, &chan->flags);
-	else
+		chan->tx_win_max = L2CAP_DEFAULT_MAX_EXT_WINDOW;
+	} else {
 		chan->tx_win = min_t(u16, chan->tx_win,
 						L2CAP_DEFAULT_MAX_TX_WINDOW);
+		chan->tx_win_max = L2CAP_DEFAULT_MAX_TX_WINDOW;
+	}
 }
 
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
@@ -2141,6 +2145,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 		case L2CAP_CONF_EWS:
 			set_bit(FLAG_EXT_CTRL, &chan->flags);
 			chan->remote_tx_win = val;
+			chan->tx_win_max = L2CAP_DEFAULT_MAX_EXT_WINDOW;
 			set_bit(CONF_EWS_RECV, &chan->conf_state);
 			break;
 
@@ -3331,18 +3336,14 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
 		return 0;
 	}
 
-	tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
-	if (tx_seq_offset < 0)
-		tx_seq_offset += 64;
+	tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
 	do {
 		if (bt_cb(next_skb)->tx_seq == tx_seq)
 			return -EINVAL;
 
-		next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
-						chan->buffer_seq) % 64;
-		if (next_tx_seq_offset < 0)
-			next_tx_seq_offset += 64;
+		next_tx_seq_offset = __seq_offset(chan,
+				bt_cb(next_skb)->tx_seq, chan->buffer_seq);
 
 		if (next_tx_seq_offset > tx_seq_offset) {
 			__skb_queue_before(&chan->srej_q, next_skb, skb);
@@ -3532,9 +3533,8 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
 			break;
 		}
 
-		chan->buffer_seq_srej =
-			(chan->buffer_seq_srej + 1) % 64;
-		tx_seq = (tx_seq + 1) % 64;
+		chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
+		tx_seq = __next_seq(chan, tx_seq);
 	}
 }
 
@@ -3569,10 +3569,13 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 
 		new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
 		new->tx_seq = chan->expected_tx_seq;
-		chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+
+		chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+
 		list_add_tail(&new->list, &chan->srej_l);
 	}
-	chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+
+	chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 }
 
 static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
@@ -3598,9 +3601,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
 	chan->expected_ack_seq = req_seq;
 	l2cap_drop_acked_frames(chan);
 
-	tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
-	if (tx_seq_offset < 0)
-		tx_seq_offset += 64;
+	tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
 	/* invalid tx_seq */
 	if (tx_seq_offset >= chan->tx_win) {
@@ -3648,10 +3649,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
 			l2cap_send_srejframe(chan, tx_seq);
 		}
 	} else {
-		expected_tx_seq_offset =
-			(chan->expected_tx_seq - chan->buffer_seq) % 64;
-		if (expected_tx_seq_offset < 0)
-			expected_tx_seq_offset += 64;
+		expected_tx_seq_offset = __seq_offset(chan,
+				chan->expected_tx_seq, chan->buffer_seq);
 
 		/* duplicated tx_seq */
 		if (tx_seq_offset < expected_tx_seq_offset)
@@ -3676,7 +3675,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
 	return 0;
 
 expected:
-	chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+	chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 
 	if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
 		bt_cb(skb)->tx_seq = tx_seq;
@@ -3686,7 +3685,8 @@ expected:
 	}
 
 	err = l2cap_reassemble_sdu(chan, skb, rx_control);
-	chan->buffer_seq = (chan->buffer_seq + 1) % 64;
+	chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
+
 	if (err < 0) {
 		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 		return err;
@@ -3899,14 +3899,11 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 	}
 
 	req_seq = __get_reqseq(chan, control);
-	req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
-	if (req_seq_offset < 0)
-		req_seq_offset += 64;
 
-	next_tx_seq_offset =
-		(chan->next_tx_seq - chan->expected_ack_seq) % 64;
-	if (next_tx_seq_offset < 0)
-		next_tx_seq_offset += 64;
+	req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
+
+	next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
+						chan->expected_ack_seq);
 
 	/* check for invalid req-seq */
 	if (req_seq_offset > next_tx_seq_offset) {
@@ -4011,7 +4008,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 			/* TODO: Notify userland of missing data */
 		}
 
-		chan->expected_tx_seq = (tx_seq + 1) % 64;
+		chan->expected_tx_seq = __next_seq(chan, tx_seq);
 
 		if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
 			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCHv2 4/5] Bluetooth: EWS: remove magic numbers in l2cap
  2011-09-16 13:39 [PATCHv2 0/5] EWS: extended window size and extended control field support Emeltchenko Andrei
                   ` (2 preceding siblings ...)
  2011-09-16 13:39 ` [PATCHv2 3/5] Bluetooth: EWS: support extended seq numbers Emeltchenko Andrei
@ 2011-09-16 13:39 ` Emeltchenko Andrei
  2011-09-16 13:39 ` [PATCHv2 5/5] Bluetooth: EWS: fix max_pdu calculation Emeltchenko Andrei
  4 siblings, 0 replies; 11+ messages in thread
From: Emeltchenko Andrei @ 2011-09-16 13:39 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Remove magic numbers for FCS and SDU LEN

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/l2cap_core.c |   40 +++++++++++++++++++++++-----------------
 1 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 091c188..195af69 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -584,7 +584,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
 		hlen = L2CAP_ENHANCED_HDR_SIZE;
 
 	if (chan->fcs == L2CAP_FCS_CRC16)
-		hlen += 2;
+		hlen += L2CAP_FCS_SIZE;
 
 	BT_DBG("chan %p, control 0x%8.8x", chan, control);
 
@@ -609,8 +609,8 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
 	__put_control_put(chan, control, skb);
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
-		u16 fcs = crc16(0, (u8 *)lh, count - 2);
-		put_unaligned_le16(fcs, skb_put(skb, 2));
+		u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
+		put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
 	}
 
 	if (lmp_no_flush_capable(conn->hcon->hdev))
@@ -1287,8 +1287,10 @@ static void l2cap_streaming_send(struct l2cap_chan *chan)
 		__put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
 
 		if (chan->fcs == L2CAP_FCS_CRC16) {
-			fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
-			put_unaligned_le16(fcs, skb->data + skb->len - 2);
+			fcs = crc16(0, (u8 *)skb->data,
+						skb->len - L2CAP_FCS_SIZE);
+			put_unaligned_le16(fcs,
+					skb->data + skb->len - L2CAP_FCS_SIZE);
 		}
 
 		l2cap_do_send(chan, skb);
@@ -1337,8 +1339,10 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
 	__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
-		fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
-		put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
+		fcs = crc16(0, (u8 *)tx_skb->data,
+						tx_skb->len - L2CAP_FCS_SIZE);
+		put_unaligned_le16(fcs,
+				tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
 	}
 
 	l2cap_do_send(chan, tx_skb);
@@ -1378,8 +1382,10 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 		__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
 		if (chan->fcs == L2CAP_FCS_CRC16) {
-			fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
-			put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
+			fcs = crc16(0, (u8 *)skb->data,
+						tx_skb->len - L2CAP_FCS_SIZE);
+			put_unaligned_le16(fcs, skb->data +
+						tx_skb->len - L2CAP_FCS_SIZE);
 		}
 
 		l2cap_do_send(chan, tx_skb);
@@ -1562,10 +1568,10 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 		hlen = L2CAP_ENHANCED_HDR_SIZE;
 
 	if (sdulen)
-		hlen += 2;
+		hlen += L2CAP_SDULEN_SIZE;
 
 	if (chan->fcs == L2CAP_FCS_CRC16)
-		hlen += 2;
+		hlen += L2CAP_FCS_SIZE;
 
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
 	skb = bt_skb_send_alloc(sk, count + hlen,
@@ -1581,7 +1587,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 	__put_control_put(chan, control, skb);
 
 	if (sdulen)
-		put_unaligned_le16(sdulen, skb_put(skb, 2));
+		put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
 
 	err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
 	if (unlikely(err < 0)) {
@@ -1590,7 +1596,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 	}
 
 	if (chan->fcs == L2CAP_FCS_CRC16)
-		put_unaligned_le16(0, skb_put(skb, 2));
+		put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
 
 	bt_cb(skb)->retries = 0;
 	return skb;
@@ -3286,7 +3292,7 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 		hdr_size = L2CAP_ENHANCED_HDR_SIZE;
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
-		skb_trim(skb, skb->len - 2);
+		skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
 		rcv_fcs = get_unaligned_le16(skb->data + skb->len);
 		our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
 
@@ -3396,7 +3402,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
 			break;
 
 		chan->sdu_len = get_unaligned_le16(skb->data);
-		skb_pull(skb, 2);
+		skb_pull(skb, L2CAP_SDULEN_SIZE);
 
 		if (chan->sdu_len > chan->imtu) {
 			err = -EMSGSIZE;
@@ -3891,7 +3897,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 		len -= L2CAP_SDULEN_SIZE;
 
 	if (chan->fcs == L2CAP_FCS_CRC16)
-		len -= 2;
+		len -= L2CAP_FCS_SIZE;
 
 	if (len > chan->mps) {
 		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@@ -3991,7 +3997,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 			len -= L2CAP_SDULEN_SIZE;
 
 		if (chan->fcs == L2CAP_FCS_CRC16)
-			len -= 2;
+			len -= L2CAP_FCS_SIZE;
 
 		if (len > chan->mps || len < 0 || __is_sframe(chan, control))
 			goto drop;
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCHv2 5/5] Bluetooth: EWS: fix max_pdu calculation
  2011-09-16 13:39 [PATCHv2 0/5] EWS: extended window size and extended control field support Emeltchenko Andrei
                   ` (3 preceding siblings ...)
  2011-09-16 13:39 ` [PATCHv2 4/5] Bluetooth: EWS: remove magic numbers in l2cap Emeltchenko Andrei
@ 2011-09-16 13:39 ` Emeltchenko Andrei
  4 siblings, 0 replies; 11+ messages in thread
From: Emeltchenko Andrei @ 2011-09-16 13:39 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Fix max_pdu_size calculationin for RFC. Change magic number to human readable
defines.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/l2cap_core.c |   27 ++++++++++++++++++++-------
 1 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 195af69..7eebddd 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2004,9 +2004,13 @@ done:
 		rfc.max_transmit    = chan->max_tx;
 		rfc.retrans_timeout = 0;
 		rfc.monitor_timeout = 0;
-		rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-		if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
-			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+
+		rfc.max_pdu_size = cpu_to_le16(min_t(u16,
+						L2CAP_DEFAULT_MAX_PDU_SIZE,
+						chan->conn->mtu -
+						L2CAP_EXTENDED_HDR_SIZE -
+						L2CAP_SDULEN_SIZE -
+						L2CAP_FCS_SIZE));
 
 		l2cap_txwin_setup(chan);
 
@@ -2252,8 +2256,13 @@ done:
 
 			chan->remote_max_tx = rfc.max_transmit;
 
-			if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
-				rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+			rfc.max_pdu_size = cpu_to_le16(min_t(u16,
+						le16_to_cpu(rfc.max_pdu_size),
+						chan->conn->mtu -
+						L2CAP_EXTENDED_HDR_SIZE -
+						L2CAP_SDULEN_SIZE -
+						L2CAP_FCS_SIZE));
+
 
 			chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
@@ -2285,8 +2294,12 @@ done:
 			break;
 
 		case L2CAP_MODE_STREAMING:
-			if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
-				rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+			rfc.max_pdu_size = cpu_to_le16(min_t(u16,
+						le16_to_cpu(rfc.max_pdu_size),
+						chan->conn->mtu -
+						L2CAP_EXTENDED_HDR_SIZE -
+						L2CAP_SDULEN_SIZE -
+						L2CAP_FCS_SIZE));
 
 			chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 1/5] Bluetooth: EWS: extended window size option support
  2011-09-16 13:39 ` [PATCHv2 1/5] Bluetooth: EWS: extended window size option support Emeltchenko Andrei
@ 2011-10-06 18:05   ` Gustavo Padovan
  2011-10-07 10:33     ` Emeltchenko Andrei
  0 siblings, 1 reply; 11+ messages in thread
From: Gustavo Padovan @ 2011-10-06 18:05 UTC (permalink / raw)
  To: Emeltchenko Andrei; +Cc: linux-bluetooth

Hi Andrei,

* Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-09-16 16:39:35 +0300]:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> Adds support for EWS option. Code partly based on Qualcomm and Atheros
> patches sent upstream a year ago.
> 
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
>  include/net/bluetooth/l2cap.h |   11 ++++++--
>  net/bluetooth/l2cap_core.c    |   53 +++++++++++++++++++++++++++++++++++++---
>  net/bluetooth/l2cap_sock.c    |   10 ++++----
>  3 files changed, 62 insertions(+), 12 deletions(-)
> 
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 1f26a39..92eac16 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -31,7 +31,7 @@
>  #define L2CAP_DEFAULT_MTU		672
>  #define L2CAP_DEFAULT_MIN_MTU		48
>  #define L2CAP_DEFAULT_FLUSH_TO		0xffff
> -#define L2CAP_DEFAULT_TX_WINDOW		63
> +#define L2CAP_DEFAULT_MAX_TX_WINDOW	63

Just keep this macro as is.

>  #define L2CAP_DEFAULT_MAX_TX		3
>  #define L2CAP_DEFAULT_RETRANS_TO	2000    /* 2 seconds */
>  #define L2CAP_DEFAULT_MONITOR_TO	12000   /* 12 seconds */
> @@ -42,6 +42,8 @@
>  #define L2CAP_DEFAULT_SDU_ARRIVAL_TIME	0xFFFFFFFF
>  #define L2CAP_DEFAULT_ACCESS_LATENCY	0xFFFFFFFF
>  
> +#define L2CAP_DEFAULT_MAX_EXT_WINDOW	0x3FFF
> +

and remove MAX from this one.

>  #define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
>  #define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
>  
> @@ -240,6 +242,7 @@ struct l2cap_conf_opt {
>  #define L2CAP_CONF_RFC		0x04
>  #define L2CAP_CONF_FCS		0x05
>  #define L2CAP_CONF_EFS		0x06
> +#define L2CAP_CONF_EWS		0x07
>  
>  #define L2CAP_CONF_MAX_SIZE	22
>  
> @@ -357,7 +360,7 @@ struct l2cap_chan {
>  
>  	__u8		fcs;
>  
> -	__u8		tx_win;
> +	__u16		tx_win;
>  	__u8		max_tx;
>  	__u16		retrans_timeout;
>  	__u16		monitor_timeout;
> @@ -381,7 +384,7 @@ struct l2cap_chan {
>  	struct sk_buff	*sdu;
>  	struct sk_buff	*sdu_last_frag;
>  
> -	__u8		remote_tx_win;
> +	__u16		remote_tx_win;
>  	__u8		remote_max_tx;
>  	__u16		remote_mps;
>  
> @@ -488,6 +491,7 @@ enum {
>  	CONF_STATE2_DEVICE,
>  	CONF_LOCAL_PEND,
>  	CONF_REMOTE_PEND,
> +	CONF_EWS_RECV,
>  };
>  
>  #define L2CAP_CONF_MAX_CONF_REQ 2
> @@ -508,6 +512,7 @@ enum {
>  /* Definitions for flags in l2cap_chan */
>  enum {
>  	FLAG_EFS_ENABLE,
> +	FLAG_EXT_CTRL,
>  };
>  
>  #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 7aad856..69e974a 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -1906,6 +1906,22 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
>  	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
>  }
>  
> +static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
> +{
> +	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
> +}
> +
> +static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
> +{
> +	if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW &&
> +						__l2cap_ews_supported(chan))
> +		/* use extended control field */
> +		set_bit(FLAG_EXT_CTRL, &chan->flags);
> +	else
> +		chan->tx_win = min_t(u16, chan->tx_win,
> +						L2CAP_DEFAULT_MAX_TX_WINDOW);
> +}
> +
>  static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
>  {
>  	struct l2cap_conf_req *req = data;
> @@ -1957,7 +1973,6 @@ done:
>  
>  	case L2CAP_MODE_ERTM:
>  		rfc.mode            = L2CAP_MODE_ERTM;
> -		rfc.txwin_size      = chan->tx_win;
>  		rfc.max_transmit    = chan->max_tx;
>  		rfc.retrans_timeout = 0;
>  		rfc.monitor_timeout = 0;
> @@ -1965,6 +1980,11 @@ done:
>  		if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
>  			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
>  
> +		l2cap_txwin_setup(chan);
> +
> +		rfc.txwin_size = min_t(u16, chan->tx_win,
> +						L2CAP_DEFAULT_MAX_TX_WINDOW);

rfc.txwin_size is exactly chan->tx_win.


Also I would like to see a patch cleaning up the names we give to the tx
window. Some places is tx_win, others txwin_size or even txwin.

> +
>  		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
>  							(unsigned long) &rfc);
>  
> @@ -1996,6 +2016,10 @@ done:
>  			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
>  		}
>  
> +		if (__l2cap_ews_supported(chan) &&
> +				test_bit(FLAG_EXT_CTRL, &chan->flags))

if EXT_CTRL is true there is no need to to check for __l2cap_ews_supported().
It is true as well.

> +			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
> +					chan->tx_win);
>  		break;
>  
>  	case L2CAP_MODE_STREAMING:
> @@ -2033,7 +2057,10 @@ done:
>  			chan->fcs = L2CAP_FCS_NONE;
>  			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
>  		}
> -
> +		
> +		if (__l2cap_ews_supported(chan) &&
> +				test_bit(FLAG_EXT_CTRL, &chan->flags))
> +			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, 0);

same here.

>  		break;
>  	}
>  
> @@ -2093,6 +2120,12 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
>  				memcpy(&efs, (void *) val, olen);
>  			break;
>  
> +		case L2CAP_CONF_EWS:
> +			set_bit(FLAG_EXT_CTRL, &chan->flags);
> +			chan->remote_tx_win = val;
> +			set_bit(CONF_EWS_RECV, &chan->conf_state);
> +			break;
> +
>  		default:
>  			if (hint)
>  				break;
> @@ -2183,7 +2216,11 @@ done:
>  			break;
>  
>  		case L2CAP_MODE_ERTM:
> -			chan->remote_tx_win = rfc.txwin_size;
> +			if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
> +				chan->remote_tx_win = rfc.txwin_size;
> +			else
> +				rfc.txwin_size = L2CAP_DEFAULT_MAX_TX_WINDOW;
> +

This seems better:
			if (test_bit(CONF_EWS_RECV)
				rfc.txwin_size = L2CAP_DEFAULT_MAX_TX_WINDOW

			chan->remote_tx_win = rfc.txwin_size;

Actually why does this code exist? Why do you want to set tx_win to
L2CAP_DEFAULT_MAX_TX_WINDOW when EWS is received.


>  			chan->remote_max_tx = rfc.max_transmit;
>  
>  			if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
> @@ -2304,6 +2341,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
>  			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
>  					sizeof(efs), (unsigned long) &efs);
>  			break;
> +
> +		case L2CAP_CONF_EWS:
> +			chan->tx_win = val < L2CAP_DEFAULT_MAX_EXT_WINDOW ?
> +				val : L2CAP_DEFAULT_MAX_EXT_WINDOW;

This should be <=, but the end result is the same.

	Gustavo

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 2/5] Bluetooth: EWS: l2cap extended control field support
  2011-09-16 13:39 ` [PATCHv2 2/5] Bluetooth: EWS: l2cap extended control field support Emeltchenko Andrei
@ 2011-10-06 18:19   ` Gustavo Padovan
  0 siblings, 0 replies; 11+ messages in thread
From: Gustavo Padovan @ 2011-10-06 18:19 UTC (permalink / raw)
  To: Emeltchenko Andrei; +Cc: linux-bluetooth

Hi Andrei,

* Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-09-16 16:39:36 +0300]:

>  /* L2CAP Supervisory Function */
> -#define L2CAP_SUPER_RCV_READY           0x0000
> -#define L2CAP_SUPER_REJECT              0x0004
> -#define L2CAP_SUPER_RCV_NOT_READY       0x0008
> -#define L2CAP_SUPER_SELECT_REJECT       0x000C
> +#define L2CAP_SUPER_RR		0x00
> +#define L2CAP_SUPER_REJ		0x01
> +#define L2CAP_SUPER_RNR		0x02
> +#define L2CAP_SUPER_SREJ	0x03
>  
>  /* L2CAP Segmentation and Reassembly */
> -#define L2CAP_SDU_UNSEGMENTED       0x0000
> -#define L2CAP_SDU_START             0x4000
> -#define L2CAP_SDU_END               0x8000
> -#define L2CAP_SDU_CONTINUE          0xC000
> +#define L2CAP_SAR_UNSEGMENTED	0x00
> +#define L2CAP_SAR_START		0x01
> +#define L2CAP_SAR_END		0x02
> +#define L2CAP_SAR_CONTINUE	0x03

I want a separate patch of these macro renames. This patch is already big.

>  
>  /* L2CAP Command rej. reasons */
> -#define L2CAP_REJ_NOT_UNDERSTOOD      0x0000
> -#define L2CAP_REJ_MTU_EXCEEDED        0x0001
> -#define L2CAP_REJ_INVALID_CID         0x0002
> -
> +#define L2CAP_REJ_NOT_UNDERSTOOD	0x0000
> +#define L2CAP_REJ_MTU_EXCEEDED		0x0001
> +#define L2CAP_REJ_INVALID_CID		0x0002
>  
>  /* L2CAP structures */
>  struct l2cap_hdr {
> @@ -150,6 +168,11 @@ struct l2cap_hdr {
>  	__le16     cid;
>  } __packed;
>  #define L2CAP_HDR_SIZE		4
> +#define L2CAP_ENHANCED_HDR_SIZE	6
> +#define L2CAP_EXTENDED_HDR_SIZE	8

Use ENH and EXT instead.

> +
> +#define L2CAP_FCS_SIZE		2
> +#define L2CAP_SDULEN_SIZE	2

A separate patch for this 4 new macros as well.

	Gustavo

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 1/5] Bluetooth: EWS: extended window size option support
  2011-10-06 18:05   ` Gustavo Padovan
@ 2011-10-07 10:33     ` Emeltchenko Andrei
  2011-10-07 20:26       ` Gustavo Padovan
  0 siblings, 1 reply; 11+ messages in thread
From: Emeltchenko Andrei @ 2011-10-07 10:33 UTC (permalink / raw)
  To: linux-bluetooth

Hi Gustavo,

On Thu, Oct 06, 2011 at 03:05:14PM -0300, Gustavo Padovan wrote:
> > Adds support for EWS option. Code partly based on Qualcomm and Atheros
> > patches sent upstream a year ago.
> > 
> > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > ---
> >  include/net/bluetooth/l2cap.h |   11 ++++++--
> >  net/bluetooth/l2cap_core.c    |   53 +++++++++++++++++++++++++++++++++++++---
> >  net/bluetooth/l2cap_sock.c    |   10 ++++----
> >  3 files changed, 62 insertions(+), 12 deletions(-)
> > 
> > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> > index 1f26a39..92eac16 100644
> > --- a/include/net/bluetooth/l2cap.h
> > +++ b/include/net/bluetooth/l2cap.h
> > @@ -31,7 +31,7 @@
> >  #define L2CAP_DEFAULT_MTU		672
> >  #define L2CAP_DEFAULT_MIN_MTU		48
> >  #define L2CAP_DEFAULT_FLUSH_TO		0xffff
> > -#define L2CAP_DEFAULT_TX_WINDOW		63
> > +#define L2CAP_DEFAULT_MAX_TX_WINDOW	63
> 
> Just keep this macro as is.
> 
> >  #define L2CAP_DEFAULT_MAX_TX		3
> >  #define L2CAP_DEFAULT_RETRANS_TO	2000    /* 2 seconds */
> >  #define L2CAP_DEFAULT_MONITOR_TO	12000   /* 12 seconds */
> > @@ -42,6 +42,8 @@
> >  #define L2CAP_DEFAULT_SDU_ARRIVAL_TIME	0xFFFFFFFF
> >  #define L2CAP_DEFAULT_ACCESS_LATENCY	0xFFFFFFFF
> >  
> > +#define L2CAP_DEFAULT_MAX_EXT_WINDOW	0x3FFF
> > +
> 
> and remove MAX from this one.
> 
> >  #define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
> >  #define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
> >  
> > @@ -240,6 +242,7 @@ struct l2cap_conf_opt {
> >  #define L2CAP_CONF_RFC		0x04
> >  #define L2CAP_CONF_FCS		0x05
> >  #define L2CAP_CONF_EFS		0x06
> > +#define L2CAP_CONF_EWS		0x07
> >  
> >  #define L2CAP_CONF_MAX_SIZE	22
> >  
> > @@ -357,7 +360,7 @@ struct l2cap_chan {
> >  
> >  	__u8		fcs;
> >  
> > -	__u8		tx_win;
> > +	__u16		tx_win;
> >  	__u8		max_tx;
> >  	__u16		retrans_timeout;
> >  	__u16		monitor_timeout;
> > @@ -381,7 +384,7 @@ struct l2cap_chan {
> >  	struct sk_buff	*sdu;
> >  	struct sk_buff	*sdu_last_frag;
> >  
> > -	__u8		remote_tx_win;
> > +	__u16		remote_tx_win;
> >  	__u8		remote_max_tx;
> >  	__u16		remote_mps;
> >  
> > @@ -488,6 +491,7 @@ enum {
> >  	CONF_STATE2_DEVICE,
> >  	CONF_LOCAL_PEND,
> >  	CONF_REMOTE_PEND,
> > +	CONF_EWS_RECV,
> >  };
> >  
> >  #define L2CAP_CONF_MAX_CONF_REQ 2
> > @@ -508,6 +512,7 @@ enum {
> >  /* Definitions for flags in l2cap_chan */
> >  enum {
> >  	FLAG_EFS_ENABLE,
> > +	FLAG_EXT_CTRL,
> >  };
> >  
> >  #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > index 7aad856..69e974a 100644
> > --- a/net/bluetooth/l2cap_core.c
> > +++ b/net/bluetooth/l2cap_core.c
> > @@ -1906,6 +1906,22 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
> >  	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
> >  }
> >  
> > +static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
> > +{
> > +	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
> > +}
> > +
> > +static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
> > +{
> > +	if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW &&
> > +						__l2cap_ews_supported(chan))
> > +		/* use extended control field */
> > +		set_bit(FLAG_EXT_CTRL, &chan->flags);
> > +	else
> > +		chan->tx_win = min_t(u16, chan->tx_win,
> > +						L2CAP_DEFAULT_MAX_TX_WINDOW);
> > +}
> > +
> >  static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
> >  {
> >  	struct l2cap_conf_req *req = data;
> > @@ -1957,7 +1973,6 @@ done:
> >  
> >  	case L2CAP_MODE_ERTM:
> >  		rfc.mode            = L2CAP_MODE_ERTM;
> > -		rfc.txwin_size      = chan->tx_win;
> >  		rfc.max_transmit    = chan->max_tx;
> >  		rfc.retrans_timeout = 0;
> >  		rfc.monitor_timeout = 0;
> > @@ -1965,6 +1980,11 @@ done:
> >  		if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
> >  			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
> >  
> > +		l2cap_txwin_setup(chan);
> > +
> > +		rfc.txwin_size = min_t(u16, chan->tx_win,
> > +						L2CAP_DEFAULT_MAX_TX_WINDOW);
> 
> rfc.txwin_size is exactly chan->tx_win.

chan->tx_win might be bigger then L2CAP_DEFAULT_MAX_TX_WINDOW since we
allow to set bigger value via socket (see below).

Current idea is to allow user to set txwin < EXT_WINDOW and if ews_supported
and txwin > TX_WINDOW then we enable extended control field.

> Also I would like to see a patch cleaning up the names we give to the tx
> window. Some places is tx_win, others txwin_size or even txwin.

This is true, I can create clean up patch later.

> 
> > +
> >  		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> >  							(unsigned long) &rfc);
> >  
> > @@ -1996,6 +2016,10 @@ done:
> >  			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
> >  		}
> >  
> > +		if (__l2cap_ews_supported(chan) &&
> > +				test_bit(FLAG_EXT_CTRL, &chan->flags))
> 
> if EXT_CTRL is true there is no need to to check for __l2cap_ews_supported().
> It is true as well.

will fix

> 
> > +			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
> > +					chan->tx_win);
> >  		break;
> >  
> >  	case L2CAP_MODE_STREAMING:
> > @@ -2033,7 +2057,10 @@ done:
> >  			chan->fcs = L2CAP_FCS_NONE;
> >  			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
> >  		}
> > -
> > +		
> > +		if (__l2cap_ews_supported(chan) &&
> > +				test_bit(FLAG_EXT_CTRL, &chan->flags))
> > +			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, 0);
> 
> same here.

OK, btw in streaming mode we do not use txwin so I do not know how to
trigger EXT_CTRL from user. 

I think I will remove this code at all.

> 
> >  		break;
> >  	}
> >  
> > @@ -2093,6 +2120,12 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
> >  				memcpy(&efs, (void *) val, olen);
> >  			break;
> >  
> > +		case L2CAP_CONF_EWS:
> > +			set_bit(FLAG_EXT_CTRL, &chan->flags);
> > +			chan->remote_tx_win = val;
> > +			set_bit(CONF_EWS_RECV, &chan->conf_state);
> > +			break;
> > +
> >  		default:
> >  			if (hint)
> >  				break;
> > @@ -2183,7 +2216,11 @@ done:
> >  			break;
> >  
> >  		case L2CAP_MODE_ERTM:
> > -			chan->remote_tx_win = rfc.txwin_size;
> > +			if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
> > +				chan->remote_tx_win = rfc.txwin_size;
> > +			else
> > +				rfc.txwin_size = L2CAP_DEFAULT_MAX_TX_WINDOW;
> > +
> 
> This seems better:
> 			if (test_bit(CONF_EWS_RECV)
> 				rfc.txwin_size = L2CAP_DEFAULT_MAX_TX_WINDOW
> 
> 			chan->remote_tx_win = rfc.txwin_size;

remote_tx_win and rfc.txwin_size are different in size. remote_tx_win
might be bigger then L2CAP_DEFAULT_MAX_TX_WINDOW.

> Actually why does this code exist? Why do you want to set tx_win to
> L2CAP_DEFAULT_MAX_TX_WINDOW when EWS is received.

I thought it would be better to put this value despite RFC field will be
ignored. Otherwise the field would be the same as for streaming mode.

> >  			chan->remote_max_tx = rfc.max_transmit;
> >  
> >  			if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
> > @@ -2304,6 +2341,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
> >  			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
> >  					sizeof(efs), (unsigned long) &efs);
> >  			break;
> > +
> > +		case L2CAP_CONF_EWS:
> > +			chan->tx_win = val < L2CAP_DEFAULT_MAX_EXT_WINDOW ?
> > +				val : L2CAP_DEFAULT_MAX_EXT_WINDOW;
> 
> This should be <=, but the end result is the same.

I change it to:

chan->tx_win = min_t(u16, val, L2CAP_DEFAULT_EXT_WINDOW);

Best regards 
Andrei Emeltchenko 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 1/5] Bluetooth: EWS: extended window size option support
  2011-10-07 10:33     ` Emeltchenko Andrei
@ 2011-10-07 20:26       ` Gustavo Padovan
  2011-10-10  8:02         ` Emeltchenko Andrei
  0 siblings, 1 reply; 11+ messages in thread
From: Gustavo Padovan @ 2011-10-07 20:26 UTC (permalink / raw)
  To: Emeltchenko Andrei, linux-bluetooth

Hi Andrei,

* Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-07 13:33:09 +0300]:

> Hi Gustavo,
> 
> On Thu, Oct 06, 2011 at 03:05:14PM -0300, Gustavo Padovan wrote:
> > > Adds support for EWS option. Code partly based on Qualcomm and Atheros
> > > patches sent upstream a year ago.
> > > 
> > > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > > ---
> > >  include/net/bluetooth/l2cap.h |   11 ++++++--
> > >  net/bluetooth/l2cap_core.c    |   53 +++++++++++++++++++++++++++++++++++++---
> > >  net/bluetooth/l2cap_sock.c    |   10 ++++----
> > >  3 files changed, 62 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> > > index 1f26a39..92eac16 100644
> > > --- a/include/net/bluetooth/l2cap.h
> > > +++ b/include/net/bluetooth/l2cap.h
> > > @@ -31,7 +31,7 @@
> > >  #define L2CAP_DEFAULT_MTU		672
> > >  #define L2CAP_DEFAULT_MIN_MTU		48
> > >  #define L2CAP_DEFAULT_FLUSH_TO		0xffff
> > > -#define L2CAP_DEFAULT_TX_WINDOW		63
> > > +#define L2CAP_DEFAULT_MAX_TX_WINDOW	63
> > 
> > Just keep this macro as is.
> > 
> > >  #define L2CAP_DEFAULT_MAX_TX		3
> > >  #define L2CAP_DEFAULT_RETRANS_TO	2000    /* 2 seconds */
> > >  #define L2CAP_DEFAULT_MONITOR_TO	12000   /* 12 seconds */
> > > @@ -42,6 +42,8 @@
> > >  #define L2CAP_DEFAULT_SDU_ARRIVAL_TIME	0xFFFFFFFF
> > >  #define L2CAP_DEFAULT_ACCESS_LATENCY	0xFFFFFFFF
> > >  
> > > +#define L2CAP_DEFAULT_MAX_EXT_WINDOW	0x3FFF
> > > +
> > 
> > and remove MAX from this one.
> > 
> > >  #define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
> > >  #define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
> > >  
> > > @@ -240,6 +242,7 @@ struct l2cap_conf_opt {
> > >  #define L2CAP_CONF_RFC		0x04
> > >  #define L2CAP_CONF_FCS		0x05
> > >  #define L2CAP_CONF_EFS		0x06
> > > +#define L2CAP_CONF_EWS		0x07
> > >  
> > >  #define L2CAP_CONF_MAX_SIZE	22
> > >  
> > > @@ -357,7 +360,7 @@ struct l2cap_chan {
> > >  
> > >  	__u8		fcs;
> > >  
> > > -	__u8		tx_win;
> > > +	__u16		tx_win;
> > >  	__u8		max_tx;
> > >  	__u16		retrans_timeout;
> > >  	__u16		monitor_timeout;
> > > @@ -381,7 +384,7 @@ struct l2cap_chan {
> > >  	struct sk_buff	*sdu;
> > >  	struct sk_buff	*sdu_last_frag;
> > >  
> > > -	__u8		remote_tx_win;
> > > +	__u16		remote_tx_win;
> > >  	__u8		remote_max_tx;
> > >  	__u16		remote_mps;
> > >  
> > > @@ -488,6 +491,7 @@ enum {
> > >  	CONF_STATE2_DEVICE,
> > >  	CONF_LOCAL_PEND,
> > >  	CONF_REMOTE_PEND,
> > > +	CONF_EWS_RECV,
> > >  };
> > >  
> > >  #define L2CAP_CONF_MAX_CONF_REQ 2
> > > @@ -508,6 +512,7 @@ enum {
> > >  /* Definitions for flags in l2cap_chan */
> > >  enum {
> > >  	FLAG_EFS_ENABLE,
> > > +	FLAG_EXT_CTRL,
> > >  };
> > >  
> > >  #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
> > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > > index 7aad856..69e974a 100644
> > > --- a/net/bluetooth/l2cap_core.c
> > > +++ b/net/bluetooth/l2cap_core.c
> > > @@ -1906,6 +1906,22 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
> > >  	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
> > >  }
> > >  
> > > +static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
> > > +{
> > > +	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
> > > +}
> > > +
> > > +static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
> > > +{
> > > +	if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW &&
> > > +						__l2cap_ews_supported(chan))
> > > +		/* use extended control field */
> > > +		set_bit(FLAG_EXT_CTRL, &chan->flags);
> > > +	else
> > > +		chan->tx_win = min_t(u16, chan->tx_win,
> > > +						L2CAP_DEFAULT_MAX_TX_WINDOW);
> > > +}
> > > +
> > >  static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
> > >  {
> > >  	struct l2cap_conf_req *req = data;
> > > @@ -1957,7 +1973,6 @@ done:
> > >  
> > >  	case L2CAP_MODE_ERTM:
> > >  		rfc.mode            = L2CAP_MODE_ERTM;
> > > -		rfc.txwin_size      = chan->tx_win;
> > >  		rfc.max_transmit    = chan->max_tx;
> > >  		rfc.retrans_timeout = 0;
> > >  		rfc.monitor_timeout = 0;
> > > @@ -1965,6 +1980,11 @@ done:
> > >  		if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
> > >  			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
> > >  
> > > +		l2cap_txwin_setup(chan);
> > > +
> > > +		rfc.txwin_size = min_t(u16, chan->tx_win,
> > > +						L2CAP_DEFAULT_MAX_TX_WINDOW);
> > 
> > rfc.txwin_size is exactly chan->tx_win.
> 
> chan->tx_win might be bigger then L2CAP_DEFAULT_MAX_TX_WINDOW since we
> allow to set bigger value via socket (see below).
> 
> Current idea is to allow user to set txwin < EXT_WINDOW and if ews_supported
> and txwin > TX_WINDOW then we enable extended control field.

Yes, but look:


+static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
+{
+       if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW &&
+                                               __l2cap_ews_supported(chan))
+               /* use extended control field */
+               set_bit(FLAG_EXT_CTRL, &chan->flags);
+       else
+               chan->tx_win = min_t(u16, chan->tx_win,
+                                               L2CAP_DEFAULT_MAX_TX_WINDOW);
+}

In l2cap_txwin_setup() chan->tx_win is already set to the value we want so
call the same min_t after it seems rather pointless. Just remove it and do a
direct assignment.

	Gustavo

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 1/5] Bluetooth: EWS: extended window size option support
  2011-10-07 20:26       ` Gustavo Padovan
@ 2011-10-10  8:02         ` Emeltchenko Andrei
  0 siblings, 0 replies; 11+ messages in thread
From: Emeltchenko Andrei @ 2011-10-10  8:02 UTC (permalink / raw)
  To: linux-bluetooth

Hi Gustavo,

On Fri, Oct 07, 2011 at 05:26:38PM -0300, Gustavo Padovan wrote:
> > > > Adds support for EWS option. Code partly based on Qualcomm and Atheros
> > > > patches sent upstream a year ago.
> > > > 
> > > > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > > > ---
> > > >  include/net/bluetooth/l2cap.h |   11 ++++++--
> > > >  net/bluetooth/l2cap_core.c    |   53 +++++++++++++++++++++++++++++++++++++---
> > > >  net/bluetooth/l2cap_sock.c    |   10 ++++----
> > > >  3 files changed, 62 insertions(+), 12 deletions(-)
> > > > 
> > > > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> > > > index 1f26a39..92eac16 100644
> > > > --- a/include/net/bluetooth/l2cap.h
> > > > +++ b/include/net/bluetooth/l2cap.h
> > > > @@ -31,7 +31,7 @@
> > > >  #define L2CAP_DEFAULT_MTU		672
> > > >  #define L2CAP_DEFAULT_MIN_MTU		48
> > > >  #define L2CAP_DEFAULT_FLUSH_TO		0xffff
> > > > -#define L2CAP_DEFAULT_TX_WINDOW		63
> > > > +#define L2CAP_DEFAULT_MAX_TX_WINDOW	63
> > > 
> > > Just keep this macro as is.
> > > 
> > > >  #define L2CAP_DEFAULT_MAX_TX		3
> > > >  #define L2CAP_DEFAULT_RETRANS_TO	2000    /* 2 seconds */
> > > >  #define L2CAP_DEFAULT_MONITOR_TO	12000   /* 12 seconds */
> > > > @@ -42,6 +42,8 @@
> > > >  #define L2CAP_DEFAULT_SDU_ARRIVAL_TIME	0xFFFFFFFF
> > > >  #define L2CAP_DEFAULT_ACCESS_LATENCY	0xFFFFFFFF
> > > >  
> > > > +#define L2CAP_DEFAULT_MAX_EXT_WINDOW	0x3FFF
> > > > +
> > > 
> > > and remove MAX from this one.
> > > 
> > > >  #define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
> > > >  #define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
> > > >  
> > > > @@ -240,6 +242,7 @@ struct l2cap_conf_opt {
> > > >  #define L2CAP_CONF_RFC		0x04
> > > >  #define L2CAP_CONF_FCS		0x05
> > > >  #define L2CAP_CONF_EFS		0x06
> > > > +#define L2CAP_CONF_EWS		0x07
> > > >  
> > > >  #define L2CAP_CONF_MAX_SIZE	22
> > > >  
> > > > @@ -357,7 +360,7 @@ struct l2cap_chan {
> > > >  
> > > >  	__u8		fcs;
> > > >  
> > > > -	__u8		tx_win;
> > > > +	__u16		tx_win;
> > > >  	__u8		max_tx;
> > > >  	__u16		retrans_timeout;
> > > >  	__u16		monitor_timeout;
> > > > @@ -381,7 +384,7 @@ struct l2cap_chan {
> > > >  	struct sk_buff	*sdu;
> > > >  	struct sk_buff	*sdu_last_frag;
> > > >  
> > > > -	__u8		remote_tx_win;
> > > > +	__u16		remote_tx_win;
> > > >  	__u8		remote_max_tx;
> > > >  	__u16		remote_mps;
> > > >  
> > > > @@ -488,6 +491,7 @@ enum {
> > > >  	CONF_STATE2_DEVICE,
> > > >  	CONF_LOCAL_PEND,
> > > >  	CONF_REMOTE_PEND,
> > > > +	CONF_EWS_RECV,
> > > >  };
> > > >  
> > > >  #define L2CAP_CONF_MAX_CONF_REQ 2
> > > > @@ -508,6 +512,7 @@ enum {
> > > >  /* Definitions for flags in l2cap_chan */
> > > >  enum {
> > > >  	FLAG_EFS_ENABLE,
> > > > +	FLAG_EXT_CTRL,
> > > >  };
> > > >  
> > > >  #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
> > > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > > > index 7aad856..69e974a 100644
> > > > --- a/net/bluetooth/l2cap_core.c
> > > > +++ b/net/bluetooth/l2cap_core.c
> > > > @@ -1906,6 +1906,22 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
> > > >  	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
> > > >  }
> > > >  
> > > > +static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
> > > > +{
> > > > +	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
> > > > +}
> > > > +
> > > > +static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
> > > > +{
> > > > +	if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW &&
> > > > +						__l2cap_ews_supported(chan))
> > > > +		/* use extended control field */
> > > > +		set_bit(FLAG_EXT_CTRL, &chan->flags);
> > > > +	else
> > > > +		chan->tx_win = min_t(u16, chan->tx_win,
> > > > +						L2CAP_DEFAULT_MAX_TX_WINDOW);
> > > > +}
> > > > +
> > > >  static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
> > > >  {
> > > >  	struct l2cap_conf_req *req = data;
> > > > @@ -1957,7 +1973,6 @@ done:
> > > >  
> > > >  	case L2CAP_MODE_ERTM:
> > > >  		rfc.mode            = L2CAP_MODE_ERTM;
> > > > -		rfc.txwin_size      = chan->tx_win;
> > > >  		rfc.max_transmit    = chan->max_tx;
> > > >  		rfc.retrans_timeout = 0;
> > > >  		rfc.monitor_timeout = 0;
> > > > @@ -1965,6 +1980,11 @@ done:
> > > >  		if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
> > > >  			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
> > > >  
> > > > +		l2cap_txwin_setup(chan);
> > > > +
> > > > +		rfc.txwin_size = min_t(u16, chan->tx_win,
> > > > +						L2CAP_DEFAULT_MAX_TX_WINDOW);
> > > 
> > > rfc.txwin_size is exactly chan->tx_win.
> > 
> > chan->tx_win might be bigger then L2CAP_DEFAULT_MAX_TX_WINDOW since we
> > allow to set bigger value via socket (see below).
> > 
> > Current idea is to allow user to set txwin < EXT_WINDOW and if ews_supported
> > and txwin > TX_WINDOW then we enable extended control field.
> 
> Yes, but look:
> 
> 
> +static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
> +{
> +       if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW &&
> +                                               __l2cap_ews_supported(chan))
> +               /* use extended control field */
> +               set_bit(FLAG_EXT_CTRL, &chan->flags);
> +       else
> +               chan->tx_win = min_t(u16, chan->tx_win,
> +                                               L2CAP_DEFAULT_MAX_TX_WINDOW);
> +}
> 
> In l2cap_txwin_setup() chan->tx_win is already set to the value we want so
> call the same min_t after it seems rather pointless. Just remove it and do a
> direct assignment.

If tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW (63) && ews_supported then tx_win might
be up to L2CAP_DEFAULT_EXT_WINDOW (0x3fff)

Where:
#define L2CAP_DEFAULT_TX_WINDOW        63
#define L2CAP_DEFAULT_EXT_WINDOW       0x3FFF

We cannot assign to TxWindow from RETRANSMISSION AND FLOW CONTROL OPTION
which shall be: "The range is 1 to 63 for Enhanced Retransmission mode."

BLUETOOTH SPECIFICATION Version 4.0 [Vol 3] page 87 of 656

Best regards 
Andrei Emeltchenko 

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2011-10-10  8:02 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-09-16 13:39 [PATCHv2 0/5] EWS: extended window size and extended control field support Emeltchenko Andrei
2011-09-16 13:39 ` [PATCHv2 1/5] Bluetooth: EWS: extended window size option support Emeltchenko Andrei
2011-10-06 18:05   ` Gustavo Padovan
2011-10-07 10:33     ` Emeltchenko Andrei
2011-10-07 20:26       ` Gustavo Padovan
2011-10-10  8:02         ` Emeltchenko Andrei
2011-09-16 13:39 ` [PATCHv2 2/5] Bluetooth: EWS: l2cap extended control field support Emeltchenko Andrei
2011-10-06 18:19   ` Gustavo Padovan
2011-09-16 13:39 ` [PATCHv2 3/5] Bluetooth: EWS: support extended seq numbers Emeltchenko Andrei
2011-09-16 13:39 ` [PATCHv2 4/5] Bluetooth: EWS: remove magic numbers in l2cap Emeltchenko Andrei
2011-09-16 13:39 ` [PATCHv2 5/5] Bluetooth: EWS: fix max_pdu calculation Emeltchenko Andrei

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).