Linux bluetooth development
 help / color / mirror / Atom feed
* [RFCv0 0/5] extended window size and extended control field support
@ 2011-08-30  7:18 Emeltchenko Andrei
  2011-08-30  7:18 ` [RFCv0 1/5] Bluetooth: extended window size option support Emeltchenko Andrei
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Emeltchenko Andrei @ 2011-08-30  7:18 UTC (permalink / raw)
  To: linux-bluetooth

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

First draft patches applied to my previous EFS patches. Please comment.

Adds support for extended window size option (EWS) and extended control
field. Code partly based on Atheros patches sent a year ago 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.

Andrei Emeltchenko (5):
  Bluetooth: extended window size option support
  Bluetooth: l2cap extended control field support
  Bluetooth: EWS: support extended seq numbers
  Bluetooth: remove magic numbers in l2cap
  Bluetooth: prevent unneeded fragmentation in l2cap

 include/net/bluetooth/l2cap.h |  304 ++++++++++++++++++++++----
 net/bluetooth/l2cap_core.c    |  481 +++++++++++++++++++++++++----------------
 net/bluetooth/l2cap_sock.c    |   11 +-
 3 files changed, 562 insertions(+), 234 deletions(-)

-- 
1.7.4.1


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

* [RFCv0 1/5] Bluetooth: extended window size option support
  2011-08-30  7:18 [RFCv0 0/5] extended window size and extended control field support Emeltchenko Andrei
@ 2011-08-30  7:18 ` Emeltchenko Andrei
  2011-08-30  7:18 ` [RFCv0 2/5] Bluetooth: l2cap extended control field support Emeltchenko Andrei
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Emeltchenko Andrei @ 2011-08-30  7:18 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    |   60 +++++++++++++++++++++++++++++++++++++++-
 net/bluetooth/l2cap_sock.c    |   10 +++---
 3 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 2350057..b586a55 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;
@@ -380,7 +383,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;
 
@@ -399,6 +402,7 @@ struct l2cap_chan {
 	__u32		remote_flush_to;
 
 	__u8            ext_flowspec_enable;
+	__u8		ext_ctrl;
 
 	struct timer_list	chan_timer;
 	struct timer_list	retrans_timer;
@@ -491,6 +495,7 @@ enum {
 	CONF_STATE2_DEVICE,
 	CONF_LOCAL_PEND,
 	CONF_REMOTE_PEND,
+	CONF_EWS_RECV,
 };
 
 #define L2CAP_CONF_MAX_CONF_REQ 2
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index de9995d..0d62b05 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -58,6 +58,7 @@
 
 int disable_ertm;
 int disable_flowspec = 1;
+int disable_extwindow = 1;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
 static u8 l2cap_fixed_chan[8] = { 0x02, };
@@ -1916,6 +1917,28 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
 			chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
 }
 
+static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
+{
+	return !disable_extwindow &&
+			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 */
+		chan->ext_ctrl = 1;
+		if (chan->tx_win > L2CAP_DEFAULT_MAX_EXT_WINDOW)
+			chan->tx_win = L2CAP_DEFAULT_MAX_EXT_WINDOW;
+	} else {
+		if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW)
+			chan->tx_win = L2CAP_DEFAULT_MAX_TX_WINDOW;
+
+		chan->ext_ctrl = 0;
+	}
+}
+
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
 {
 	struct l2cap_conf_req *req = data;
@@ -1976,7 +1999,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;
@@ -1984,6 +2006,10 @@ 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 = chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW?
+			L2CAP_DEFAULT_MAX_TX_WINDOW : chan->tx_win;
+
 		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
 							(unsigned long) &rfc);
 
@@ -2023,6 +2049,10 @@ done:
 					sizeof(efs), (unsigned long) &efs);
 		}
 
+		if (__l2cap_ews_supported(chan) && chan->ext_ctrl)
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+					chan->tx_win);
+
 		break;
 
 	case L2CAP_MODE_STREAMING:
@@ -2061,6 +2091,9 @@ done:
 					sizeof(efs), (unsigned long) &efs);
 		}
 
+		if (__l2cap_ews_supported(chan) && chan->ext_ctrl)
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, 0);
+
 		break;
 	}
 
@@ -2121,6 +2154,12 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 				memcpy(&efs, (void *) val, olen);
 			break;
 
+		case L2CAP_CONF_EWS:
+			chan->ext_ctrl = 1;
+			chan->remote_tx_win = val;
+			set_bit(CONF_EWS_RECV, &chan->conf_state);
+			break;
+
 		default:
 			if (hint)
 				break;
@@ -2217,7 +2256,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)
@@ -2339,6 +2382,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;
 		}
 	}
 
@@ -2980,6 +3030,9 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
 		if (!disable_flowspec)
 			feat_mask |= L2CAP_FEAT_EXT_FLOW;
 
+		if (!disable_extwindow)
+			feat_mask |= L2CAP_FEAT_EXT_WINDOW;
+
 		put_unaligned_le32(feat_mask, rsp->data);
 		l2cap_send_cmd(conn, cmd->ident,
 					L2CAP_INFO_RSP, sizeof(buf), buf);
@@ -4504,3 +4557,6 @@ MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
 
 module_param(disable_flowspec, bool, 0644);
 MODULE_PARM_DESC(disable_flowspec, "Disable Extended Flow Specification");
+
+module_param(disable_extwindow, bool, 0644);
+MODULE_PARM_DESC(disable_extwindow, "Disable Extended Window Size");
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] 10+ messages in thread

* [RFCv0 2/5] Bluetooth: l2cap extended control field support
  2011-08-30  7:18 [RFCv0 0/5] extended window size and extended control field support Emeltchenko Andrei
  2011-08-30  7:18 ` [RFCv0 1/5] Bluetooth: extended window size option support Emeltchenko Andrei
