Hi Andrei, * Emeltchenko Andrei <Andrei.Emeltchenko.news@xxxxxxxxx> [2011-09-07 17:05:11 +0300]: > From: Andrei Emeltchenko <andrei.emeltchenko@xxxxxxxxx> > > Adds support for parsing extended control field. Extended control > field may be used for ERTM and streaming mode (if EWS specified). > u32 control is used for standard, enhanced and extended control > fields. Flag in l2cap chan specifies which format is in use. > > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@xxxxxxxxx> > --- > include/net/bluetooth/l2cap.h | 276 +++++++++++++++++++++++++++++++++------ > net/bluetooth/l2cap_core.c | 291 ++++++++++++++++++++++------------------ > 2 files changed, 397 insertions(+), 170 deletions(-) > > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h > index 92eac16..5395984 100644 > --- a/include/net/bluetooth/l2cap.h > +++ b/include/net/bluetooth/l2cap.h > @@ -27,6 +27,8 @@ > #ifndef __L2CAP_H > #define __L2CAP_H > > +#include <asm/unaligned.h> > + > /* L2CAP defaults */ > #define L2CAP_DEFAULT_MTU 672 > #define L2CAP_DEFAULT_MIN_MTU 48 > @@ -113,36 +115,52 @@ struct l2cap_conninfo { > #define L2CAP_FCS_CRC16 0x01 > > /* L2CAP Control Field bit masks */ > -#define L2CAP_CTRL_SAR 0xC000 > -#define L2CAP_CTRL_REQSEQ 0x3F00 > -#define L2CAP_CTRL_TXSEQ 0x007E > -#define L2CAP_CTRL_RETRANS 0x0080 > -#define L2CAP_CTRL_FINAL 0x0080 > -#define L2CAP_CTRL_POLL 0x0010 > -#define L2CAP_CTRL_SUPERVISE 0x000C > -#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */ > - > -#define L2CAP_CTRL_TXSEQ_SHIFT 1 > -#define L2CAP_CTRL_REQSEQ_SHIFT 8 > -#define L2CAP_CTRL_SAR_SHIFT 14 > +#define L2CAP_CTRL_SAR_MASK 0xC000 > +#define L2CAP_CTRL_REQSEQ_MASK 0x3F00 > +#define L2CAP_CTRL_TXSEQ_MASK 0x007E > +#define L2CAP_CTRL_SUPERVISE_MASK 0x000C Don't add a _MASK here. It just make the macros bigger. > + > +#define L2CAP_CTRL_RETRANS 0x0080 > +#define L2CAP_CTRL_FINAL 0x0080 > +#define L2CAP_CTRL_POLL 0x0010 > +#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */ > + > +#define L2CAP_CTRL_TXSEQ_SHIFT 1 > +#define L2CAP_CTRL_SUPER_SHIFT 2 > +#define L2CAP_CTRL_REQSEQ_SHIFT 8 > +#define L2CAP_CTRL_SAR_SHIFT 14 > + > +/* L2CAP Extended Control Field bit mask */ > +#define L2CAP_EXT_CTRL_TXSEQ_MASK 0xFFFC0000 > +#define L2CAP_EXT_CTRL_SAR_MASK 0x00030000 > +#define L2CAP_EXT_CTRL_SUPERVISE_MASK 0x00030000 > +#define L2CAP_EXT_CTRL_REQSEQ_MASK 0x0000FFFC > + > +#define L2CAP_EXT_CTRL_POLL 0x00040000 > +#define L2CAP_EXT_CTRL_FINAL 0x00000002 > +#define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */ > + > +#define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2 > +#define L2CAP_EXT_CTRL_SAR_SHIFT 16 > +#define L2CAP_EXT_CTRL_SUPER_SHIFT 16 > +#define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18 > > /* L2CAP Supervisory Function */ > -#define L2CAP_SUPER_RCV_READY 0x0000 > -#define L2CAP_SUPER_REJECT 0x0004 > -#define L2CAP_SUPER_RCV_NOT_READY 0x0008 > -#define L2CAP_SUPER_SELECT_REJECT 0x000C > +#define L2CAP_SUPER_RR 0x00 > +#define L2CAP_SUPER_REJ 0x01 > +#define L2CAP_SUPER_RNR 0x02 > +#define L2CAP_SUPER_SREJ 0x03 > > /* L2CAP Segmentation and Reassembly */ > -#define L2CAP_SDU_UNSEGMENTED 0x0000 > -#define L2CAP_SDU_START 0x4000 > -#define L2CAP_SDU_END 0x8000 > -#define L2CAP_SDU_CONTINUE 0xC000 > +#define L2CAP_SAR_UNSEGMENTED 0x00 > +#define L2CAP_SAR_START 0x01 > +#define L2CAP_SAR_END 0x02 > +#define L2CAP_SAR_CONTINUE 0x03 > > /* L2CAP Command rej. reasons */ > -#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000 > -#define L2CAP_REJ_MTU_EXCEEDED 0x0001 > -#define L2CAP_REJ_INVALID_CID 0x0002 > - > +#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000 > +#define L2CAP_REJ_MTU_EXCEEDED 0x0001 > +#define L2CAP_REJ_INVALID_CID 0x0002 > > /* L2CAP structures */ > struct l2cap_hdr { > @@ -150,6 +168,11 @@ struct l2cap_hdr { > __le16 cid; > } __packed; > #define L2CAP_HDR_SIZE 4 > +#define L2CAP_ENHANCED_HDR_SIZE 6 > +#define L2CAP_EXTENDED_HDR_SIZE 8 > + > +#define L2CAP_FCS_SIZE 2 > +#define L2CAP_SDULEN_SIZE 2 > > struct l2cap_cmd_hdr { > __u8 code; > @@ -320,7 +343,7 @@ struct l2cap_conn_param_update_rsp { > > /* ----- L2CAP channels and connections ----- */ > struct srej_list { > - __u8 tx_seq; > + __u16 tx_seq; > struct list_head list; > }; > > @@ -370,16 +393,16 @@ struct l2cap_chan { > unsigned long conn_state; > unsigned long flags; > > - __u8 next_tx_seq; > - __u8 expected_ack_seq; > - __u8 expected_tx_seq; > - __u8 buffer_seq; > - __u8 buffer_seq_srej; > - __u8 srej_save_reqseq; > - __u8 frames_sent; > - __u8 unacked_frames; > + __u16 next_tx_seq; > + __u16 expected_ack_seq; > + __u16 expected_tx_seq; > + __u16 buffer_seq; > + __u16 buffer_seq_srej; > + __u16 srej_save_reqseq; > + __u16 frames_sent; > + __u16 unacked_frames; > __u8 retry_count; > - __u8 num_acked; > + __u16 num_acked; > __u16 sdu_len; > struct sk_buff *sdu; > struct sk_buff *sdu_last_frag; > @@ -539,11 +562,186 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) > return sub == ch->remote_tx_win; > } > > -#define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1) > -#define __get_reqseq(ctrl) (((ctrl) & L2CAP_CTRL_REQSEQ) >> 8) > -#define __is_iframe(ctrl) (!((ctrl) & L2CAP_CTRL_FRAME_TYPE)) > -#define __is_sframe(ctrl) ((ctrl) & L2CAP_CTRL_FRAME_TYPE) > -#define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) > +static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >> > + L2CAP_EXT_CTRL_REQSEQ_SHIFT; > + else > + return (ctrl & L2CAP_CTRL_REQSEQ_MASK) >> > + L2CAP_CTRL_REQSEQ_SHIFT; > +} > + > +static inline __u32 __set_reqseq(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_MASK; > + else > + return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & > + L2CAP_CTRL_REQSEQ_MASK; > +} > + > +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_MASK) >> > + L2CAP_EXT_CTRL_TXSEQ_SHIFT; > + else > + return (ctrl & L2CAP_CTRL_TXSEQ_MASK) >> > + 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_MASK; > + else > + return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & > + L2CAP_CTRL_TXSEQ_MASK; > +} > + > +static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE; > + else > + return ctrl & L2CAP_CTRL_FRAME_TYPE; > +} > + > +static inline __u32 __set_sframe(struct l2cap_chan *chan) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return L2CAP_EXT_CTRL_FRAME_TYPE; > + else > + return L2CAP_CTRL_FRAME_TYPE; > +} > + > +static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return (ctrl & L2CAP_EXT_CTRL_SAR_MASK) >> > + L2CAP_EXT_CTRL_SAR_SHIFT; > + else > + return (ctrl & L2CAP_CTRL_SAR_MASK) >> > + 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_MASK; > + else > + return (sar << L2CAP_CTRL_SAR_SHIFT) & > + L2CAP_CTRL_SAR_MASK; > +} > + > +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_MASK; > + else > + return L2CAP_CTRL_SAR_MASK; > +} > + > +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_MASK) >> > + L2CAP_EXT_CTRL_SUPER_SHIFT; > + else > + return (ctrl & L2CAP_CTRL_SUPERVISE_MASK) >> > + 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_MASK; > + else > + return (super << L2CAP_CTRL_SUPER_SHIFT) & > + L2CAP_CTRL_SUPERVISE_MASK; > +} > + > +static inline __u32 __set_ctrl_final(struct l2cap_chan *chan) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return L2CAP_EXT_CTRL_FINAL; > + else > + return L2CAP_CTRL_FINAL; > +} > + > +static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return ctrl & L2CAP_EXT_CTRL_FINAL; > + else > + return ctrl & L2CAP_CTRL_FINAL; > +} > + > +static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return L2CAP_EXT_CTRL_POLL; > + else > + return L2CAP_CTRL_POLL; > +} > + > +static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return ctrl & L2CAP_EXT_CTRL_POLL; > + else > + return ctrl & L2CAP_CTRL_POLL; > +} > + > +static inline __u32 __get_control(struct l2cap_chan *chan, void *p) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return get_unaligned_le32(p); > + else > + return get_unaligned_le16(p); > +} > + > +static inline __u32 __get_control_pull(struct l2cap_chan *chan, > + struct sk_buff *skb, void *p) > +{ > + __u32 ctrl; > + > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { > + ctrl = get_unaligned_le32(p); > + skb_pull(skb, 4); > + } else { > + ctrl = get_unaligned_le16(p); > + skb_pull(skb, 2); > + } > + > + return ctrl; > +} > + > +static inline void __put_control(struct l2cap_chan *chan, __u32 control, void *p) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return put_unaligned_le32(control, p); > + else > + return put_unaligned_le16(control, p); > +} > + > +static inline void __put_control_put(struct l2cap_chan *chan, __u32 control, void *p) > +{ > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + return put_unaligned_le32(control, skb_put(p, 4)); > + else > + return put_unaligned_le16(control, skb_put(p, 2)); > +} > > extern int disable_ertm; > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > index 81b8d02..aae92df 100644 > --- a/net/bluetooth/l2cap_core.c > +++ b/net/bluetooth/l2cap_core.c > @@ -570,30 +570,36 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, > hci_send_acl(conn->hcon, skb, flags); > } > > -static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) > +static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) > { > struct sk_buff *skb; > struct l2cap_hdr *lh; > struct l2cap_conn *conn = chan->conn; > - int count, hlen = L2CAP_HDR_SIZE + 2; > + int count, hlen; > u8 flags; > > if (chan->state != BT_CONNECTED) > return; > > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + hlen = L2CAP_EXTENDED_HDR_SIZE; > + else > + hlen = L2CAP_ENHANCED_HDR_SIZE; > + > if (chan->fcs == L2CAP_FCS_CRC16) > hlen += 2; > > - BT_DBG("chan %p, control 0x%2.2x", chan, control); > + BT_DBG("chan %p, control 0x%8.8x", chan, control); > > count = min_t(unsigned int, conn->mtu, hlen); > - control |= L2CAP_CTRL_FRAME_TYPE; > + > + control |= __set_sframe(chan); > > if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) > - control |= L2CAP_CTRL_FINAL; > + control |= __set_ctrl_final(chan); > > if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state)) > - control |= L2CAP_CTRL_POLL; > + control |= __set_ctrl_poll(chan); > > skb = bt_skb_alloc(count, GFP_ATOMIC); > if (!skb) > @@ -602,7 +608,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); > @@ -619,15 +626,15 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) > hci_send_acl(chan->conn->hcon, skb, flags); > } > > -static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) > +static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) > { > if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { > - control |= L2CAP_SUPER_RCV_NOT_READY; > + control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); > set_bit(CONN_RNR_SENT, &chan->conn_state); > } else > - control |= L2CAP_SUPER_RCV_READY; > + control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); > > - control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; > + control |= __set_reqseq(chan, chan->buffer_seq); > > l2cap_send_sframe(chan, control); > } > @@ -1274,12 +1281,13 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) > static void l2cap_streaming_send(struct l2cap_chan *chan) > { > struct sk_buff *skb; > - u16 control, fcs; > + u32 control; > + u16 fcs; > > while ((skb = skb_dequeue(&chan->tx_q))) { > - control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE); > - control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; > - put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); > + control = __get_control(chan, skb->data + L2CAP_HDR_SIZE); > + control |= __set_txseq(chan, chan->next_tx_seq); > + __put_control(chan, control, skb->data + L2CAP_HDR_SIZE); > > if (chan->fcs == L2CAP_FCS_CRC16) { > fcs = crc16(0, (u8 *)skb->data, skb->len - 2); > @@ -1292,10 +1300,11 @@ static void l2cap_streaming_send(struct l2cap_chan *chan) > } > } > > -static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) > +static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq) > { > struct sk_buff *skb, *tx_skb; > - u16 control, fcs; > + u16 fcs; > + u32 control; > > skb = skb_peek(&chan->tx_q); > if (!skb) > @@ -1318,16 +1327,17 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) > > tx_skb = skb_clone(skb, GFP_ATOMIC); > bt_cb(skb)->retries++; > - control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); > - control &= L2CAP_CTRL_SAR; > + > + control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); > + control &= __get_sar_mask(chan); > > if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) > - control |= L2CAP_CTRL_FINAL; > + control |= __set_ctrl_final(chan); > > - control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) > - | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); > + control |= __set_reqseq(chan, chan->buffer_seq); > + control |= __set_txseq(chan, tx_seq); > > - put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); > + __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); > > if (chan->fcs == L2CAP_FCS_CRC16) { > fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); > @@ -1340,7 +1350,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) > static int l2cap_ertm_send(struct l2cap_chan *chan) > { > struct sk_buff *skb, *tx_skb; > - u16 control, fcs; > + u16 fcs; > + u32 control; > int nsent = 0; > > if (chan->state != BT_CONNECTED) > @@ -1358,16 +1369,16 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) > > bt_cb(skb)->retries++; > > - control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); > - control &= L2CAP_CTRL_SAR; > + control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); > + control &= __get_sar_mask(chan); > > if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) > - control |= L2CAP_CTRL_FINAL; > + control |= __set_ctrl_final(chan); > > - control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) > - | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); > - put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); > + control |= __set_reqseq(chan, chan->buffer_seq); > + control |= __set_txseq(chan, chan->next_tx_seq); > > + __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); > > if (chan->fcs == L2CAP_FCS_CRC16) { > fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2); > @@ -1411,12 +1422,12 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan) > > static void l2cap_send_ack(struct l2cap_chan *chan) > { > - u16 control = 0; > + u32 control = 0; > > - control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; > + control |= __set_reqseq(chan, chan->buffer_seq); > > if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { > - control |= L2CAP_SUPER_RCV_NOT_READY; > + control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); > set_bit(CONN_RNR_SENT, &chan->conn_state); > l2cap_send_sframe(chan, control); > return; > @@ -1425,20 +1436,20 @@ static void l2cap_send_ack(struct l2cap_chan *chan) > if (l2cap_ertm_send(chan) > 0) > return; > > - control |= L2CAP_SUPER_RCV_READY; > + control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); > l2cap_send_sframe(chan, control); > } > > static void l2cap_send_srejtail(struct l2cap_chan *chan) > { > struct srej_list *tail; > - u16 control; > + u32 control; > > - control = L2CAP_SUPER_SELECT_REJECT; > - control |= L2CAP_CTRL_FINAL; > + control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); > + control |= __set_ctrl_final(chan); > > tail = list_entry((&chan->srej_l)->prev, struct srej_list, list); > - control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; > + control |= __set_reqseq(chan, tail->tx_seq); > > l2cap_send_sframe(chan, control); > } > @@ -1534,12 +1545,12 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms > return skb; > } > > -static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) > +static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 control, u16 sdulen) > { > struct sock *sk = chan->sk; > struct l2cap_conn *conn = chan->conn; > struct sk_buff *skb; > - int err, count, hlen = L2CAP_HDR_SIZE + 2; > + int err, count, hlen; > struct l2cap_hdr *lh; > > BT_DBG("sk %p len %d", sk, (int)len); > @@ -1547,6 +1558,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m > if (!conn) > return ERR_PTR(-ENOTCONN); > > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + hlen = L2CAP_EXTENDED_HDR_SIZE; > + else > + hlen = L2CAP_ENHANCED_HDR_SIZE; > + > if (sdulen) > hlen += 2; > > @@ -1563,7 +1579,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct m > lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); > lh->cid = cpu_to_le16(chan->dcid); > lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); > - put_unaligned_le16(control, skb_put(skb, 2)); > + > + __put_control_put(chan, control, skb); > + > if (sdulen) > put_unaligned_le16(sdulen, skb_put(skb, 2)); > > @@ -1584,11 +1602,11 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si > { > struct sk_buff *skb; > struct sk_buff_head sar_queue; > - u16 control; > + u32 control; > size_t size = 0; > > skb_queue_head_init(&sar_queue); > - control = L2CAP_SDU_START; > + control = __set_ctrl_sar(chan, L2CAP_SAR_START); > skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); > if (IS_ERR(skb)) > return PTR_ERR(skb); > @@ -1601,10 +1619,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; > } > > @@ -1628,7 +1646,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 */ > @@ -1660,7 +1678,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)) > @@ -1991,8 +2009,11 @@ done: > rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); > > l2cap_txwin_setup(chan); > - rfc.txwin_size = chan->tx_win > L2CAP_DEFAULT_MAX_TX_WINDOW ? > - L2CAP_DEFAULT_MAX_TX_WINDOW : chan->tx_win; > + > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + rfc.txwin_size = L2CAP_DEFAULT_MAX_TX_WINDOW; > + else > + rfc.txwin_size = chan->tx_win; > > l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), > (unsigned long) &rfc); > @@ -3267,7 +3288,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, > static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb) > { > u16 our_fcs, rcv_fcs; > - int hdr_size = L2CAP_HDR_SIZE + 2; > + int hdr_size; > + > + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) > + hdr_size = L2CAP_EXTENDED_HDR_SIZE; > + else > + hdr_size = L2CAP_ENHANCED_HDR_SIZE; > > if (chan->fcs == L2CAP_FCS_CRC16) { > skb_trim(skb, skb->len - 2); > @@ -3282,14 +3308,14 @@ static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb) > > static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) > { > - u16 control = 0; > + u32 control = 0; > > chan->frames_sent = 0; > > - control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; > + control |= __set_reqseq(chan, chan->buffer_seq); > > if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { > - control |= L2CAP_SUPER_RCV_NOT_READY; > + control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); > l2cap_send_sframe(chan, control); > set_bit(CONN_RNR_SENT, &chan->conn_state); > } > @@ -3301,12 +3327,12 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) > > if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) && > chan->frames_sent == 0) { > - control |= L2CAP_SUPER_RCV_READY; > + control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); > l2cap_send_sframe(chan, control); > } > } > > -static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar) > +static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar) > { > struct sk_buff *next_skb; > int tx_seq_offset, next_tx_seq_offset; > @@ -3367,19 +3393,19 @@ static void append_skb_frag(struct sk_buff *skb, > skb->truesize += new_frag->truesize; > } > > -static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) > +static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control) > { > int err = -EINVAL; > > - switch (control & L2CAP_CTRL_SAR) { > - case L2CAP_SDU_UNSEGMENTED: > + switch (__get_ctrl_sar(chan, control)) { > + case L2CAP_SAR_UNSEGMENTED: > if (chan->sdu) > break; > > err = chan->ops->recv(chan->data, skb); > break; > > - case L2CAP_SDU_START: > + case L2CAP_SAR_START: > if (chan->sdu) > break; > > @@ -3401,7 +3427,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; > > @@ -3415,7 +3441,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; > > @@ -3450,14 +3476,14 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1 > > static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) > { > - u16 control; > + u32 control; > > BT_DBG("chan %p, Enter local busy", chan); > > set_bit(CONN_LOCAL_BUSY, &chan->conn_state); > > - control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; > - control |= L2CAP_SUPER_RCV_NOT_READY; > + control = __set_reqseq(chan, chan->buffer_seq); > + control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); > l2cap_send_sframe(chan, control); > > set_bit(CONN_RNR_SENT, &chan->conn_state); > @@ -3467,13 +3493,14 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) > > static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan) > { > - u16 control; > + u32 control; > > if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) > goto done; > > - control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; > - control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; > + control = __set_reqseq(chan, chan->buffer_seq); > + control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); > + control |= __set_ctrl_poll(chan); > l2cap_send_sframe(chan, control); > chan->retry_count = 1; > > @@ -3499,10 +3526,10 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy) > } > } > > -static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) > +static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq) > { > struct sk_buff *skb; > - u16 control; > + u32 control; > > while ((skb = skb_peek(&chan->srej_q)) && > !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { > @@ -3512,7 +3539,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) { > @@ -3526,10 +3553,10 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) > } > } > > -static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) > +static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq) > { > struct srej_list *l, *tmp; > - u16 control; > + u32 control; > > list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { > if (l->tx_seq == tx_seq) { > @@ -3537,22 +3564,22 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) > kfree(l); > return; > } > - control = L2CAP_SUPER_SELECT_REJECT; > - control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; > + control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); > + control |= __set_reqseq(chan, l->tx_seq); > l2cap_send_sframe(chan, control); > list_del(&l->list); > list_add_tail(&l->list, &chan->srej_l); > } > } > > -static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) > +static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq) > { > struct srej_list *new; > - u16 control; > + u32 control; > > while (tx_seq != chan->expected_tx_seq) { > - control = L2CAP_SUPER_SELECT_REJECT; > - control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; > + control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); > + control |= __set_reqseq(chan, chan->expected_tx_seq); > l2cap_send_sframe(chan, control); > > new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); > @@ -3563,19 +3590,19 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) > chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; > } > > -static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) > +static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb) > { > - u8 tx_seq = __get_txseq(rx_control); > - u8 req_seq = __get_reqseq(rx_control); > - u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; > + u16 tx_seq = __get_txseq(chan, rx_control); > + u16 req_seq = __get_reqseq(chan, rx_control); > + u8 sar = __get_ctrl_sar(chan, rx_control); > int tx_seq_offset, expected_tx_seq_offset; > int num_to_ack = (chan->tx_win/6) + 1; > int err = 0; > > - BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len, > + BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len, > tx_seq, rx_control); > > - if (L2CAP_CTRL_FINAL & rx_control && > + if (__is_ctrl_final(chan, rx_control) && > test_bit(CONN_WAIT_F, &chan->conn_state)) { > __clear_monitor_timer(chan); > if (chan->unacked_frames > 0) > @@ -3680,7 +3707,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); > } > @@ -3698,15 +3725,16 @@ drop: > return 0; > } > > -static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control) > +static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control) > { > - BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control), > - rx_control); > + BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", > + chan, __get_reqseq(chan, rx_control), > + rx_control); Indentation is wrong here. > > - chan->expected_ack_seq = __get_reqseq(rx_control); > + chan->expected_ack_seq = __get_reqseq(chan, rx_control); > l2cap_drop_acked_frames(chan); > > - if (rx_control & L2CAP_CTRL_POLL) { > + if (__is_ctrl_poll(chan, rx_control)) { > set_bit(CONN_SEND_FBIT, &chan->conn_state); > if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { > if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && > @@ -3719,7 +3747,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)) > @@ -3738,9 +3766,9 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co > } > } > > -static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control) > +static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control) > { > - u8 tx_seq = __get_reqseq(rx_control); > + u16 tx_seq = __get_reqseq(chan, rx_control); > > BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); > > @@ -3749,7 +3777,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 { > @@ -3759,15 +3787,15 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c > set_bit(CONN_REJ_ACT, &chan->conn_state); > } > } > -static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control) > +static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control) > { > - u8 tx_seq = __get_reqseq(rx_control); > + u16 tx_seq = __get_reqseq(chan, rx_control); > > - BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); > + BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control); > > clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); > > - if (rx_control & L2CAP_CTRL_POLL) { > + if (__is_ctrl_poll(chan, rx_control)) { > chan->expected_ack_seq = tx_seq; > l2cap_drop_acked_frames(chan); > > @@ -3780,7 +3808,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); > @@ -3795,37 +3823,39 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_ > } > } > > -static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control) > +static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control) > { > - u8 tx_seq = __get_reqseq(rx_control); > + u16 tx_seq = __get_reqseq(chan, rx_control); > > - BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); > + BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control); > > set_bit(CONN_REMOTE_BUSY, &chan->conn_state); > chan->expected_ack_seq = tx_seq; > l2cap_drop_acked_frames(chan); > > - if (rx_control & L2CAP_CTRL_POLL) > + if (__is_ctrl_poll(chan, rx_control)) > set_bit(CONN_SEND_FBIT, &chan->conn_state); > > if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) { > __clear_retrans_timer(chan); > - if (rx_control & L2CAP_CTRL_POLL) > + if (__is_ctrl_poll(chan, rx_control)) > l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL); > return; > } > > - if (rx_control & L2CAP_CTRL_POLL) > + if (__is_ctrl_poll(chan, rx_control)) > l2cap_send_srejtail(chan); > - else > - l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY); > + else { > + rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR); > + l2cap_send_sframe(chan, rx_control); > + } You need to add { } to th if as well. > } > > -static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) > +static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb) > { > - BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len); > + BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len); > > - if (L2CAP_CTRL_FINAL & rx_control && > + if (__is_ctrl_final(chan, rx_control) && > test_bit(CONN_WAIT_F, &chan->conn_state)) { > __clear_monitor_timer(chan); > if (chan->unacked_frames > 0) > @@ -3833,20 +3863,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; > } > @@ -3858,12 +3888,11 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont > static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) > { > struct l2cap_chan *chan = l2cap_pi(sk)->chan; > - u16 control; > - u8 req_seq; > + u32 control; > + u16 req_seq; > int len, next_tx_seq_offset, req_seq_offset; > > - control = get_unaligned_le16(skb->data); > - skb_pull(skb, 2); > + control = __get_control_pull(chan, skb, skb->data); > len = skb->len; > > /* > @@ -3874,8 +3903,9 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) > if (l2cap_check_fcs(chan, skb)) > goto drop; > > - if (__is_sar_start(control) && __is_iframe(control)) > - len -= 2; > + if (__is_sar_start(chan, control) && > + !__is_sframe(chan, control)) > + len -= L2CAP_SDULEN_SIZE; > > if (chan->fcs == L2CAP_FCS_CRC16) > len -= 2; > @@ -3885,7 +3915,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; > @@ -3901,7 +3931,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; > @@ -3929,8 +3959,8 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk > { > struct l2cap_chan *chan; > struct sock *sk = NULL; > - u16 control; > - u8 tx_seq; > + u32 control; > + u16 tx_seq; > int len; > > chan = l2cap_get_chan_by_scid(conn, cid); > @@ -3971,23 +4001,22 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk > goto done; > > case L2CAP_MODE_STREAMING: > - control = get_unaligned_le16(skb->data); > - skb_pull(skb, 2); > + control = __get_control_pull(chan, skb, skb->data); > len = skb->len; > > if (l2cap_check_fcs(chan, skb)) > goto drop; > > - if (__is_sar_start(control)) > - len -= 2; > + if (__is_sar_start(chan, control)) > + len -= L2CAP_SDULEN_SIZE; > > if (chan->fcs == L2CAP_FCS_CRC16) > len -= 2; > > - if (len > chan->mps || len < 0 || __is_sframe(control)) > + if (len > chan->mps || len < 0 || __is_sframe(chan, control)) > goto drop; > > - tx_seq = __get_txseq(control); > + tx_seq = __get_txseq(chan, control); > > if (chan->expected_tx_seq != tx_seq) { > /* Frame(s) missing - must discard partial SDU */ Otherwise looks pretty good. Gustavo -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html