* [PATCHv3 01/16] Bluetooth: clean up spaces in L2CAP header
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 02/16] Bluetooth: EWS: extended window size option support Emeltchenko Andrei
` (14 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Spaces converted to tabs
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 17 ++++++++---------
1 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index aea083c..08ad40b 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -134,10 +134,9 @@ struct l2cap_conninfo {
#define L2CAP_SDU_CONTINUE 0xC000
/* 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 {
@@ -273,13 +272,13 @@ struct l2cap_info_rsp {
} __packed;
/* info type */
-#define L2CAP_IT_CL_MTU 0x0001
-#define L2CAP_IT_FEAT_MASK 0x0002
-#define L2CAP_IT_FIXED_CHAN 0x0003
+#define L2CAP_IT_CL_MTU 0x0001
+#define L2CAP_IT_FEAT_MASK 0x0002
+#define L2CAP_IT_FIXED_CHAN 0x0003
/* info result */
-#define L2CAP_IR_SUCCESS 0x0000
-#define L2CAP_IR_NOTSUPP 0x0001
+#define L2CAP_IR_SUCCESS 0x0000
+#define L2CAP_IR_NOTSUPP 0x0001
struct l2cap_conn_param_update_req {
__le16 min;
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 02/16] Bluetooth: EWS: extended window size option support
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 01/16] Bluetooth: clean up spaces in L2CAP header Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 03/16] Bluetooth: EWS: adds ext control field bit mask Emeltchenko Andrei
` (13 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Adds support for extended window size (EWS) config option. We enable EWS
feature in L2CAP Info RSP when hs enabled. EWS option is included in L2CAP
Config Req if tx_win (which is set via socket) bigger then standard default
value (63) && hs enabled && remote side supports EWS feature.
Using EWS selects extended control field in L2CAP.
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 | 8 +++++-
net/bluetooth/l2cap_core.c | 51 ++++++++++++++++++++++++++++++++++++++--
net/bluetooth/l2cap_sock.c | 8 +++---
3 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 08ad40b..51998ff 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -32,6 +32,7 @@
#define L2CAP_DEFAULT_MIN_MTU 48
#define L2CAP_DEFAULT_FLUSH_TO 0xffff
#define L2CAP_DEFAULT_TX_WINDOW 63
+#define L2CAP_DEFAULT_EXT_WINDOW 0x3FFF
#define L2CAP_DEFAULT_MAX_TX 3
#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
@@ -233,6 +234,7 @@ struct l2cap_conf_opt {
#define L2CAP_CONF_QOS 0x03
#define L2CAP_CONF_RFC 0x04
#define L2CAP_CONF_FCS 0x05
+#define L2CAP_CONF_EWS 0x07
#define L2CAP_CONF_MAX_SIZE 22
@@ -333,7 +335,7 @@ struct l2cap_chan {
__u8 fcs;
- __u8 tx_win;
+ __u16 tx_win;
__u8 max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
@@ -357,7 +359,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;
@@ -442,6 +444,7 @@ enum {
CONF_CONNECT_PEND,
CONF_NO_FCS_RECV,
CONF_STATE2_DEVICE,
+ CONF_EWS_RECV,
};
#define L2CAP_CONF_MAX_CONF_REQ 2
@@ -465,6 +468,7 @@ enum {
FLAG_FORCE_ACTIVE,
FLAG_FORCE_RELIABLE,
FLAG_FLUSHABLE,
+ 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 18a08c5..6e34312 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1898,6 +1898,22 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
}
}
+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_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_TX_WINDOW);
+}
+
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
{
struct l2cap_conf_req *req = data;
@@ -1944,7 +1960,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;
@@ -1952,6 +1967,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_TX_WINDOW);
+
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
(unsigned long) &rfc);
@@ -1963,6 +1983,10 @@ done:
chan->fcs = L2CAP_FCS_NONE;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
}
+
+ if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+ chan->tx_win);
break;
case L2CAP_MODE_STREAMING:
@@ -2038,6 +2062,15 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
break;
+ case L2CAP_CONF_EWS:
+ if (!enable_hs)
+ return -ECONNREFUSED;
+
+ set_bit(FLAG_EXT_CTRL, &chan->flags);
+ set_bit(CONF_EWS_RECV, &chan->conf_state);
+ chan->remote_tx_win = val;
+ break;
+
default:
if (hint)
break;
@@ -2098,7 +2131,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_TX_WINDOW;
+
chan->remote_max_tx = rfc.max_transmit;
if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
@@ -2190,6 +2227,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
sizeof(rfc), (unsigned long) &rfc);
break;
+
+ case L2CAP_CONF_EWS:
+ chan->tx_win = min_t(u16, val,
+ L2CAP_DEFAULT_EXT_WINDOW);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS,
+ 2, chan->tx_win);
+ break;
}
}
@@ -2785,7 +2829,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 aa2f2f0..4b388b7 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))
@@ -501,7 +501,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)) {
@@ -509,7 +509,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_EXT_WINDOW) {
err = -EINVAL;
break;
}
@@ -533,7 +533,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:
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 03/16] Bluetooth: EWS: adds ext control field bit mask
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 01/16] Bluetooth: clean up spaces in L2CAP header Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 02/16] Bluetooth: EWS: extended window size option support Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 04/16] Bluetooth: EWS: rewrite handling Supervisory (S) bits Emeltchenko Andrei
` (12 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Adds extended control field bit masks and rearrange defines to logical
groups: masks, flags and shift groups.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 41 +++++++++++++++++++++++++++++------------
1 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 51998ff..fa7edab 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -109,18 +109,35 @@ 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
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 04/16] Bluetooth: EWS: rewrite handling Supervisory (S) bits
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (2 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 03/16] Bluetooth: EWS: adds ext control field bit mask Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 05/16] Bluetooth: EWS: rewrite handling SAR bits Emeltchenko Andrei
` (11 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Supervisory bits occupy different windows in standard / extended control
fields. Convert hardcoded masks to relative ones and use shift to access
S-bit window.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 27 +++++++++++++++++++++++----
net/bluetooth/l2cap_core.c | 41 ++++++++++++++++++++++-------------------
2 files changed, 45 insertions(+), 23 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index fa7edab..f24f5cf 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -140,10 +140,10 @@ struct l2cap_conninfo {
#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
@@ -518,6 +518,25 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
#define __is_sframe(ctrl) ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
#define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
+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;
+}
+
extern int disable_ertm;
int l2cap_init_sockets(void);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6e34312..93b5da6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -613,10 +613,10 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 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;
@@ -1408,7 +1408,7 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
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;
@@ -1417,7 +1417,7 @@ 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);
}
@@ -1426,7 +1426,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan)
struct srej_list *tail;
u16 control;
- control = L2CAP_SUPER_SELECT_REJECT;
+ control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
control |= L2CAP_CTRL_FINAL;
tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
@@ -3119,7 +3119,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
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);
}
@@ -3131,7 +3131,7 @@ 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);
}
}
@@ -3287,7 +3287,7 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *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_ctrl_super(chan, L2CAP_SUPER_RNR);
l2cap_send_sframe(chan, control);
set_bit(CONN_RNR_SENT, &chan->conn_state);
@@ -3303,7 +3303,8 @@ static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
goto done;
control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
- control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+ control |= L2CAP_CTRL_POLL;
+ control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
l2cap_send_sframe(chan, control);
chan->retry_count = 1;
@@ -3367,7 +3368,7 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
kfree(l);
return;
}
- control = L2CAP_SUPER_SELECT_REJECT;
+ control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
l2cap_send_sframe(chan, control);
list_del(&l->list);
@@ -3381,7 +3382,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
u16 control;
while (tx_seq != chan->expected_tx_seq) {
- control = L2CAP_SUPER_SELECT_REJECT;
+ control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
l2cap_send_sframe(chan, control);
@@ -3645,10 +3646,12 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c
return;
}
- if (rx_control & L2CAP_CTRL_POLL)
+ if (rx_control & L2CAP_CTRL_POLL) {
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)
@@ -3663,20 +3666,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;
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 05/16] Bluetooth: EWS: rewrite handling SAR bits
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (3 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 04/16] Bluetooth: EWS: rewrite handling Supervisory (S) bits Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 06/16] Bluetooth: EWS: rewrite reqseq calculation Emeltchenko Andrei
` (10 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Segmentation and Reassembly (SAR) occupies different windows in standard and
extended control fields. Convert hardcoded masks to relative ones and use shift
to access SAR bits.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 37 ++++++++++++++++++++++++++++++++-----
net/bluetooth/l2cap_core.c | 30 +++++++++++++++---------------
2 files changed, 47 insertions(+), 20 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index f24f5cf..0759ac6 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -146,10 +146,10 @@ struct l2cap_conninfo {
#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
@@ -516,7 +516,34 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
#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 __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)
{
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 93b5da6..9ee42ba 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1311,7 +1311,7 @@ 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_sar_mask(chan);
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
@@ -1351,7 +1351,7 @@ 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_sar_mask(chan);
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
@@ -1582,7 +1582,7 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
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);
@@ -1595,10 +1595,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;
}
@@ -1654,7 +1654,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))
@@ -3201,15 +3201,15 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
{
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;
@@ -3231,7 +3231,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;
@@ -3245,7 +3245,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;
@@ -3343,7 +3343,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) {
@@ -3398,7 +3398,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
{
u8 tx_seq = __get_txseq(rx_control);
u8 req_seq = __get_reqseq(rx_control);
- u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
+ 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;
@@ -3707,7 +3707,7 @@ 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))
+ if (__is_sar_start(chan, control) && __is_iframe(control))
len -= 2;
if (chan->fcs == L2CAP_FCS_CRC16)
@@ -3811,7 +3811,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
if (l2cap_check_fcs(chan, skb))
goto drop;
- if (__is_sar_start(control))
+ if (__is_sar_start(chan, control))
len -= 2;
if (chan->fcs == L2CAP_FCS_CRC16)
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 06/16] Bluetooth: EWS: rewrite reqseq calculation
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (4 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 05/16] Bluetooth: EWS: rewrite handling SAR bits Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 07/16] Bluetooth: EWS: rewrite L2CAP ERTM txseq calculation Emeltchenko Andrei
` (9 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
reqseq calculation uses now information about control field type.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 20 +++++++++++++++++-
net/bluetooth/l2cap_core.c | 42 ++++++++++++++++++++--------------------
2 files changed, 39 insertions(+), 23 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 0759ac6..57b64bb 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -365,11 +365,11 @@ struct l2cap_chan {
__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 buffer_seq;
__u8 retry_count;
__u8 num_acked;
__u16 sdu_len;
@@ -512,8 +512,24 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
return sub == ch->remote_tx_win;
}
+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;
+}
#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)
static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9ee42ba..f35eb73 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -618,7 +618,7 @@ static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
} else
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);
}
@@ -1316,8 +1316,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
- control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
- | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+ control |= __set_reqseq(chan, chan->buffer_seq);
+ control |= tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
@@ -1356,8 +1356,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
- control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
- | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+ control |= __set_reqseq(chan, chan->buffer_seq);
+ control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
@@ -1405,7 +1405,7 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
{
u16 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 |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
@@ -1430,7 +1430,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan)
control |= L2CAP_CTRL_FINAL;
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);
}
@@ -3116,7 +3116,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
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 |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
@@ -3286,7 +3286,7 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
- control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ control = __set_reqseq(chan, chan->buffer_seq);
control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
l2cap_send_sframe(chan, control);
@@ -3302,7 +3302,7 @@ static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
goto done;
- control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ control = __set_reqseq(chan, chan->buffer_seq);
control |= L2CAP_CTRL_POLL;
control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
l2cap_send_sframe(chan, control);
@@ -3369,7 +3369,7 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
return;
}
control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
- control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ control |= __set_reqseq(chan, l->tx_seq);
l2cap_send_sframe(chan, control);
list_del(&l->list);
list_add_tail(&l->list, &chan->srej_l);
@@ -3383,7 +3383,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
while (tx_seq != chan->expected_tx_seq) {
control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
- control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ control |= __set_reqseq(chan, chan->expected_tx_seq);
l2cap_send_sframe(chan, control);
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
@@ -3397,7 +3397,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
{
u8 tx_seq = __get_txseq(rx_control);
- u8 req_seq = __get_reqseq(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;
@@ -3531,10 +3531,10 @@ drop:
static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 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%4.4x", 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) {
@@ -3571,7 +3571,7 @@ 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)
{
- 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);
@@ -3592,7 +3592,7 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c
}
static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 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);
@@ -3628,7 +3628,7 @@ 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)
{
- 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);
@@ -3692,7 +3692,7 @@ 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;
+ u16 req_seq;
int len, next_tx_seq_offset, req_seq_offset;
control = get_unaligned_le16(skb->data);
@@ -3718,7 +3718,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;
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 07/16] Bluetooth: EWS: rewrite L2CAP ERTM txseq calculation
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (5 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 06/16] Bluetooth: EWS: rewrite reqseq calculation Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 08/16] Bluetooth: EWS: rewrite check frame type function Emeltchenko Andrei
` (8 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
L2CAP ERTM txseq calculation uses now information about control field type.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 36 +++++++++++++++++++++++++++---------
net/bluetooth/l2cap_core.c | 22 +++++++++++-----------
2 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 57b64bb..3ca24af 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -316,7 +316,7 @@ struct l2cap_conn_param_update_rsp {
/* ----- L2CAP channels and connections ----- */
struct srej_list {
- __u8 tx_seq;
+ __u16 tx_seq;
struct list_head list;
};
@@ -362,14 +362,14 @@ 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_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 sdu_len;
@@ -529,7 +529,25 @@ static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
else
return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
}
-#define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
+
+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;
+}
+
#define __is_iframe(ctrl) (!((ctrl) & L2CAP_CTRL_FRAME_TYPE))
#define __is_sframe(ctrl) ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index f35eb73..1c367d6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1270,7 +1270,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan)
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;
+ control |= __set_txseq(chan, chan->next_tx_seq);
put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
if (chan->fcs == L2CAP_FCS_CRC16) {
@@ -1284,7 +1284,7 @@ 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;
@@ -1317,7 +1317,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
control |= L2CAP_CTRL_FINAL;
control |= __set_reqseq(chan, chan->buffer_seq);
- control |= tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
+ control |= __set_txseq(chan, tx_seq);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
@@ -1357,7 +1357,7 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
control |= L2CAP_CTRL_FINAL;
control |= __set_reqseq(chan, chan->buffer_seq);
- control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
+ control |= __set_txseq(chan, chan->next_tx_seq);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
@@ -3136,7 +3136,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
}
}
-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;
@@ -3330,7 +3330,7 @@ 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;
@@ -3357,7 +3357,7 @@ 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;
@@ -3376,7 +3376,7 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
}
}
-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;
@@ -3396,7 +3396,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
{
- u8 tx_seq = __get_txseq(rx_control);
+ 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;
@@ -3763,7 +3763,7 @@ 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;
+ u16 tx_seq;
int len;
chan = l2cap_get_chan_by_scid(conn, cid);
@@ -3820,7 +3820,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
if (len > chan->mps || len < 0 || __is_sframe(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] 25+ messages in thread* [PATCHv3 08/16] Bluetooth: EWS: rewrite check frame type function
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (6 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 07/16] Bluetooth: EWS: rewrite L2CAP ERTM txseq calculation Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 09/16] Bluetooth: EWS: rewrite handling FINAL (F) bit Emeltchenko Andrei
` (7 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Check frame function uses now information about control field type.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 18 ++++++++++++++++--
net/bluetooth/l2cap_core.c | 9 +++++----
2 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 3ca24af..9444dce 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -548,8 +548,22 @@ static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
}
-#define __is_iframe(ctrl) (!((ctrl) & L2CAP_CTRL_FRAME_TYPE))
-#define __is_sframe(ctrl) ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
+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))
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 1c367d6..9262a00 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -578,7 +578,8 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
BT_DBG("chan %p, control 0x%2.2x", 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;
@@ -3707,7 +3708,7 @@ 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(chan, control) && __is_iframe(control))
+ if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
len -= 2;
if (chan->fcs == L2CAP_FCS_CRC16)
@@ -3734,7 +3735,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;
@@ -3817,7 +3818,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
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(chan, control);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 09/16] Bluetooth: EWS: rewrite handling FINAL (F) bit
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (7 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 08/16] Bluetooth: EWS: rewrite check frame type function Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 10/16] Bluetooth: EWS: rewrite handling POLL (P) bit Emeltchenko Andrei
` (6 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Handle final (F) bit in L2CAP using information about control field type.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 15 +++++++++++++++
net/bluetooth/l2cap_core.c | 20 ++++++++++----------
2 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 9444dce..3110c43 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -612,6 +612,21 @@ static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
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;
+}
extern int disable_ertm;
int l2cap_init_sockets(void);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9262a00..c500d1c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -582,7 +582,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
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;
@@ -1315,7 +1315,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
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 |= __set_reqseq(chan, chan->buffer_seq);
control |= __set_txseq(chan, tx_seq);
@@ -1355,7 +1355,7 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
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 |= __set_reqseq(chan, chan->buffer_seq);
control |= __set_txseq(chan, chan->next_tx_seq);
@@ -1428,7 +1428,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan)
u16 control;
control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
- control |= L2CAP_CTRL_FINAL;
+ control |= __set_ctrl_final(chan);
tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
control |= __set_reqseq(chan, tail->tx_seq);
@@ -3407,7 +3407,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", 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)
@@ -3512,7 +3512,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);
}
@@ -3551,7 +3551,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))
@@ -3581,7 +3581,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 {
@@ -3612,7 +3612,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);
@@ -3659,7 +3659,7 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
{
BT_DBG("chan %p rx_control 0x%4.4x 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)
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 10/16] Bluetooth: EWS: rewrite handling POLL (P) bit
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (8 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 09/16] Bluetooth: EWS: rewrite handling FINAL (F) bit Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-13 19:47 ` Gustavo Padovan
2011-10-11 10:37 ` [PATCHv3 11/16] Bluetooth: EWS: handling different Control fields Emeltchenko Andrei
` (5 subsequent siblings)
15 siblings, 1 reply; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Handle POLL (P) bit in L2CAP ERTM using information about control field type.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 16 ++++++++++++++++
net/bluetooth/l2cap_core.c | 14 +++++++-------
2 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 3110c43..67a2fdb 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -627,6 +627,22 @@ static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
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;
+}
extern int disable_ertm;
int l2cap_init_sockets(void);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c500d1c..97aa545 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -585,7 +585,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
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)
@@ -3304,7 +3304,7 @@ static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
goto done;
control = __set_reqseq(chan, chan->buffer_seq);
- control |= L2CAP_CTRL_POLL;
+ control |= __set_ctrl_poll(chan);
control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
l2cap_send_sframe(chan, control);
chan->retry_count = 1;
@@ -3538,7 +3538,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
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) &&
@@ -3599,7 +3599,7 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
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);
@@ -3637,17 +3637,17 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c
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 {
rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCHv3 10/16] Bluetooth: EWS: rewrite handling POLL (P) bit
2011-10-11 10:37 ` [PATCHv3 10/16] Bluetooth: EWS: rewrite handling POLL (P) bit Emeltchenko Andrei
@ 2011-10-13 19:47 ` Gustavo Padovan
0 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2011-10-13 19:47 UTC (permalink / raw)
To: Emeltchenko Andrei; +Cc: linux-bluetooth
Hi Andrei,
* Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-11 13:37:50 +0300]:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Handle POLL (P) bit in L2CAP ERTM using information about control field type.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/l2cap.h | 16 ++++++++++++++++
> net/bluetooth/l2cap_core.c | 14 +++++++-------
> 2 files changed, 23 insertions(+), 7 deletions(-)
Patches up to this one were applied. Thanks for doing this work.
Gustavo
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCHv3 11/16] Bluetooth: EWS: handling different Control fields
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (9 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 10/16] Bluetooth: EWS: rewrite handling POLL (P) bit Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-13 19:49 ` Gustavo Padovan
2011-10-11 10:37 ` [PATCHv3 12/16] Bluetooth: EWS: recalculate L2CAP header size Emeltchenko Andrei
` (4 subsequent siblings)
15 siblings, 1 reply; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
There are three different Control Field formats: the Standard Control
Field, the Enhanced Control Field, and the Extended Control Field.
Patch adds function to handle all those fields seamlessly.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 43 +++++++++++++++++++
net/bluetooth/l2cap_core.c | 93 +++++++++++++++++++++-------------------
2 files changed, 92 insertions(+), 44 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 67a2fdb..3a5f4c0 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
@@ -643,6 +645,47 @@ static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
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;
int l2cap_init_sockets(void);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 97aa545..6a5d1d6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -561,7 +561,7 @@ 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;
@@ -575,7 +575,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
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);
@@ -594,7 +594,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);
@@ -611,7 +612,7 @@ 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 |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
@@ -1267,12 +1268,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 = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
control |= __set_txseq(chan, chan->next_tx_seq);
- put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
+ __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
if (chan->fcs == L2CAP_FCS_CRC16) {
fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
@@ -1288,7 +1290,8 @@ static void l2cap_streaming_send(struct l2cap_chan *chan)
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)
@@ -1311,7 +1314,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
tx_skb = skb_clone(skb, GFP_ATOMIC);
bt_cb(skb)->retries++;
- control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+
+ 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))
@@ -1320,7 +1324,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
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);
@@ -1333,7 +1337,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 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)
@@ -1351,7 +1356,7 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
bt_cb(skb)->retries++;
- control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+ 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))
@@ -1359,8 +1364,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
control |= __set_reqseq(chan, chan->buffer_seq);
control |= __set_txseq(chan, chan->next_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 *)skb->data, tx_skb->len - 2);
@@ -1404,7 +1409,7 @@ 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 |= __set_reqseq(chan, chan->buffer_seq);
@@ -1425,7 +1430,7 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
static void l2cap_send_srejtail(struct l2cap_chan *chan)
{
struct srej_list *tail;
- u16 control;
+ u32 control;
control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
control |= __set_ctrl_final(chan);
@@ -1529,7 +1534,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
struct msghdr *msg, size_t len,
- u16 control, u16 sdulen)
+ u32 control, u16 sdulen)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
@@ -1558,7 +1563,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
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));
@@ -1579,7 +1586,7 @@ 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);
@@ -1623,7 +1630,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 */
@@ -3113,7 +3120,7 @@ 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;
@@ -3198,7 +3205,7 @@ 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;
@@ -3281,7 +3288,7 @@ 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);
@@ -3298,7 +3305,7 @@ 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;
@@ -3334,7 +3341,7 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
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)) {
@@ -3361,7 +3368,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 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) {
@@ -3380,7 +3387,7 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 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 = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
@@ -3395,7 +3402,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 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)
{
u16 tx_seq = __get_txseq(chan, rx_control);
u16 req_seq = __get_reqseq(chan, rx_control);
@@ -3404,7 +3411,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
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 (__is_ctrl_final(chan, rx_control) &&
@@ -3530,9 +3537,9 @@ 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,
+ 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(chan, rx_control);
@@ -3570,11 +3577,11 @@ 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)
{
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);
@@ -3591,11 +3598,11 @@ 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)
{
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);
@@ -3627,11 +3634,11 @@ 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)
{
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;
@@ -3655,9 +3662,9 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c
}
}
-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 (__is_ctrl_final(chan, rx_control) &&
test_bit(CONN_WAIT_F, &chan->conn_state)) {
@@ -3692,12 +3699,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;
+ 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;
/*
@@ -3763,7 +3769,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
{
struct l2cap_chan *chan;
struct sock *sk = NULL;
- u16 control;
+ u32 control;
u16 tx_seq;
int len;
@@ -3805,8 +3811,7 @@ 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))
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCHv3 11/16] Bluetooth: EWS: handling different Control fields
2011-10-11 10:37 ` [PATCHv3 11/16] Bluetooth: EWS: handling different Control fields Emeltchenko Andrei
@ 2011-10-13 19:49 ` Gustavo Padovan
2011-10-14 10:56 ` Emeltchenko Andrei
0 siblings, 1 reply; 25+ messages in thread
From: Gustavo Padovan @ 2011-10-13 19:49 UTC (permalink / raw)
To: Emeltchenko Andrei; +Cc: linux-bluetooth
* Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-11 13:37:51 +0300]:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> There are three different Control Field formats: the Standard Control
> Field, the Enhanced Control Field, and the Extended Control Field.
> Patch adds function to handle all those fields seamlessly.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/l2cap.h | 43 +++++++++++++++++++
> net/bluetooth/l2cap_core.c | 93 +++++++++++++++++++++-------------------
> 2 files changed, 92 insertions(+), 44 deletions(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 67a2fdb..3a5f4c0 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
> @@ -643,6 +645,47 @@ static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
> 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);
> + }
I prefer not hide the skb_pull inside another function.
> +
> + 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));
> +}
get ride of this, you still can do __put_control(chan, control, skb_put())
Gustavo
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCHv3 11/16] Bluetooth: EWS: handling different Control fields
2011-10-13 19:49 ` Gustavo Padovan
@ 2011-10-14 10:56 ` Emeltchenko Andrei
2011-10-14 18:09 ` Gustavo Padovan
0 siblings, 1 reply; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-14 10:56 UTC (permalink / raw)
To: linux-bluetooth
Hi Gustavo,
On Thu, Oct 13, 2011 at 04:49:25PM -0300, Gustavo Padovan wrote:
> * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-11 13:37:51 +0300]:
>
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >
> > There are three different Control Field formats: the Standard Control
> > Field, the Enhanced Control Field, and the Extended Control Field.
> > Patch adds function to handle all those fields seamlessly.
> >
> > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > ---
> > include/net/bluetooth/l2cap.h | 43 +++++++++++++++++++
> > net/bluetooth/l2cap_core.c | 93 +++++++++++++++++++++-------------------
> > 2 files changed, 92 insertions(+), 44 deletions(-)
> >
> > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> > index 67a2fdb..3a5f4c0 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
> > @@ -643,6 +645,47 @@ static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
> > 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);
> > + }
>
>
> I prefer not hide the skb_pull inside another function.
OK, I will change it to something like:
<------8<----------------------------------------------------------------
| @@ -4005,7 +4009,8 @@ static int l2cap_ertm_data_rcv(struct sock *sk,
| struct sk_buff *skb)
| u16 req_seq;
| int len, next_tx_seq_offset, req_seq_offset;
|
| - control = __get_control_pull(chan, skb, skb->data);
| + control = __get_control(chan, skb->data);
| + skb_pull(skb, __get_ctrl_size(chan));
| len = skb->len;
|
| /*
|
<------8<----------------------------------------------------------------
> > +
> > + 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));
> > +}
>
>
> get ride of this, you still can do __put_control(chan, control,
> skb_put())
the second argument in skb_put changes so I cannot use proposed way.
what about change to code below:
<------8<--------------------------------------------------------
| @@ -1586,6 +1588,7 @@ static struct sk_buff
| *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
| struct sk_buff *skb;
| int err, count, hlen;
| struct l2cap_hdr *lh;
| + unsigned char *data;
|
| BT_DBG("sk %p len %d", sk, (int)len);
|
| @@ -1614,7 +1617,8 @@ static struct sk_buff
| *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
| lh->cid = cpu_to_le16(chan->dcid);
| lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
|
| - __put_control_put(chan, control, skb);
| + data = skb_put(skb, __get_ctrl_size(chan));
| + __put_control(chan, control, data);
|
| if (sdulen)
| put_unaligned_le16(sdulen, skb_put(skb,
| L2CAP_SDULEN_SIZE));
|
<------8<--------------------------------------------------------
Best regards
Andrei Emeltchenko
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCHv3 11/16] Bluetooth: EWS: handling different Control fields
2011-10-14 10:56 ` Emeltchenko Andrei
@ 2011-10-14 18:09 ` Gustavo Padovan
2011-10-14 18:19 ` Gustavo Padovan
0 siblings, 1 reply; 25+ messages in thread
From: Gustavo Padovan @ 2011-10-14 18:09 UTC (permalink / raw)
To: Emeltchenko Andrei, linux-bluetooth
Hi Andrei,
* Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-14 13:56:03 +0300]:
> Hi Gustavo,
>
> On Thu, Oct 13, 2011 at 04:49:25PM -0300, Gustavo Padovan wrote:
> > * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-11 13:37:51 +0300]:
> >
> > > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > >
> > > There are three different Control Field formats: the Standard Control
> > > Field, the Enhanced Control Field, and the Extended Control Field.
> > > Patch adds function to handle all those fields seamlessly.
> > >
> > > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > > ---
> > > include/net/bluetooth/l2cap.h | 43 +++++++++++++++++++
> > > net/bluetooth/l2cap_core.c | 93 +++++++++++++++++++++-------------------
> > > 2 files changed, 92 insertions(+), 44 deletions(-)
> > >
> > > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> > > index 67a2fdb..3a5f4c0 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
> > > @@ -643,6 +645,47 @@ static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
> > > 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);
> > > + }
> >
> >
> > I prefer not hide the skb_pull inside another function.
>
> OK, I will change it to something like:
>
> <------8<----------------------------------------------------------------
> | @@ -4005,7 +4009,8 @@ static int l2cap_ertm_data_rcv(struct sock *sk,
> | struct sk_buff *skb)
> | u16 req_seq;
> | int len, next_tx_seq_offset, req_seq_offset;
> |
> | - control = __get_control_pull(chan, skb, skb->data);
> | + control = __get_control(chan, skb->data);
> | + skb_pull(skb, __get_ctrl_size(chan));
> | len = skb->len;
> |
> | /*
> |
> <------8<----------------------------------------------------------------
>
>
> > > +
> > > + 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));
> > > +}
> >
> >
> > get ride of this, you still can do __put_control(chan, control,
> > skb_put())
> the second argument in skb_put changes so I cannot use proposed way.
Why not?
You just call __put_control(chan, control, skb_put(skb, N));
This pass exactly what you want to __put_control(). Do you agree?
Gustavo
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCHv3 11/16] Bluetooth: EWS: handling different Control fields
2011-10-14 18:09 ` Gustavo Padovan
@ 2011-10-14 18:19 ` Gustavo Padovan
0 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2011-10-14 18:19 UTC (permalink / raw)
To: Emeltchenko Andrei, linux-bluetooth
* Gustavo Padovan <padovan@profusion.mobi> [2011-10-14 15:09:15 -0300]:
> Hi Andrei,
>
> * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-14 13:56:03 +0300]:
>
> > Hi Gustavo,
> >
> > On Thu, Oct 13, 2011 at 04:49:25PM -0300, Gustavo Padovan wrote:
> > > * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-11 13:37:51 +0300]:
> > >
> > > > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > > >
> > > > There are three different Control Field formats: the Standard Control
> > > > Field, the Enhanced Control Field, and the Extended Control Field.
> > > > Patch adds function to handle all those fields seamlessly.
> > > >
> > > > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > > > ---
> > > > include/net/bluetooth/l2cap.h | 43 +++++++++++++++++++
> > > > net/bluetooth/l2cap_core.c | 93 +++++++++++++++++++++-------------------
> > > > 2 files changed, 92 insertions(+), 44 deletions(-)
> > > >
> > > > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> > > > index 67a2fdb..3a5f4c0 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
> > > > @@ -643,6 +645,47 @@ static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
> > > > 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);
> > > > + }
> > >
> > >
> > > I prefer not hide the skb_pull inside another function.
> >
> > OK, I will change it to something like:
> >
> > <------8<----------------------------------------------------------------
> > | @@ -4005,7 +4009,8 @@ static int l2cap_ertm_data_rcv(struct sock *sk,
> > | struct sk_buff *skb)
> > | u16 req_seq;
> > | int len, next_tx_seq_offset, req_seq_offset;
> > |
> > | - control = __get_control_pull(chan, skb, skb->data);
> > | + control = __get_control(chan, skb->data);
> > | + skb_pull(skb, __get_ctrl_size(chan));
> > | len = skb->len;
> > |
> > | /*
> > |
> > <------8<----------------------------------------------------------------
> >
> >
> > > > +
> > > > + 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));
> > > > +}
> > >
> > >
> > > get ride of this, you still can do __put_control(chan, control,
> > > skb_put())
> > the second argument in skb_put changes so I cannot use proposed way.
>
> Why not?
>
> You just call __put_control(chan, control, skb_put(skb, N));
Actually it is __get_ctrl_size() instead of N here, and just rename it to
__ctrl_size() only.
Gustavo
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCHv3 12/16] Bluetooth: EWS: recalculate L2CAP header size
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (10 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 11/16] Bluetooth: EWS: handling different Control fields Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-13 19:54 ` Gustavo Padovan
2011-10-11 10:37 ` [PATCHv3 13/16] Bluetooth: EWS: support extended seq numbers Emeltchenko Andrei
` (3 subsequent siblings)
15 siblings, 1 reply; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Recalculate length of L2CAP header based on Control field length.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/l2cap_core.c | 21 ++++++++++++++++++---
1 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6a5d1d6..92b0f03 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -566,12 +566,17 @@ 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_EXT_HDR_SIZE;
+ else
+ hlen = L2CAP_ENH_HDR_SIZE;
+
if (chan->fcs == L2CAP_FCS_CRC16)
hlen += 2;
@@ -1539,7 +1544,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
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);
@@ -1547,6 +1552,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
if (!conn)
return ERR_PTR(-ENOTCONN);
+ if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+ hlen = L2CAP_EXT_HDR_SIZE;
+ else
+ hlen = L2CAP_ENH_HDR_SIZE;
+
if (sdulen)
hlen += 2;
@@ -3105,7 +3115,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_EXT_HDR_SIZE;
+ else
+ hdr_size = L2CAP_ENH_HDR_SIZE;
if (chan->fcs == L2CAP_FCS_CRC16) {
skb_trim(skb, skb->len - 2);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCHv3 13/16] Bluetooth: EWS: support extended seq numbers
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (11 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 12/16] Bluetooth: EWS: recalculate L2CAP header size Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 14/16] Bluetooth: EWS: define L2CAP header sizes Emeltchenko Andrei
` (2 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 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 3a5f4c0..b3ae9ea 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -355,6 +355,7 @@ struct l2cap_chan {
__u8 fcs;
__u16 tx_win;
+ __u16 tx_win_max;
__u8 max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
@@ -502,6 +503,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 92b0f03..2f1cd92 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1288,7 +1288,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);
}
}
@@ -1382,7 +1382,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++;
@@ -1924,12 +1925,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_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_EXT_WINDOW;
+ } else {
chan->tx_win = min_t(u16, chan->tx_win,
L2CAP_DEFAULT_TX_WINDOW);
+ chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
+ }
}
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
@@ -2086,6 +2090,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
set_bit(FLAG_EXT_CTRL, &chan->flags);
set_bit(CONF_EWS_RECV, &chan->conf_state);
+ chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
chan->remote_tx_win = val;
break;
@@ -3173,18 +3178,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);
@@ -3374,9 +3375,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);
}
}
@@ -3411,10 +3411,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)
@@ -3440,9 +3443,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) {
@@ -3490,10 +3491,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)
@@ -3518,7 +3517,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;
@@ -3528,7 +3527,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;
@@ -3741,14 +3741,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) {
@@ -3853,7 +3850,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] 25+ messages in thread* [PATCHv3 14/16] Bluetooth: EWS: define L2CAP header sizes
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (12 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 13/16] Bluetooth: EWS: support extended seq numbers Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-13 19:55 ` Gustavo Padovan
2011-10-11 10:37 ` [PATCHv3 15/16] Bluetooth: EWS: remove magic numbers in l2cap Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 16/16] Bluetooth: EWS: fix max_pdu calculation Emeltchenko Andrei
15 siblings, 1 reply; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Adds definitins for L2CAP header sizes to be uses when calculating
payload size instead of magic numbers.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b3ae9ea..ebd6392 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -164,6 +164,12 @@ struct l2cap_hdr {
__le16 cid;
} __packed;
#define L2CAP_HDR_SIZE 4
+#define L2CAP_ENH_HDR_SIZE 6
+#define L2CAP_EXT_HDR_SIZE 8
+
+#define L2CAP_FCS_SIZE 2
+#define L2CAP_SDULEN_SIZE 2
+#define L2CAP_PSMLEN_SIZE 2
struct l2cap_cmd_hdr {
__u8 code;
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCHv3 14/16] Bluetooth: EWS: define L2CAP header sizes
2011-10-11 10:37 ` [PATCHv3 14/16] Bluetooth: EWS: define L2CAP header sizes Emeltchenko Andrei
@ 2011-10-13 19:55 ` Gustavo Padovan
2011-10-14 11:15 ` Emeltchenko Andrei
0 siblings, 1 reply; 25+ messages in thread
From: Gustavo Padovan @ 2011-10-13 19:55 UTC (permalink / raw)
To: Emeltchenko Andrei; +Cc: linux-bluetooth
Hi Andrei,
* Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-11 13:37:54 +0300]:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Adds definitins for L2CAP header sizes to be uses when calculating
> payload size instead of magic numbers.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/l2cap.h | 6 ++++++
> 1 files changed, 6 insertions(+), 0 deletions(-)
Applied, Thanks. Please fix patch 11 and rebase the others so I can apply
everything.
Gustavo
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCHv3 14/16] Bluetooth: EWS: define L2CAP header sizes
2011-10-13 19:55 ` Gustavo Padovan
@ 2011-10-14 11:15 ` Emeltchenko Andrei
0 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-14 11:15 UTC (permalink / raw)
To: linux-bluetooth
Hi Gustavo,
On Thu, Oct 13, 2011 at 04:55:35PM -0300, Gustavo Padovan wrote:
> Hi Andrei,
>
> * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2011-10-11 13:37:54 +0300]:
>
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >
> > Adds definitins for L2CAP header sizes to be uses when calculating
> > payload size instead of magic numbers.
> >
> > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > ---
> > include/net/bluetooth/l2cap.h | 6 ++++++
> > 1 files changed, 6 insertions(+), 0 deletions(-)
>
> Applied, Thanks. Please fix patch 11 and rebase the others so I can apply
> everything.
Sorry for noticing it late, could you rearrange that patch so that it
comes before "Bluetooth: EWS: recalculate L2CAP header size"
(PATCHv3 12/16)
Best regards
Andrei Emeltchenko
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCHv3 15/16] Bluetooth: EWS: remove magic numbers in l2cap
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (13 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 14/16] Bluetooth: EWS: define L2CAP header sizes Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
2011-10-11 10:37 ` [PATCHv3 16/16] Bluetooth: EWS: fix max_pdu calculation Emeltchenko Andrei
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Remove magic numbers for FCS, SDU LEN and PSM LEN
when calculating packet payload.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/l2cap_core.c | 46 ++++++++++++++++++++++++-------------------
1 files changed, 26 insertions(+), 20 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 2f1cd92..a703301 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -578,7 +578,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
hlen = L2CAP_ENH_HDR_SIZE;
if (chan->fcs == L2CAP_FCS_CRC16)
- hlen += 2;
+ hlen += L2CAP_FCS_SIZE;
BT_DBG("chan %p, control 0x%8.8x", chan, control);
@@ -603,8 +603,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))
@@ -1282,8 +1282,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);
@@ -1332,8 +1334,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);
@@ -1373,8 +1377,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);
@@ -1484,7 +1490,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
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 = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
struct l2cap_hdr *lh;
BT_DBG("sk %p len %d", sk, (int)len);
@@ -1559,10 +1565,10 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
hlen = L2CAP_ENH_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,
@@ -1578,7 +1584,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
__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)) {
@@ -1587,7 +1593,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
}
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;
@@ -3128,7 +3134,7 @@ static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
hdr_size = L2CAP_ENH_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);
@@ -3238,7 +3244,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;
@@ -3730,10 +3736,10 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
goto drop;
if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
- len -= 2;
+ 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);
@@ -3830,10 +3836,10 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
goto drop;
if (__is_sar_start(chan, control))
- len -= 2;
+ 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] 25+ messages in thread* [PATCHv3 16/16] Bluetooth: EWS: fix max_pdu calculation
2011-10-11 10:37 [PATCHv3 00/16] EWS: extended window size and extended control field support Emeltchenko Andrei
` (14 preceding siblings ...)
2011-10-11 10:37 ` [PATCHv3 15/16] Bluetooth: EWS: remove magic numbers in l2cap Emeltchenko Andrei
@ 2011-10-11 10:37 ` Emeltchenko Andrei
15 siblings, 0 replies; 25+ messages in thread
From: Emeltchenko Andrei @ 2011-10-11 10:37 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 | 42 ++++++++++++++++++++++++++++--------------
1 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a703301..d418ddb 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1947,6 +1947,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
struct l2cap_conf_req *req = data;
struct l2cap_conf_rfc rfc = { .mode = chan->mode };
void *ptr = req->data;
+ u16 size;
BT_DBG("chan %p", chan);
@@ -1991,9 +1992,12 @@ 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);
+
+ size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
+ L2CAP_EXT_HDR_SIZE -
+ L2CAP_SDULEN_SIZE -
+ L2CAP_FCS_SIZE);
+ rfc.max_pdu_size = cpu_to_le16(size);
l2cap_txwin_setup(chan);
@@ -2023,9 +2027,12 @@ done:
rfc.max_transmit = 0;
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);
+
+ size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
+ L2CAP_EXT_HDR_SIZE -
+ L2CAP_SDULEN_SIZE -
+ L2CAP_FCS_SIZE);
+ rfc.max_pdu_size = cpu_to_le16(size);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
(unsigned long) &rfc);
@@ -2058,6 +2065,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
u16 mtu = L2CAP_DEFAULT_MTU;
u16 result = L2CAP_CONF_SUCCESS;
+ u16 size;
BT_DBG("chan %p", chan);
@@ -2167,10 +2175,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);
-
- chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+ size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
+ chan->conn->mtu -
+ L2CAP_EXT_HDR_SIZE -
+ L2CAP_SDULEN_SIZE -
+ L2CAP_FCS_SIZE);
+ rfc.max_pdu_size = cpu_to_le16(size);
+ chan->remote_mps = size;
rfc.retrans_timeout =
le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
@@ -2185,10 +2196,13 @@ 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);
-
- chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+ size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
+ chan->conn->mtu -
+ L2CAP_EXT_HDR_SIZE -
+ L2CAP_SDULEN_SIZE -
+ L2CAP_FCS_SIZE);
+ rfc.max_pdu_size = cpu_to_le16(size);
+ chan->remote_mps = size;
set_bit(CONF_MODE_DONE, &chan->conf_state);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 25+ messages in thread