@ 2011-08-30  7:18 ` Emeltchenko Andrei
  2011-08-30  7:18 ` [RFCv0 3/5] Bluetooth: EWS: support extended seq numbers Emeltchenko Andrei
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Emeltchenko Andrei @ 2011-08-30  7:18 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 |  276 ++++++++++++++++++++++++++++++++------
 net/bluetooth/l2cap_core.c    |  299 +++++++++++++++++++++++------------------
 2 files changed, 405 insertions(+), 170 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b586a55..e2906c8 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_MASK		0xC000
+#define L2CAP_CTRL_REQSEQ_MASK		0x3F00
+#define L2CAP_CTRL_TXSEQ_MASK		0x007E
+#define L2CAP_CTRL_SUPERVISE_MASK	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_MASK	0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR_MASK		0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE_MASK	0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ_MASK	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;
 };
 
@@ -369,16 +392,16 @@ struct l2cap_chan {
 	unsigned long	conf_state;
 	unsigned long	conn_state;
 
-	__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;
@@ -537,11 +560,186 @@ 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(__u8 ext_ctrl, __u32 ctrl)
+{
+	if (ext_ctrl)
+		return (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >>
+			L2CAP_EXT_CTRL_REQSEQ_SHIFT;
+	else
+		return (ctrl & L2CAP_CTRL_REQSEQ_MASK) >>
+			L2CAP_CTRL_REQSEQ_SHIFT;
+}
+
+static inline __u32 __set_reqseq(__u8 ext_ctrl, __u32 reqseq)
+{
+	if (ext_ctrl)
+		return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
+			L2CAP_EXT_CTRL_REQSEQ_MASK;
+	else
+		return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) &
+			L2CAP_CTRL_REQSEQ_MASK;
+}
+
+static inline __u16 __get_txseq(__u8 ext_ctrl, __u32 ctrl)
+{
+	if (ext_ctrl)
+		return (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
+			L2CAP_EXT_CTRL_TXSEQ_SHIFT;
+	else
+		return (ctrl & L2CAP_CTRL_TXSEQ_MASK) >>
+			L2CAP_CTRL_TXSEQ_SHIFT;
+}
+
+static inline __u32 __set_txseq(__u8 ext_ctrl, __u32 txseq)
+{
+	if (ext_ctrl)
+		return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
+			L2CAP_EXT_CTRL_TXSEQ_MASK;
+	else
+		return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) &
+			L2CAP_CTRL_TXSEQ_MASK;
+}
+
+static inline bool __is_sframe(__u8 ext_ctrl, __u32 ctrl)
+{
+	if (ext_ctrl)
+		return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
+	else
+		return ctrl & L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u32 __set_sframe(__u8 ext_ctrl)
+{
+	if (ext_ctrl)
+		return L2CAP_EXT_CTRL_FRAME_TYPE;
+	else
+		return L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u8 __get_ctrl_sar(__u8 ext_ctrl, __u32 ctrl)
+{
+	if (ext_ctrl)
+		return (ctrl & L2CAP_EXT_CTRL_SAR_MASK) >>
+			L2CAP_EXT_CTRL_SAR_SHIFT;
+	else
+		return (ctrl & L2CAP_CTRL_SAR_MASK) >>
+			L2CAP_CTRL_SAR_SHIFT;
+}
+
+static inline __u32 __set_ctrl_sar(__u8 ext_ctrl, __u32 sar)
+{
+	if (ext_ctrl)
+		return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) &
+			L2CAP_EXT_CTRL_SAR_MASK;
+	else
+		return (sar << L2CAP_CTRL_SAR_SHIFT) &
+			L2CAP_CTRL_SAR_MASK;
+}
+
+static inline bool __is_sar_start(__u8 ext_ctrl, __u32 ctrl)
+{
+	return __get_ctrl_sar(ext_ctrl, ctrl) == L2CAP_SAR_START;
+}
+
+static inline __u32 __get_sar_mask(__u8 ext_ctrl)
+{
+	if (ext_ctrl)
+		return L2CAP_EXT_CTRL_SAR_MASK;
+	else
+		return L2CAP_CTRL_SAR_MASK;
+}
+
+static inline __u8 __get_ctrl_super(__u8 ext_ctrl, __u32 ctrl)
+{
+	if (ext_ctrl)
+		return (ctrl & L2CAP_EXT_CTRL_SUPERVISE_MASK) >>
+			L2CAP_EXT_CTRL_SUPER_SHIFT;
+	else
+		return (ctrl & L2CAP_CTRL_SUPERVISE_MASK) >>
+			L2CAP_CTRL_SUPER_SHIFT;
+}
+
+static inline __u32 __set_ctrl_super(__u8 ext_ctrl, __u32 super)
+{
+	if (ext_ctrl)
+		return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
+			L2CAP_EXT_CTRL_SUPERVISE_MASK;
+	else
+		return (super << L2CAP_CTRL_SUPER_SHIFT) &
+			L2CAP_CTRL_SUPERVISE_MASK;
+}
+
+static inline __u32 __set_ctrl_final(__u8 ext_ctrl)
+{
+	if (ext_ctrl)
+		return L2CAP_EXT_CTRL_FINAL;
+	else
+		return L2CAP_CTRL_FINAL;
+}
+
+static inline bool __is_ctrl_final(__u8 ext_ctrl, __u32 ctrl)
+{
+	if (ext_ctrl)
+		return ctrl & L2CAP_EXT_CTRL_FINAL;
+	else
+		return ctrl & L2CAP_CTRL_FINAL;
+}
+
+static inline __u32 __set_ctrl_poll(__u8 ext_ctrl)
+{
+	if (ext_ctrl)
+		return L2CAP_EXT_CTRL_POLL;
+	else
+		return L2CAP_CTRL_POLL;
+}
+
+static inline bool __is_ctrl_poll(__u8 ext_ctrl, __u32 ctrl)
+{
+	if (ext_ctrl)
+		return ctrl & L2CAP_EXT_CTRL_POLL;
+	else
+		return ctrl & L2CAP_CTRL_POLL;
+}
+
+static inline __u32 __get_control(__u8 ext_ctrl, void *p)
+{
+	if (ext_ctrl)
+		return get_unaligned_le32(p);
+	else
+		return get_unaligned_le16(p);
+}
+
+static inline __u32 __get_control_pull(__u8 ext_ctrl,
+		struct sk_buff *skb, void *p)
+{
+	__u32 ctrl;
+
+	if (ext_ctrl) {
+		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(__u8 ext_ctrl, __u32 control, void *p)
+{
+	if (ext_ctrl)
+		return put_unaligned_le32(control, p);
+	else
+		return put_unaligned_le16(control, p);
+}
+
+static inline void __put_control_put(__u8 ext_ctrl, __u32 control, void *p)
+{
+	if (ext_ctrl)
+		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 0d62b05..820a2b0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -582,30 +582,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 (chan->ext_ctrl)
+		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->ext_ctrl);
 
 	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-		control |= L2CAP_CTRL_FINAL;
+		control |= __set_ctrl_final(chan->ext_ctrl);
 
 	if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
-		control |= L2CAP_CTRL_POLL;
+		control |= __set_ctrl_poll(chan->ext_ctrl);
 
 	skb = bt_skb_alloc(count, GFP_ATOMIC);
 	if (!skb)
@@ -614,7 +620,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->ext_ctrl, control, skb);
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
 		u16 fcs = crc16(0, (u8 *)lh, count - 2);
@@ -631,15 +638,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->ext_ctrl, L2CAP_SUPER_RNR);
 		set_bit(CONN_RNR_SENT, &chan->conn_state);
 	} else
-		control |= L2CAP_SUPER_RCV_READY;
+		control |= __set_ctrl_super(chan->ext_ctrl, L2CAP_SUPER_RR);
 
-	control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= __set_reqseq(chan->ext_ctrl, chan->buffer_seq);
 
 	l2cap_send_sframe(chan, control);
 }
@@ -1281,12 +1288,15 @@ 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->ext_ctrl,
+				skb->data + L2CAP_HDR_SIZE);
+		control |= __set_txseq(chan->ext_ctrl, chan->next_tx_seq);
+		__put_control(chan->ext_ctrl, control,
+				skb->data + L2CAP_HDR_SIZE);
 
 		if (chan->fcs == L2CAP_FCS_CRC16) {
 			fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
@@ -1299,10 +1309,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)
@@ -1325,16 +1336,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->ext_ctrl, tx_skb->data + L2CAP_HDR_SIZE);
+	control &= __get_sar_mask(chan->ext_ctrl);
 
 	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-		control |= L2CAP_CTRL_FINAL;
+		control |= __set_ctrl_final(chan->ext_ctrl);
 
-	control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-			| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+	control |= __set_reqseq(chan->ext_ctrl, chan->buffer_seq);
+	control |= __set_txseq(chan->ext_ctrl, tx_seq);
 
-	put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+	__put_control(chan->ext_ctrl, control, tx_skb->data + L2CAP_HDR_SIZE);
 
 	if (chan->fcs == L2CAP_FCS_CRC16) {
 		fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
@@ -1347,7 +1359,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)
@@ -1365,16 +1378,18 @@ 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->ext_ctrl,
+				tx_skb->data + L2CAP_HDR_SIZE);
+		control &= __get_sar_mask(chan->ext_ctrl);
 
 		if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-			control |= L2CAP_CTRL_FINAL;
+			control |= __set_ctrl_final(chan->ext_ctrl);
 
-		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->ext_ctrl, chan->buffer_seq);
+		control |= __set_txseq(chan->ext_ctrl, chan->next_tx_seq);
 
+		__put_control(chan->ext_ctrl, control,
+				tx_skb->data + L2CAP_HDR_SIZE);
 
 		if (chan->fcs == L2CAP_FCS_CRC16) {
 			fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
@@ -1418,12 +1433,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->ext_ctrl, chan->buffer_seq);
 
 	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		control |= L2CAP_SUPER_RCV_NOT_READY;
+		control |= __set_ctrl_super(chan->ext_ctrl, L2CAP_SUPER_RNR);
 		set_bit(CONN_RNR_SENT, &chan->conn_state);
 		l2cap_send_sframe(chan, control);
 		return;
@@ -1432,20 +1447,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->ext_ctrl, 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->ext_ctrl, L2CAP_SUPER_SREJ);
+	control |= __set_ctrl_final(chan->ext_ctrl);
 
 	tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
-	control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= __set_reqseq(chan->ext_ctrl, tail->tx_seq);
 
 	l2cap_send_sframe(chan, control);
 }
@@ -1541,12 +1556,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);
@@ -1554,6 +1569,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 	if (!conn)
 		return ERR_PTR(-ENOTCONN);
 
+	if (chan->ext_ctrl)
+		hlen = L2CAP_EXTENDED_HDR_SIZE;
+	else
+		hlen = L2CAP_ENHANCED_HDR_SIZE;
+
 	if (sdulen)
 		hlen += 2;
 
@@ -1570,7 +1590,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->ext_ctrl, control, skb);
+
 	if (sdulen)
 		put_unaligned_le16(sdulen, skb_put(skb, 2));
 
@@ -1591,11 +1613,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->ext_ctrl, L2CAP_SAR_START);
 	skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
@@ -1608,10 +1630,12 @@ 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->ext_ctrl,
+					L2CAP_SAR_CONTINUE);
 			buflen = chan->remote_mps;
 		} else {
-			control = L2CAP_SDU_END;
+			control = __set_ctrl_sar(chan->ext_ctrl,
+					L2CAP_SAR_END);
 			buflen = len;
 		}
 
@@ -1635,7 +1659,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 */
@@ -1667,7 +1691,8 @@ 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->ext_ctrl,
+					L2CAP_SAR_UNSEGMENTED);
 			skb = l2cap_create_iframe_pdu(chan, msg, len, control,
 									0);
 			if (IS_ERR(skb))
@@ -2007,8 +2032,11 @@ done:
 			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
 
 		l2cap_txwin_setup(chan);
-		rfc.txwin_size = chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW?
-			L2CAP_DEFAULT_MAX_TX_WINDOW : chan->tx_win;
+
+		if (chan->ext_ctrl)
+			rfc.txwin_size = L2CAP_DEFAULT_MAX_TX_WINDOW;
+		else
+			rfc.txwin_size = chan->tx_win;
 
 		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
 							(unsigned long) &rfc);
@@ -3298,7 +3326,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 (chan->ext_ctrl)
+		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);
@@ -3313,14 +3346,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->ext_ctrl, chan->buffer_seq);
 
 	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-		control |= L2CAP_SUPER_RCV_NOT_READY;
+		control |= __set_ctrl_super(chan->ext_ctrl, L2CAP_SUPER_RNR);
 		l2cap_send_sframe(chan, control);
 		set_bit(CONN_RNR_SENT, &chan->conn_state);
 	}
@@ -3332,12 +3365,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->ext_ctrl, 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;
@@ -3398,19 +3431,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->ext_ctrl, 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;
 
@@ -3432,7 +3465,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;
 
@@ -3446,7 +3479,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;
 
@@ -3481,14 +3514,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->ext_ctrl, chan->buffer_seq);
+	control |= __set_ctrl_super(chan->ext_ctrl, L2CAP_SUPER_RNR);
 	l2cap_send_sframe(chan, control);
 
 	set_bit(CONN_RNR_SENT, &chan->conn_state);
@@ -3498,13 +3531,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->ext_ctrl, chan->buffer_seq);
+	control |= __set_ctrl_super(chan->ext_ctrl, L2CAP_SUPER_RR);
+	control |= __set_ctrl_poll(chan->ext_ctrl);
 	l2cap_send_sframe(chan, control);
 	chan->retry_count = 1;
 
@@ -3530,10 +3564,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)) {
@@ -3543,7 +3577,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->ext_ctrl, bt_cb(skb)->sar);
 		err = l2cap_reassemble_sdu(chan, skb, control);
 
 		if (err < 0) {
@@ -3557,10 +3591,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) {
@@ -3568,22 +3602,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->ext_ctrl, L2CAP_SUPER_SREJ);
+		control |= __set_reqseq(chan->ext_ctrl, 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->ext_ctrl, L2CAP_SUPER_SREJ);
+		control |= __set_reqseq(chan->ext_ctrl, chan->expected_tx_seq);
 		l2cap_send_sframe(chan, control);
 
 		new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
@@ -3594,19 +3628,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->ext_ctrl, rx_control);
+	u16 req_seq = __get_reqseq(chan->ext_ctrl, rx_control);
+	u8 sar = __get_ctrl_sar(chan->ext_ctrl, 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->ext_ctrl, rx_control) &&
 			test_bit(CONN_WAIT_F, &chan->conn_state)) {
 		__clear_monitor_timer(chan);
 		if (chan->unacked_frames > 0)
@@ -3711,7 +3745,7 @@ expected:
 		return err;
 	}
 
-	if (rx_control & L2CAP_CTRL_FINAL) {
+	if (__is_ctrl_final(chan->ext_ctrl, rx_control)) {
 		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
 			l2cap_retransmit_frames(chan);
 	}
@@ -3729,15 +3763,16 @@ 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->ext_ctrl, rx_control),
+			rx_control);
 
-	chan->expected_ack_seq = __get_reqseq(rx_control);
+	chan->expected_ack_seq = __get_reqseq(chan->ext_ctrl, rx_control);
 	l2cap_drop_acked_frames(chan);
 
-	if (rx_control & L2CAP_CTRL_POLL) {
+	if (__is_ctrl_poll(chan->ext_ctrl, 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) &&
@@ -3750,7 +3785,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->ext_ctrl, rx_control)) {
 		clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
 		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
@@ -3769,9 +3804,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->ext_ctrl, rx_control);
 
 	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
 
@@ -3780,7 +3815,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->ext_ctrl, rx_control)) {
 		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
 			l2cap_retransmit_frames(chan);
 	} else {
@@ -3790,15 +3825,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->ext_ctrl, 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->ext_ctrl, rx_control)) {
 		chan->expected_ack_seq = tx_seq;
 		l2cap_drop_acked_frames(chan);
 
@@ -3811,7 +3846,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->ext_ctrl, 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);
@@ -3826,37 +3861,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->ext_ctrl, 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->ext_ctrl, 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->ext_ctrl, rx_control))
 			l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
 		return;
 	}
 
-	if (rx_control & L2CAP_CTRL_POLL)
+	if (__is_ctrl_poll(chan->ext_ctrl, rx_control))
 		l2cap_send_srejtail(chan);
-	else
-		l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
+	else {
+		rx_control = __set_ctrl_super(chan->ext_ctrl, 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->ext_ctrl, rx_control) &&
 			test_bit(CONN_WAIT_F, &chan->conn_state)) {
 		__clear_monitor_timer(chan);
 		if (chan->unacked_frames > 0)
@@ -3864,20 +3901,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->ext_ctrl, 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;
 	}
@@ -3889,12 +3926,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->ext_ctrl, skb, skb->data);
 	len = skb->len;
 
 	/*
@@ -3905,8 +3941,9 @@ 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->ext_ctrl, control) &&
+			!__is_sframe(chan->ext_ctrl, control))
+		len -= L2CAP_SDULEN_SIZE;
 
 	if (chan->fcs == L2CAP_FCS_CRC16)
 		len -= 2;
@@ -3916,7 +3953,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->ext_ctrl, control);
 	req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
 	if (req_seq_offset < 0)
 		req_seq_offset += 64;
@@ -3932,7 +3969,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 		goto drop;
 	}
 
-	if (__is_iframe(control)) {
+	if (!__is_sframe(chan->ext_ctrl, control)) {
 		if (len < 0) {
 			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 			goto drop;
@@ -3960,8 +3997,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);
@@ -4002,23 +4039,23 @@ 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->ext_ctrl, 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->ext_ctrl, 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->ext_ctrl,
+					control))
 			goto drop;
 
-		tx_seq = __get_txseq(control);
+		tx_seq = __get_txseq(chan->ext_ctrl, 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] 10+ messages in thread

* [RFCv0 3/5] Bluetooth: EWS: support extended seq numbers
  2011-08-30  7:18 [RFCv0 0/5] extended window size and extended control field support Emeltchenko Andrei
  2011-08-30  7:18 ` [RFCv0 1/5] Bluetooth: extended window size option support Emeltchenko Andrei
  2011-08-30  7:18 ` [RFCv0 2/5] Bluetooth: l2cap extended control field support Emeltchenko Andrei
@ 2011-08-30  7:18 ` Emeltchenko Andrei
  2011-08-30  7:18 ` [RFCv0 4/5] Bluetooth: remove magic numbers in l2cap Emeltchenko Andrei
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Emeltchenko Andrei @ 2011-08-30  7:18 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/l2cap.h |   17 +++++++++++
 net/bluetooth/l2cap_core.c    |   63 +++++++++++++++++++---------------------
 net/bluetooth/l2cap_sock.c    |    1 +
 3 files changed, 48 insertions(+), 33 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index e2906c8..97df6a0 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;
@@ -548,6 +549,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 820a2b0..7e67f9b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1305,7 +1305,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);
 	}
 }
 
@@ -1401,7 +1401,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++;
@@ -1954,13 +1955,16 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
 			__l2cap_ews_supported(chan)) {
 		/* use extended control field */
 		chan->ext_ctrl = 1;
+		chan->tx_win_max = L2CAP_DEFAULT_MAX_EXT_WINDOW;
+
 		if (chan->tx_win > L2CAP_DEFAULT_MAX_EXT_WINDOW)
 			chan->tx_win = L2CAP_DEFAULT_MAX_EXT_WINDOW;
 	} else {
+		chan->ext_ctrl = 0;
+		chan->tx_win_max = L2CAP_DEFAULT_MAX_TX_WINDOW;
+
 		if (chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW)
 			chan->tx_win = L2CAP_DEFAULT_MAX_TX_WINDOW;
-
-		chan->ext_ctrl = 0;
 	}
 }
 
@@ -2185,6 +2189,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 		case L2CAP_CONF_EWS:
 			chan->ext_ctrl = 1;
 			chan->remote_tx_win = val;
+			chan->tx_win_max = L2CAP_DEFAULT_MAX_EXT_WINDOW;
 			set_bit(CONF_EWS_RECV, &chan->conf_state);
 			break;
 
@@ -3384,18 +3389,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);
@@ -3585,9 +3586,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);
 	}
 }
 
@@ -3622,10 +3622,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)
@@ -3651,9 +3654,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) {
@@ -3701,10 +3702,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)
@@ -3729,7 +3728,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;
@@ -3739,7 +3738,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;
@@ -3954,14 +3954,11 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 	}
 
 	req_seq = __get_reqseq(chan->ext_ctrl, 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) {
@@ -4067,7 +4064,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);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index d6a4f63..bf343aa 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -969,6 +969,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 
 	/* Default config options */
 	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+	chan->tx_win_max = L2CAP_DEFAULT_MAX_TX_WINDOW;
 
 	chan->data = sk;
 	chan->ops = &l2cap_chan_ops;
-- 
1.7.4.1


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

* [RFCv0 4/5] Bluetooth: remove magic numbers in l2cap
  2011-08-30  7:18 [RFCv0 0/5] extended window size and extended control field support Emeltchenko Andrei
                   ` (2 preceding siblings ...)
  2011-08-30  7:18 ` [RFCv0 3/5] Bluetooth: EWS: support extended seq numbers Emeltchenko Andrei
@ 2011-08-30  7:18 ` Emeltchenko Andrei
  2011-08-30  7:18 ` [RFCv0 5/5] Bluetooth: prevent unneeded fragmentation " Emeltchenko Andrei
  2011-08-30 16:10 ` [RFCv0 0/5] extended window size and extended control field support Mat Martineau
  5 siblings, 0 replies; 10+ messages in thread
From: Emeltchenko Andrei @ 2011-08-30  7:18 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 7e67f9b..274b60c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -599,7 +599,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);
 
@@ -624,8 +624,8 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
 	__put_control_put(chan->ext_ctrl, 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))
@@ -1299,8 +1299,10 @@ static void l2cap_streaming_send(struct l2cap_chan *chan)
 				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);
@@ -1349,8 +1351,10 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
 	__put_control(chan->ext_ctrl, 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);
@@ -1392,8 +1396,10 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 				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);
@@ -1576,10 +1582,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,
@@ -1595,7 +1601,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 	__put_control_put(chan->ext_ctrl, 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)) {
@@ -1604,7 +1610,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;
@@ -3339,7 +3345,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);
 
@@ -3449,7 +3455,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;
@@ -3946,7 +3952,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);
@@ -4046,7 +4052,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->ext_ctrl,
 					control))
-- 
1.7.4.1


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

* [RFCv0 5/5] Bluetooth: prevent unneeded fragmentation in l2cap
  2011-08-30  7:18 [RFCv0 0/5] extended window size and extended control field support Emeltchenko Andrei
                   ` (3 preceding siblings ...)
  2011-08-30  7:18 ` [RFCv0 4/5] Bluetooth: remove magic numbers in l2cap Emeltchenko Andrei
@ 2011-08-30  7:18 ` Emeltchenko Andrei
  2011-08-30 16:10 ` [RFCv0 0/5] extended window size and extended control field support Mat Martineau
  5 siblings, 0 replies; 10+ messages in thread
From: Emeltchenko Andrei @ 2011-08-30  7:18 UTC (permalink / raw)
  To: linux-bluetooth

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

Calculate pdu length before creating I-frame. Otherwise if
conn->mtu - (headers) < remote_mps we get fragmented packets in
create_iframe_pdu function.

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

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 274b60c..4bb70d2 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1571,8 +1571,6 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 	int err, count, hlen;
 	struct l2cap_hdr *lh;
 
-	BT_DBG("sk %p len %d", sk, (int)len);
-
 	if (!conn)
 		return ERR_PTR(-ENOTCONN);
 
@@ -1587,6 +1585,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m
 	if (chan->fcs == L2CAP_FCS_CRC16)
 		hlen += L2CAP_FCS_SIZE;
 
+	BT_DBG("sk %p, msg %p, len %d, sdulen %d, hlen %d",
+		sk, msg, (int)len, (int)sdulen, hlen);
+
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
 	skb = bt_skb_send_alloc(sk, count + hlen,
 			msg->msg_flags & MSG_DONTWAIT, &err);
@@ -1622,24 +1623,30 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
 	struct sk_buff_head sar_queue;
 	u32 control;
 	size_t size = 0;
+	size_t pdu_len;
 
 	skb_queue_head_init(&sar_queue);
 	control = __set_ctrl_sar(chan->ext_ctrl, L2CAP_SAR_START);
-	skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
+
+	pdu_len = chan->conn->mtu;
+	pdu_len -= L2CAP_EXTENDED_HDR_SIZE + L2CAP_FCS_SIZE + L2CAP_SDULEN_SIZE;
+	pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
+
+	skb = l2cap_create_iframe_pdu(chan, msg, pdu_len, control, len);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
 
 	__skb_queue_tail(&sar_queue, skb);
-	len -= chan->remote_mps;
-	size += chan->remote_mps;
+	len -= pdu_len;
+	size += pdu_len;
 
 	while (len > 0) {
 		size_t buflen;
 
-		if (len > chan->remote_mps) {
+		if (len > pdu_len) {
 			control = __set_ctrl_sar(chan->ext_ctrl,
 					L2CAP_SAR_CONTINUE);
-			buflen = chan->remote_mps;
+			buflen = pdu_len;
 		} else {
 			control = __set_ctrl_sar(chan->ext_ctrl,
 					L2CAP_SAR_END);
@@ -3349,8 +3356,10 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 		rcv_fcs = get_unaligned_le16(skb->data + skb->len);
 		our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
 
-		if (our_fcs != rcv_fcs)
+		if (our_fcs != rcv_fcs) {
+			BT_DBG("FCS check failed");
 			return -EBADMSG;
+		}
 	}
 	return 0;
 }
-- 
1.7.4.1


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

* Re: [RFCv0 0/5] extended window size and extended control field support
  2011-08-30  7:18 [RFCv0 0/5] extended window size and extended control field support Emeltchenko Andrei
                   ` (4 preceding siblings ...)
  2011-08-30  7:18 ` [RFCv0 5/5] Bluetooth: prevent unneeded fragmentation " Emeltchenko Andrei
@ 2011-08-30 16:10 ` Mat Martineau
  2011-08-30 18:18   ` Marcel Holtmann
  2011-08-30 21:06   ` Andrei Emeltchenko
  5 siblings, 2 replies; 10+ messages in thread
From: Mat Martineau @ 2011-08-30 16:10 UTC (permalink / raw)
  To: Emeltchenko Andrei; +Cc: linux-bluetooth, pkrystad, padovan


Hi Andrei -

On Tue, 30 Aug 2011, Emeltchenko Andrei wrote:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> First draft patches applied to my previous EFS patches. Please comment.
>
> Adds support for extended window size option (EWS) and extended control
> field. Code partly based on Atheros patches sent a year ago 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.
>
> Andrei Emeltchenko (5):
>  Bluetooth: extended window size option support
>  Bluetooth: l2cap extended control field support
>  Bluetooth: EWS: support extended seq numbers
>  Bluetooth: remove magic numbers in l2cap
>  Bluetooth: prevent unneeded fragmentation in l2cap
>
> include/net/bluetooth/l2cap.h |  304 ++++++++++++++++++++++----
> net/bluetooth/l2cap_core.c    |  481 +++++++++++++++++++++++++----------------
> net/bluetooth/l2cap_sock.c    |   11 +-
> 3 files changed, 562 insertions(+), 234 deletions(-)
>
> -- 
> 1.7.4.1

Extended window size is next on my list to upstream.  As you probably 
noticed, the git://codeaurora.org/kernel/msm.git code has a slightly 
different approach to handling the two control field types.  The 
fields are handled in a struct that's part of the bt_cb control block, 
and only read/written in wire format when the frame is first received 
or about to be sent.  Are there any issues with this method (other 
than the fact that I haven't upstreamed it yet)?  Some of the 
subsequent L2CAP state machine changes depend on this.

Please let me know if there are specific features from the 
git://codeaurora.org/kernel/msm.git code base that you would like to 
prioritize for upstreaming - there's a lot to do to bring in those 
L2CAP and AMP changes, and I'll have more time to devote to it in 
mid-September.  I think we can gain a lot by reviewing each other's 
patches and coordinating our efforts.

Regards,

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [RFCv0 0/5] extended window size and extended control field support
  2011-08-30 16:10 ` [RFCv0 0/5] extended window size and extended control field support Mat Martineau
@ 2011-08-30 18:18   ` Marcel Holtmann
  2011-08-31 17:53     ` Mat Martineau
  2011-08-30 21:06   ` Andrei Emeltchenko
  1 sibling, 1 reply; 10+ messages in thread
From: Marcel Holtmann @ 2011-08-30 18:18 UTC (permalink / raw)
  To: Mat Martineau; +Cc: Emeltchenko Andrei, linux-bluetooth, pkrystad, padovan

Hi Mat,

> > First draft patches applied to my previous EFS patches. Please comment.
> >
> > Adds support for extended window size option (EWS) and extended control
> > field. Code partly based on Atheros patches sent a year ago 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.
> >
> > Andrei Emeltchenko (5):
> >  Bluetooth: extended window size option support
> >  Bluetooth: l2cap extended control field support
> >  Bluetooth: EWS: support extended seq numbers
> >  Bluetooth: remove magic numbers in l2cap
> >  Bluetooth: prevent unneeded fragmentation in l2cap
> >
> > include/net/bluetooth/l2cap.h |  304 ++++++++++++++++++++++----
> > net/bluetooth/l2cap_core.c    |  481 +++++++++++++++++++++++++----------------
> > net/bluetooth/l2cap_sock.c    |   11 +-
> > 3 files changed, 562 insertions(+), 234 deletions(-)
> >
> > -- 
> > 1.7.4.1
> 
> Extended window size is next on my list to upstream.  As you probably 
> noticed, the git://codeaurora.org/kernel/msm.git code has a slightly 
> different approach to handling the two control field types.  The 
> fields are handled in a struct that's part of the bt_cb control block, 
> and only read/written in wire format when the frame is first received 
> or about to be sent.  Are there any issues with this method (other 
> than the fact that I haven't upstreamed it yet)?  Some of the 
> subsequent L2CAP state machine changes depend on this.

in general using bt_cb is fine, but it depends a little bit on the
details. The space of the skb cb is limited. So we need to be cautious
here.

We are also currently making bt_cb global for all protocols. Maybe one
way is to have l2cap_cb for this. We need to see what makes more sense
and what is more efficient.

> Please let me know if there are specific features from the 
> git://codeaurora.org/kernel/msm.git code base that you would like to 
> prioritize for upstreaming - there's a lot to do to bring in those 
> L2CAP and AMP changes, and I'll have more time to devote to it in 
> mid-September.  I think we can gain a lot by reviewing each other's 
> patches and coordinating our efforts.

Maybe just for reference, you should post a set of patches to the
mailing list so they are archived and seen by others. Digging into a
generic msm.git tree is not really efficient.

Regards

Marcel



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

* Re: [RFCv0 0/5] extended window size and extended control field support
  2011-08-30 16:10 ` [RFCv0 0/5] extended window size and extended control field support Mat Martineau
  2011-08-30 18:18   ` Marcel Holtmann
@ 2011-08-30 21:06   ` Andrei Emeltchenko
  1 sibling, 0 replies; 10+ messages in thread
From: Andrei Emeltchenko @ 2011-08-30 21:06 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, pkrystad, padovan

Hi Mat

On Tue, Aug 30, 2011 at 7:10 PM, Mat Martineau <mathewm@codeaurora.org> wrote:
>
> Hi Andrei -
>
> On Tue, 30 Aug 2011, Emeltchenko Andrei wrote:
>
>> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>>
>> First draft patches applied to my previous EFS patches. Please comment.
>>
>> Adds support for extended window size option (EWS) and extended control
>> field. Code partly based on Atheros patches sent a year ago 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.
>>
>> Andrei Emeltchenko (5):
>>  Bluetooth: extended window size option support
>>  Bluetooth: l2cap extended control field support
>>  Bluetooth: EWS: support extended seq numbers
>>  Bluetooth: remove magic numbers in l2cap
>>  Bluetooth: prevent unneeded fragmentation in l2cap
>>
>> include/net/bluetooth/l2cap.h |  304 ++++++++++++++++++++++----
>> net/bluetooth/l2cap_core.c    |  481
>> +++++++++++++++++++++++++----------------
>> net/bluetooth/l2cap_sock.c    |   11 +-
>> 3 files changed, 562 insertions(+), 234 deletions(-)
>>
>> --
>> 1.7.4.1
>
> Extended window size is next on my list to upstream.  As you probably
> noticed, the git://codeaurora.org/kernel/msm.git code has a slightly
> different approach to handling the two control field types.  The fields are
> handled in a struct that's part of the bt_cb control block, and only
> read/written in wire format when the frame is first received or about to be
> sent.  Are there any issues with this method (other than the fact that I
> haven't upstreamed it yet)?  Some of the subsequent L2CAP state machine
> changes depend on this.

AFAIK this was discussed about one year ago:
http://www.spinics.net/lists/linux-arm-msm/msg01022.html

> Please let me know if there are specific features from the
> git://codeaurora.org/kernel/msm.git code base that you would like to
> prioritize for upstreaming - there's a lot to do to bring in those L2CAP and
> AMP changes, and I'll have more time to devote to it in mid-September.  I
> think we can gain a lot by reviewing each other's patches and coordinating
> our efforts.

I think the same. We will come up with our priority list soon.

Regards,
Andrei

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

* Re: [RFCv0 0/5] extended window size and extended control field support
  2011-08-30 18:18   ` Marcel Holtmann
@ 2011-08-31 17:53     ` Mat Martineau
  0 siblings, 0 replies; 10+ messages in thread
From: Mat Martineau @ 2011-08-31 17:53 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: Emeltchenko Andrei, linux-bluetooth, pkrystad, padovan


On Tue, 30 Aug 2011, Marcel Holtmann wrote:

> Hi Mat,
>
>>> First draft patches applied to my previous EFS patches. Please comment.
>>>
>>> Adds support for extended window size option (EWS) and extended control
>>> field. Code partly based on Atheros patches sent a year ago 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.
>>>
>>> Andrei Emeltchenko (5):
>>>  Bluetooth: extended window size option support
>>>  Bluetooth: l2cap extended control field support
>>>  Bluetooth: EWS: support extended seq numbers
>>>  Bluetooth: remove magic numbers in l2cap
>>>  Bluetooth: prevent unneeded fragmentation in l2cap
>>>
>>> include/net/bluetooth/l2cap.h |  304 ++++++++++++++++++++++----
>>> net/bluetooth/l2cap_core.c    |  481 +++++++++++++++++++++++++----------------
>>> net/bluetooth/l2cap_sock.c    |   11 +-
>>> 3 files changed, 562 insertions(+), 234 deletions(-)
>>>
>>> --
>>> 1.7.4.1
>>
>> Extended window size is next on my list to upstream.  As you probably
>> noticed, the git://codeaurora.org/kernel/msm.git code has a slightly
>> different approach to handling the two control field types.  The
>> fields are handled in a struct that's part of the bt_cb control block,
>> and only read/written in wire format when the frame is first received
>> or about to be sent.  Are there any issues with this method (other
>> than the fact that I haven't upstreamed it yet)?  Some of the
>> subsequent L2CAP state machine changes depend on this.
>
> in general using bt_cb is fine, but it depends a little bit on the
> details. The space of the skb cb is limited. So we need to be cautious
> here.

Yes, I've been keeping that limited space in mind.  Some of the data 
already in bt_cb was control field data, so I removed the redundant 
entries.

> We are also currently making bt_cb global for all protocols. Maybe one
> way is to have l2cap_cb for this. We need to see what makes more sense
> and what is more efficient.
>
>> Please let me know if there are specific features from the
>> git://codeaurora.org/kernel/msm.git code base that you would like to
>> prioritize for upstreaming - there's a lot to do to bring in those
>> L2CAP and AMP changes, and I'll have more time to devote to it in
>> mid-September.  I think we can gain a lot by reviewing each other's
>> patches and coordinating our efforts.
>
> Maybe just for reference, you should post a set of patches to the
> mailing list so they are archived and seen by others. Digging into a
> generic msm.git tree is not really efficient.

I'll take a look at that - I'd have to split up the commits in that 
git repository in order for them to be suitable for the mailing list.


--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

end of thread, other threads:[~2011-08-31 17:53 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-30  7:18 [RFCv0 0/5] extended window size and extended control field support Emeltchenko Andrei
2011-08-30  7:18 ` [RFCv0 1/5] Bluetooth: extended window size option support Emeltchenko Andrei
2011-08-30  7:18 ` [RFCv0 2/5] Bluetooth: l2cap extended control field support Emeltchenko Andrei
2011-08-30  7:18 ` [RFCv0 3/5] Bluetooth: EWS: support extended seq numbers Emeltchenko Andrei
2011-08-30  7:18 ` [RFCv0 4/5] Bluetooth: remove magic numbers in l2cap Emeltchenko Andrei
2011-08-30  7:18 ` [RFCv0 5/5] Bluetooth: prevent unneeded fragmentation " Emeltchenko Andrei
2011-08-30 16:10 ` [RFCv0 0/5] extended window size and extended control field support Mat Martineau
2011-08-30 18:18   ` Marcel Holtmann
2011-08-31 17:53     ` Mat Martineau
2011-08-30 21:06   ` Andrei Emeltchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox