Skip to contentSkip to conversation

New L2CAP ERTM state machine

RFC In review Mat Martineau 5 participants 21 messages Feb 23, 2012 – Mar 6, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover New L2CAP ERTM state machine

Here's an update for the ERTM state machine patch. I've made the changes that were suggested earlier this month, and separated the header changes and l2cap_core changes.

The first patch is a reasonable size for mailing list discussion, but the second is too large. In place of the second patch I'm providing a link to the change. Let me know if I should just try to send the large patch anyway.

You can pull these changes from:
git://codeaurora.org/quic/bluetooth/bluetooth-next.git

Tag name: mathewm-2012-02-23-ertm

Mat Martineau (2):
Bluetooth: Header changes for ERTM state machine replacement
Bluetooth: L2CAP ERTM state machine replacement

 include/net/bluetooth/bluetooth.h |   14 +-
 include/net/bluetooth/l2cap.h     |  260 +---
 net/bluetooth/l2cap_core.c        | 2771 +++++++++++++++++++++++++------------
 3 files changed, 1954 insertions(+), 1091 deletions(-)
Signature · 6 lines
1.7.9

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

RFC 1/2 Bluetooth: Header changes for ERTM state machine replacement

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

---
 include/net/bluetooth/bluetooth.h |   14 ++-
 include/net/bluetooth/l2cap.h     |  260 +++++++++----------------------------
 2 files changed, 73 insertions(+), 201 deletions(-)
include/net/bluetooth/bluetooth.h +12 -2
index 262ebd1..a667cb8 100644
@@ -215,14 +215,24 @@ void bt_accept_unlink(struct sock *sk);
 struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
 
 /* Skb helpers */
+struct bt_l2cap_control {
+	__u8  frame_type;
+	__u8  final;
+	__u8  sar;
+	__u8  super;
+	__u16 reqseq;
+	__u16 txseq;
+	__u8  poll;
+	__u8  fcs;
+};
+
 struct bt_skb_cb {
 	__u8 pkt_type;
 	__u8 incoming;
 	__u16 expect;
-	__u16 tx_seq;
 	__u8 retries;
-	__u8 sar;
 	__u8 force_active;
+	struct bt_l2cap_control control;
 };
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
 
include/net/bluetooth/l2cap.h +61 -199

335 lines not on this page · raw message

Signature · 6 lines
1.7.9

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

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

Hi Mat,

It is better to have normal patches for a better review. I think that we can minimize amount of changes by redefining defines when they cannot be used.

I also think think that patches shall be logically split like:
- change control field handling
- working with FCS, etc which do not affect state machine
- adding states

Also check some comments below: (I copied some code from the link you sent)

Quoted 12 lines · Mat Martineau

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

---
 include/net/bluetooth/bluetooth.h |   14 ++-
 include/net/bluetooth/l2cap.h     |  260 +++++++++----------------------------
 2 files changed, 73 insertions(+), 201 deletions(-)

...

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 684

Quoted 11 lines
include/net/bluetooth/l2cap.h +0 -11
-static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
-{
-	int sub;
-
-	sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
-
-	if (sub < 0)
-		sub += 64;
-
-	return sub == ch->remote_tx_win;
-}

BTW: was it already changed? What is the status with Luiz's patch?

...

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 824

Quoted 7 lines
include/net/bluetooth/l2cap.h +0 -7
-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);
-}

Cannot it still be used?

+ if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
+ __get_extended_control(get_unaligned_le32(skb->data),
+ control);
+ skb_pull(skb, L2CAP_EXT_CTRL_SIZE);
+ } else {
+ __get_enhanced_control(get_unaligned_le16(skb->data),
+ control);
+ skb_pull(skb, L2CAP_ENH_CTRL_SIZE);
+ }

- control = __get_control(chan, skb->data);
- skb_pull(skb, __ctrl_size(chan));

...

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 833

Quoted 8 lines
include/net/bluetooth/l2cap.h +0 -8
-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);
-}

Can it be used in the code below:

+ if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
+ put_unaligned_le32(__pack_extended_control(control),
+ skb->data + L2CAP_HDR_SIZE);
+ } else {
+ put_unaligned_le16(__pack_enhanced_control(control),
+ skb->data + L2CAP_HDR_SIZE);
+ }

and for example here:

-       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+       /* Control header is populated later */
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))

+ put_unaligned_le32(0, skb_put(skb, 4));
+ else
+ put_unaligned_le16(0, skb_put(skb, 2));

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 841

Quoted 8 lines
include/net/bluetooth/l2cap.h +0 -8
-
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
-	else
-		return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
-}

Regards,
Andrei

#3 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

Hi Andrei,

Quoted 6 lines · Andrei Emeltchenko

Hi Mat,

It is better to have normal patches for a better review. I think that we can minimize amount of changes by redefining defines when they cannot be used.

Quoted 6 lines

I also think think that patches shall be logically split like:
- change control field handling
- working with FCS, etc which do not affect state machine
- adding states

Also check some comments below: (I copied some code from the link you sen=

t)

Quoted 9 lines · Mat Martineau
Quoted 7 lines

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. =A0An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. =A0Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

Quoted 4 lines
Quoted 4 lines

---
=A0include/net/bluetooth/bluetooth.h | =A0 14 ++- =A0include/net/bluetooth/l2cap.h =A0 =A0 | =A0260 +++++++++-------------=

---------------

Quoted 30 lines
Quoted 1 line

=A02 files changed, 73 insertions(+), 201 deletions(-)

...

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 684

Quoted 11 lines
include/net/bluetooth/l2cap.h +0 -11
-static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
-{
- =A0 =A0 int sub;
-
- =A0 =A0 sub =3D (ch->next_tx_seq - ch->expected_ack_seq) % 64;
-
- =A0 =A0 if (sub < 0)
- =A0 =A0 =A0 =A0 =A0 =A0 sub +=3D 64;
-
- =A0 =A0 return sub =3D=3D ch->remote_tx_win;
-}

BTW: was it already changed? What is the status with Luiz's patch?

...

Review

Quoted 7 lines
(quoted diff) +0 -7
-static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
-{
- =A0 =A0 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
- =A0 =A0 =A0 =A0 =A0 =A0 return get_unaligned_le32(p);
- =A0 =A0 else
- =A0 =A0 =A0 =A0 =A0 =A0 return get_unaligned_le16(p);
-}

Cannot it still be used?

Quoted 2 lines

+ =A0 =A0 =A0 if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 __get_extended_control(get_unaligned_le32(s=

kb->data),

Quoted 1 line

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=

=A0control);

Quoted 3 lines

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 skb_pull(skb, L2CAP_EXT_CTRL_SIZE);
+ =A0 =A0 =A0 } else {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 __get_enhanced_control(get_unaligned_le16(s=

kb->data),

Quoted 1 line

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=

=A0control);

Quoted 9 lines

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 skb_pull(skb, L2CAP_ENH_CTRL_SIZE);
+ =A0 =A0 =A0 }

- =A0 =A0 =A0 control =3D __get_control(chan, skb->data);
- =A0 =A0 =A0 skb_pull(skb, __ctrl_size(chan));

...

Quoted 1 line

-static inline void __put_control(struct l2cap_chan *chan, __u32 control=

,

Quoted 1 line
Quoted 1 line

- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *p)

Quoted 10 lines

Review

Quoted 6 lines
(quoted diff) +0 -6
-{
- =A0 =A0 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
- =A0 =A0 =A0 =A0 =A0 =A0 return put_unaligned_le32(control, p);
- =A0 =A0 else
- =A0 =A0 =A0 =A0 =A0 =A0 return put_unaligned_le16(control, p);
-}

Can it be used in the code below:

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (test_bit(FLAG_EXT_CTRL, &chan->flags)) =

{

Quoted 1 line

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 put_unaligned_le32(__pack_e=

xtended_control(control),

Quoted 1 line

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=

=A0 skb->data + L2CAP_HDR_SIZE);

Quoted 2 lines

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 put_unaligned_le16(__pack_e=

nhanced_control(control),

Quoted 1 line

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=

=A0 skb->data + L2CAP_HDR_SIZE);

Quoted 5 lines

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 }

and for example here:

- =A0 =A0 =A0 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)=

));

Quoted 7 lines

+ =A0 =A0 =A0 /* Control header is populated later */
+ =A0 =A0 =A0 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 put_unaligned_le32(0, skb_put(skb, 4));
+ =A0 =A0 =A0 else
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 put_unaligned_le16(0, skb_put(skb, 2));

Quoted 8 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 841

Quoted 8 lines
include/net/bluetooth/l2cap.h +0 -8
-
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
- =A0 =A0 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
- =A0 =A0 =A0 =A0 =A0 =A0 return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
- =A0 =A0 else
- =A0 =A0 =A0 =A0 =A0 =A0 return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
-}

Do we have that many places with this test in Mat's code? If not, then we might not need to bother having all of these helpers, I think. And if we add them, I do think it makes sense to add them to l2cap_core.c than in l2cap.h, right?

Regards,

--=20
Ulisses Furquim
ProFUSION embedded systems
http://profusion.mobi
Mobile: +55 19 9250 0942
Skype: ulissesffs

#4 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

Andrei and Ulisses -

Quoted 7 lines · Ulisses Furquim

Hi Andrei,

Quoted 3 lines · Andrei Emeltchenko

Hi Mat,

It is better to have normal patches for a better review.

I would have preferred to have more "normal" patches, but I didn't want to keep you guys waiting another week.

Quoted 2 lines
Quoted 2 lines

I think that we can minimize amount of changes by redefining defines when they cannot be used.

Do you mean that it would be better to modify existing macros rather than remove them?

Quoted 5 lines
Quoted 5 lines

I also think think that patches shall be logically split like:
- change control field handling
- working with FCS, etc which do not affect state machine
- adding states

Sounds like a good way to divide things up.

Quoted 19 lines
Quoted 19 lines

Also check some comments below: (I copied some code from the link you sent)

Quoted 12 lines · Mat Martineau

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

---
  include/net/bluetooth/bluetooth.h |   14 ++-
  include/net/bluetooth/l2cap.h     |  260 +++++++++----------------------------
  2 files changed, 73 insertions(+), 201 deletions(-)

...

Quoted 13 lines
Quoted 5 lines
Quoted 5 lines
include/net/bluetooth/l2cap.h +0 -5
-static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
-{
-     int sub;
-
-     sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
Quoted 8 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 684

Quoted 6 lines
include/net/bluetooth/l2cap.h +0 -6
-
-     if (sub<  0)
-             sub += 64;
-
-     return sub == ch->remote_tx_win;
-}

BTW: was it already changed? What is the status with Luiz's patch?

I'm not sure about the patch status - but I do know this function isn't needed with the new ERTM code.

Quoted 12 lines
Quoted 12 lines

...

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 824

Quoted 7 lines
include/net/bluetooth/l2cap.h +0 -7
-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);
-}

Cannot it still be used?

It's not needed. The control header is only parsed in one place now at the beginning of l2cap_ertm_data_rcv(), and this macro isn't a good fit for the code there.

Quoted 27 lines
Quoted 27 lines
(quoted diff) +9 -2
+       if (test_bit(FLAG_EXT_CTRL,&chan->flags)) {
+               __get_extended_control(get_unaligned_le32(skb->data),
+                                      control);
+               skb_pull(skb, L2CAP_EXT_CTRL_SIZE);
+       } else {
+               __get_enhanced_control(get_unaligned_le16(skb->data),
+                                      control);
+               skb_pull(skb, L2CAP_ENH_CTRL_SIZE);
+       }
 
-       control = __get_control(chan, skb->data);
-       skb_pull(skb, __ctrl_size(chan));
 
...

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 833

Quoted 9 lines
include/net/bluetooth/l2cap.h +0 -8
-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);
-}

Can it be used in the code below:

Quoted 8 lines

Review

Quoted 8 lines
(quoted diff) +7 -0
+               if (test_bit(FLAG_EXT_CTRL,&chan->flags)) {
+                       put_unaligned_le32(__pack_extended_control(control),
+                                       skb->data + L2CAP_HDR_SIZE);
+               } else {
+                       put_unaligned_le16(__pack_enhanced_control(control),
+                                       skb->data + L2CAP_HDR_SIZE);
+               }

Since the __pack function differs based on the extended/enhanced header type, it doesn't seem worthwhile to check FLAG_EXT_CTRL twice.

The code I'm porting in predates the __put_control macro, so I didn't make an effort to remove it. In order to avoid breaking things, I'm trying to only change the ported code where required. I'm open to making this code better, though!

Quoted 8 lines

Review

Quoted 8 lines

and for example here:

(quoted diff) +5 -1
-       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+       /* Control header is populated later */
+       if (test_bit(FLAG_EXT_CTRL,&chan->flags))
+               put_unaligned_le32(0, skb_put(skb, 4));
+       else
+               put_unaligned_le16(0, skb_put(skb, 2));

This is the only place the macro would drop in cleanly - but it seems like a macro should be used in more than one place unless it's hiding some really distracting syntax. In this case, I think it's clearer to see what's going on.

And - I forgot to fix some magic numbers in those skb_puts.

Quoted 14 lines
Quoted 9 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 841

Quoted 9 lines
include/net/bluetooth/l2cap.h +0 -8
-
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
-     if (test_bit(FLAG_EXT_CTRL,&chan->flags))
-             return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
-     else
-             return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
-}

Do we have that many places with this test in Mat's code? If not, then we might not need to bother having all of these helpers, I think. And if we add them, I do think it makes sense to add them to l2cap_core.c than in l2cap.h, right?

Not too many places with the FLAG_EXT_CTRL test, with use of struct bt_control in most of the code. I would rather have helpers in l2cap_core.c if they're needed.

Thanks for the reviews!

Signature · 3 lines
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
#5 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

Hi Mat,

On Fri, Feb 24, 2012 at 9:21 PM, Mat Martineau <[email protected]> wro= te:

Quoted 11 lines

Andrei and Ulisses -

Quoted 7 lines · Ulisses Furquim

Hi Andrei,

Quoted 2 lines · On Fri, Feb 24, 2012 at 7:48 AM, Andrei Emeltchenko…

Hi Mat,

<snip>

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

and for example here:

- =A0 =A0 =A0 __put_control(chan, control, skb_put(skb, __ctrl_size(cha=

n)));

Quoted 9 lines
Quoted 6 lines
Quoted 6 lines

+ =A0 =A0 =A0 /* Control header is populated later */
+ =A0 =A0 =A0 if (test_bit(FLAG_EXT_CTRL,&chan->flags))

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 put_unaligned_le32(0, skb_put(skb, 4));
+ =A0 =A0 =A0 else
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 put_unaligned_le16(0, skb_put(skb, 2));

This is the only place the macro would drop in cleanly - but it seems lik=

e a

Quoted 1 line

macro should be used in more than one place unless it's hiding some reall=

y

Quoted 1 line

distracting syntax. =A0In this case, I think it's clearer to see what's g=

oing

Quoted 1 line

on.

If we don't have a lot of places then I'd rather see what's going on as wel= l.

Quoted 1 line

And - I forgot to fix some magic numbers in those skb_puts.

This would be good to fix.

Quoted 15 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
include/net/bluetooth/l2cap.h +0 -4
-
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
- =A0 =A0 if (test_bit(FLAG_EXT_CTRL,&chan->flags))
Quoted 9 lines
Quoted 4 lines
Quoted 4 lines

- =A0 =A0 =A0 =A0 =A0 =A0 return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
- =A0 =A0 else
- =A0 =A0 =A0 =A0 =A0 =A0 return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE; -}

Do we have that many places with this test in Mat's code? If not, then we might not need to bother having all of these helpers, I think. And if we add them, I do think it makes sense to add them to l2cap_core.c than in l2cap.h, right?

Quoted 2 lines

Not too many places with the FLAG_EXT_CTRL test, with use of struct bt_control in most of the code. =A0I would rather have helpers in l2cap_c=

ore.c

Quoted 1 line

if they're needed.

Agreed.

Regards,

--=20
Ulisses Furquim
ProFUSION embedded systems
http://profusion.mobi
Mobile: +55 19 9250 0942
Skype: ulissesffs

#6 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

In reply to Mat Martineau

Hi all,

Quoted 5 lines · Mat Martineau
Quoted 2 lines
Quoted 2 lines

I think that we can minimize amount of changes by redefining defines when they cannot be used.

Do you mean that it would be better to modify existing macros rather than remove them?

Only if they might be used of course.

Quoted 6 lines
Quoted 4 lines
Quoted 4 lines

I also think think that patches shall be logically split like:
- change control field handling
- working with FCS, etc which do not affect state machine
- adding states

Sounds like a good way to divide things up.

Agree, this does not mean of course that the whole code shall be put in 3 patches ;) Otherwise it might be rejected because of huge size.

Quoted 12 lines
Quoted 11 lines
Quoted 11 lines · Mat Martineau

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 824

Quoted 8 lines

This change affects data structures storing ERTM state and control

include/net/bluetooth/l2cap.h +0 -7
-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);
-}

Cannot it still be used?

Quoted 3 lines

It's not needed. The control header is only parsed in one place now at the beginning of l2cap_ertm_data_rcv(), and this macro isn't a good fit for the code there.

If this is used only once it is not needed of course.

Quoted 5 lines
Quoted 5 lines

Review

Quoted 5 lines

and for example here:

(quoted diff) +2 -1
-       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+       /* Control header is populated later */
+       if (test_bit(FLAG_EXT_CTRL,&chan->flags))

BTW: Here and in all other places please put space after ",".

Quoted 8 lines
Quoted 3 lines

Review

Quoted 3 lines
(quoted diff) +3 -0
+               put_unaligned_le32(0, skb_put(skb, 4));
+       else
+               put_unaligned_le16(0, skb_put(skb, 2));

This is the only place the macro would drop in cleanly - but it seems like a macro should be used in more than one place unless it's hiding some really distracting syntax. In this case, I think it's clearer to see what's going on.

If the code is dealing with control size than it is OK to see what is going on but if you use this in L2CAP code implementing e.g. ERTM then this is not that useful.

Quoted 1 line

And - I forgot to fix some magic numbers in those skb_puts.

Yes, we should not have them.

Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/net/bluetooth/l2cap.h +0 -4
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
-     if (test_bit(FLAG_EXT_CTRL,&chan->flags))
-             return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
Quoted 8 lines
Quoted 3 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 841

Quoted 3 lines
include/net/bluetooth/l2cap.h +0 -3
-     else
-             return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
-}

Do we have that many places with this test in Mat's code? If not, then we might not need to bother having all of these helpers, I think. And if we add them, I do think it makes sense to add them to l2cap_core.c than in l2cap.h, right?

Quoted 3 lines

Not too many places with the FLAG_EXT_CTRL test, with use of struct bt_control in most of the code. I would rather have helpers in l2cap_core.c if they're needed.

Agree with this.

Quoted 1 line

Thanks for the reviews!

Best regards
Andrei Emeltchenko

#7 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

In reply to Mat Martineau

Hi Mat,

On Thu, Feb 23, 2012 at 6:37 PM, Mat Martineau <[email protected]> wro= te:

Quoted 11 lines

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. =A0An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. =A0Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

---
=A0include/net/bluetooth/bluetooth.h | =A0 14 ++- =A0include/net/bluetooth/l2cap.h =A0 =A0 | =A0260 +++++++++--------------=

--------------

Quoted 1 line

=A02 files changed, 73 insertions(+), 201 deletions(-)

<snip>

include/net/bluetooth/l2cap.=

Quoted 1 line
include/net/bluetooth/l2cap.= renamed from include/net/bluetooth/l2cap.h +0 -0

h

Quoted 3 lines

index d6d8ec8..a499b60 100644

include/net/bluetooth/l2cap.h +0 -0

<snip>

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_=

Quoted 1 line
include/net/bluetooth/l2cap.h +0 -0
@@ -645,200 +664,43 @@ static inline bool l2cap_clear_timer(struct l2cap_=

chan *chan,

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_= · line 665

Quoted 3 lines
include/net/bluetooth/l2cap.h +0 -0
 =A0#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 =A0#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)

Are these two still needed? I saw you moved others to l2cap_core.c which is fine but what about these?

Regards,

--=20
Ulisses Furquim
ProFUSION embedded systems
http://profusion.mobi
Mobile: +55 19 9250 0942
Skype: ulissesffs

#8 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

Ulisses -

Quoted 25 lines · Ulisses Furquim

Hi Mat,

Quoted 12 lines · Mat Martineau

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

---
  include/net/bluetooth/bluetooth.h |   14 ++-
  include/net/bluetooth/l2cap.h     |  260 +++++++++----------------------------
  2 files changed, 73 insertions(+), 201 deletions(-)

<snip>

Quoted 4 lines
include/net/bluetooth/l2cap.h +0 -0
index d6d8ec8..a499b60 100644

<snip>

Quoted 7 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 666

Quoted 4 lines
include/net/bluetooth/l2cap.h +0 -0
@@ -645,200 +664,43 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
 
  #define __set_chan_timer(c, t) l2cap_set_timer(c,&c->chan_timer, (t))
  #define __clear_chan_timer(c) l2cap_clear_timer(c,&c->chan_timer)

Are these two still needed? I saw you moved others to l2cap_core.c which is fine but what about these?

Since these macros are unrelated to ERTM, that would be a separate patch.

I think all the macros traditionally land in the header files because there are no #defines in the l2cap*.c files. However, I see that many other .c files in net/bluetooth do have #defines.

It's not that I "moved" the other macros, as much as my ported code had static functions instead. I tried to minimize changes to the ported code rather than minimize changes to the upstream code.

Signature · 3 lines
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
#9 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

Hi Mat,

On Fri, Feb 24, 2012 at 9:32 PM, Mat Martineau <[email protected]> wro= te:

Quoted 36 lines

Ulisses -

Quoted 32 lines · Ulisses Furquim

Hi Mat,

Quoted 14 lines · On Thu, Feb 23, 2012 at 6:37 PM, Mat Martineau<[email protected]> =A0wrote:

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. =A0An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. =A0Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

---
=A0include/net/bluetooth/bluetooth.h | =A0 14 ++- =A0include/net/bluetooth/l2cap.h =A0 =A0 | =A0260
+++++++++----------------------------
=A02 files changed, 73 insertions(+), 201 deletions(-)

<snip>

Quoted 5 lines
include/net/bluetooth/l2cap.h +0 -0
index d6d8ec8..a499b60 100644

<snip>

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/net/bluetooth/l2cap.h +0 -0
@@ -645,200 +664,43 @@ static inline bool l2cap_clear_timer(struct
 l2cap_chan *chan,
 

=A0#define __set_chan_timer(c, t) l2cap_set_timer(c,&c->chan_timer, (t)=

)

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

=A0#define __clear_chan_timer(c) l2cap_clear_timer(c,&c->chan_timer)

Are these two still needed? I saw you moved others to l2cap_core.c which is fine but what about these?

Since these macros are unrelated to ERTM, that would be a separate patch.

You're right, sorry.

Quoted 1 line

I think all the macros traditionally land in the header files because the=

re

Quoted 1 line

are no #defines in the l2cap*.c files. =A0However, I see that many other =

.c

Quoted 4 lines

files in net/bluetooth do have #defines.

It's not that I "moved" the other macros, as much as my ported code had static functions instead. =A0I tried to minimize changes to the ported co=

de

Quoted 1 line

rather than minimize changes to the upstream code.

Yes, I saw the static functions there and I like it better there than in l2cap.h, really.

Regards,

--=20
Ulisses Furquim
ProFUSION embedded systems
http://profusion.mobi
Mobile: +55 19 9250 0942
Skype: ulissesffs

#10 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

In reply to Mat Martineau

Hi Mat,

Quoted 18 lines · Mat Martineau

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

---
 include/net/bluetooth/bluetooth.h |   14 ++-
 include/net/bluetooth/l2cap.h     |  260 +++++++++----------------------------
 2 files changed, 73 insertions(+), 201 deletions(-)
include/net/bluetooth/bluetooth.h +0 -0
index 262ebd1..a667cb8 100644

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 218

Quoted 4 lines
include/net/bluetooth/bluetooth.h +1 -0
@@ -215,14 +215,24 @@ void bt_accept_unlink(struct sock *sk);
 struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
 
 /* Skb helpers */
+struct bt_l2cap_control {

I would call this struct l2cap_ctrl only. Much smaller.

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 219

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u8  frame_type;

This could be frame_type:1, only one bit is needed here.

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 220

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u8  final;

final:1

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 221

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u8  sar;

sar:2

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 222

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u8  super;

super:2

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 223

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u16 reqseq;

go on..

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 233

Quoted 11 lines
include/net/bluetooth/bluetooth.h +5 -1
+	__u16 txseq;
+	__u8  poll;
+	__u8  fcs;
+};
+
 struct bt_skb_cb {
 	__u8 pkt_type;
 	__u8 incoming;
 	__u16 expect;
-	__u16 tx_seq;
 	__u8 retries;

I would put retries inside l2cap_ctrl. It says how many times we sent that frame, looks a type of information that fits there.

Quoted 11 lines
include/net/bluetooth/bluetooth.h +1 -1
-	__u8 sar;
 	__u8 force_active;
+	struct bt_l2cap_control control;
 };
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
 
include/net/bluetooth/l2cap.h +0 -0
index d6d8ec8..a499b60 100644

include/net/bluetooth/l2cap.h line 6

Quoted 4 lines
include/net/bluetooth/l2cap.h +1 -0
@@ -3,6 +3,7 @@
    Copyright (C) 2000-2001 Qualcomm Incorporated
    Copyright (C) 2009-2010 Gustavo F. Padovan <[email protected]>
    Copyright (C) 2010 Google Inc.
+   Copyright (c) 2012 Code Aurora Forum.  All rights reserved.

Leave the Copyright note to when you really add code to l2cap.c

Quoted 47 lines
include/net/bluetooth/l2cap.h +9 -0
    Written 2000,2001 by Maxim Krasnyansky <[email protected]>
 
@@ -44,6 +45,9 @@
 #define L2CAP_DEFAULT_MAX_SDU_SIZE	0xFFFF
 #define L2CAP_DEFAULT_SDU_ITIME		0xFFFFFFFF
 #define L2CAP_DEFAULT_ACC_LAT		0xFFFFFFFF
+#define L2CAP_BREDR_MAX_PAYLOAD		1019    /* 3-DH5 packet */
+#define L2CAP_MAX_ERTM_QUEUED		5
+#define L2CAP_MIN_ERTM_QUEUED		2
 
 #define L2CAP_DISC_TIMEOUT             (100)
 #define L2CAP_DISC_REJ_TIMEOUT         (5000)  /*  5 seconds */
@@ -139,6 +143,8 @@ struct l2cap_conninfo {
 
 #define L2CAP_CTRL_TXSEQ_SHIFT		1
 #define L2CAP_CTRL_SUPER_SHIFT		2
+#define L2CAP_CTRL_POLL_SHIFT		4
+#define L2CAP_CTRL_FINAL_SHIFT		7
 #define L2CAP_CTRL_REQSEQ_SHIFT		8
 #define L2CAP_CTRL_SAR_SHIFT		14
 
@@ -152,9 +158,11 @@ struct l2cap_conninfo {
 #define L2CAP_EXT_CTRL_FINAL		0x00000002
 #define L2CAP_EXT_CTRL_FRAME_TYPE	0x00000001 /* I- or S-Frame */
 
+#define L2CAP_EXT_CTRL_FINAL_SHIFT	1
 #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_POLL_SHIFT	18
 #define L2CAP_EXT_CTRL_TXSEQ_SHIFT	18
 
 /* L2CAP Supervisory Function */
@@ -186,6 +194,8 @@ struct l2cap_hdr {
 #define L2CAP_FCS_SIZE		2
 #define L2CAP_SDULEN_SIZE	2
 #define L2CAP_PSMLEN_SIZE	2
+#define L2CAP_ENH_CTRL_SIZE	2
+#define L2CAP_EXT_CTRL_SIZE	4
 
 struct l2cap_cmd_hdr {
 	__u8       code;
@@ -401,9 +411,12 @@ struct l2cap_conn_param_update_rsp {
 #define L2CAP_CONN_PARAM_REJECTED	0x0001
 
 /* ----- L2CAP channels and connections ----- */

include/net/bluetooth/l2cap.h struct l2cap_conn_param_update_rsp { · line 420

Quoted 10 lines
include/net/bluetooth/l2cap.h +6 -3
-struct srej_list {
-	__u16	tx_seq;
-	struct list_head list;
+struct l2cap_seq_list {
+	__u16 head;
+	__u16 tail;
+	__u16 size;
+	__u16 mask;
+	__u16 *list;
 };

So I looked to the code and saw the big kalloc you do in the list element here that is 256KB if we use the maximum tx_win in both directions. I'm open to ideas here, I don't have any better.

Quoted 32 lines
include/net/bluetooth/l2cap.h +6 -2
 struct l2cap_chan {
@@ -446,6 +459,9 @@ struct l2cap_chan {
 	__u16		monitor_timeout;
 	__u16		mps;
 
+	__u8		tx_state;
+	__u8		rx_state;
+
 	unsigned long	conf_state;
 	unsigned long	conn_state;
 	unsigned long	flags;
@@ -454,15 +470,16 @@ struct l2cap_chan {
 	__u16		expected_ack_seq;
 	__u16		expected_tx_seq;
 	__u16		buffer_seq;
-	__u16		buffer_seq_srej;
 	__u16		srej_save_reqseq;
+	__u16		last_acked_seq;
 	__u16		frames_sent;
 	__u16		unacked_frames;
 	__u8		retry_count;
-	__u8		num_acked;
+	__u16		srej_queue_next;
 	__u16		sdu_len;
 	struct sk_buff	*sdu;
 	struct sk_buff	*sdu_last_frag;
+	atomic_t	ertm_queued;
 
 	__u16		remote_tx_win;
 	__u8		remote_max_tx;

include/net/bluetooth/l2cap.h struct l2cap_chan { · line 506

Quoted 4 lines
include/net/bluetooth/l2cap.h +1 -0
@@ -486,11 +503,13 @@ struct l2cap_chan {
 	struct delayed_work	retrans_timer;
 	struct delayed_work	monitor_timer;
 	struct delayed_work	ack_timer;
+	struct work_struct	tx_work;

Do we really need another work in the L2CAP code?

Quoted 13 lines
include/net/bluetooth/l2cap.h +2 -1
 	struct sk_buff		*tx_send_head;
 	struct sk_buff_head	tx_q;
 	struct sk_buff_head	srej_q;
-	struct list_head	srej_l;
+	struct l2cap_seq_list	srej_list;
+	struct l2cap_seq_list	retrans_list;
 
 	struct list_head list;
 	struct list_head global_l;
@@ -645,200 +664,43 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
 
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 656

Quoted 10 lines
include/net/bluetooth/l2cap.h +0 -9
 #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
-#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
-		msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
-#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
-#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
-		msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
-#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
-#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
-		msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
-#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)

So, I was expecting a patch that we could build without the l2cap.c code so we could apply it and move on, but this one completely breaks the build.

Also I noted that you just turned some of macros here in functions in l2cap.c. Why? Keep those as is for the next round of patches, no unnecessary changes here.

Quoted 175 lines
include/net/bluetooth/l2cap.h +0 -174
-
-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;
-
-	sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
-
-	if (sub < 0)
-		sub += 64;
-
-	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;
-}
-
-static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
-						L2CAP_EXT_CTRL_TXSEQ_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
-}
-
-static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
-							L2CAP_EXT_CTRL_TXSEQ;
-	else
-		return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
-}
-
-static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
-	else
-		return ctrl & L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u32 __set_sframe(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_FRAME_TYPE;
-	else
-		return L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
-}
 
-static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
-	else
-		return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
-}
-
-static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
-{
-	return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
-}
-
-static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_SAR;
-	else
-		return L2CAP_CTRL_SAR;
-}
-
-static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
-						L2CAP_EXT_CTRL_SUPER_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
-}
-
-static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
-						L2CAP_EXT_CTRL_SUPERVISE;
-	else
-		return (super << L2CAP_CTRL_SUPER_SHIFT) &
-							L2CAP_CTRL_SUPERVISE;
-}
-
-static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_FINAL;
-	else
-		return L2CAP_CTRL_FINAL;
-}
-
-static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_FINAL;
-	else
-		return ctrl & L2CAP_CTRL_FINAL;
-}
-
-static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_POLL;
-	else
-		return L2CAP_CTRL_POLL;
-}
-
-static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_POLL;
-	else
-		return ctrl & L2CAP_CTRL_POLL;
-}
-
-static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return get_unaligned_le32(p);
-	else
-		return get_unaligned_le16(p);
-}
-
-static inline 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

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 841

Quoted 10 lines
include/net/bluetooth/l2cap.h +0 -10
-		return put_unaligned_le16(control, p);
-}
-
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
-	else
-		return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
-}

Are we going to replace the Extended Window Size implemetation too?

Quoted 14 lines
include/net/bluetooth/l2cap.h +14 -0
+#define L2CAP_SEQ_LIST_CLEAR       0xFFFF
+#define L2CAP_SEQ_LIST_TAIL        0x8000
+
+#define L2CAP_ERTM_TX_STATE_XMIT          0x01
+#define L2CAP_ERTM_TX_STATE_WAIT_F        0x02
+
+#define L2CAP_ERTM_RX_STATE_RECV                    0x01
+#define L2CAP_ERTM_RX_STATE_SREJ_SENT               0x02
+
+#define L2CAP_ERTM_TXSEQ_EXPECTED        0x00
+#define L2CAP_ERTM_TXSEQ_EXPECTED_SREJ   0x01
+#define L2CAP_ERTM_TXSEQ_UNEXPECTED      0x02
+#define L2CAP_ERTM_TXSEQ_UNEXPECTED_SREJ 0x03
+#define L2CAP_ERTM_TXSEQ_DUPLICATE       0x04

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 691

Quoted 10 lines
include/net/bluetooth/l2cap.h +10 -0
+#define L2CAP_ERTM_TXSEQ_DUPLICATE_SREJ  0x05
+#define L2CAP_ERTM_TXSEQ_INVALID         0x06
+#define L2CAP_ERTM_TXSEQ_INVALID_IGNORE  0x07
+
+#define L2CAP_ERTM_EVENT_DATA_REQUEST          0x01
+#define L2CAP_ERTM_EVENT_LOCAL_BUSY_DETECTED   0x02
+#define L2CAP_ERTM_EVENT_LOCAL_BUSY_CLEAR      0x03
+#define L2CAP_ERTM_EVENT_RECV_REQSEQ_AND_FBIT  0x04
+#define L2CAP_ERTM_EVENT_RECV_FBIT             0x05
+#define L2CAP_ERTM_EVENT_RETRANS_TIMER_EXPIRES 0x06
			...RETRANS_TO

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 692

Quoted 1 line
include/net/bluetooth/l2cap.h +1 -0
+#define L2CAP_ERTM_EVENT_MONITOR_TIMER_EXPIRES 0x07
			...MONITOR_TO

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 699

Quoted 7 lines
include/net/bluetooth/l2cap.h +7 -0
+#define L2CAP_ERTM_EVENT_EXPLICIT_POLL         0x08
+#define L2CAP_ERTM_EVENT_RECV_IFRAME           0x09
+#define L2CAP_ERTM_EVENT_RECV_RR               0x0a
+#define L2CAP_ERTM_EVENT_RECV_REJ              0x0b
+#define L2CAP_ERTM_EVENT_RECV_RNR              0x0c
+#define L2CAP_ERTM_EVENT_RECV_SREJ             0x0d
+#define L2CAP_ERTM_EVENT_RECV_FRAME            0x0e

When we started ERTM we decided to let "_ERTM_" out of the macro names, can we go that way? Shorter names are better.

Also s/EVENT/EV/

Gustavo

#11 lore raw

Re: [RFC 1/2] Bluetooth: Header changes for ERTM state machine replacement

Quoted 24 lines · Gustavo Padovan

Hi Mat,

Quoted 20 lines · Mat Martineau

This change affects data structures storing ERTM state and control fields, and adds new definitions for states and events. An l2cap_seq_list structure is added for tracking ERTM sequence numbers without repeated memory allocations. Control fields are carried in the bt_skb_cb struct rather than constantly doing shift and mask operations.

---
 include/net/bluetooth/bluetooth.h |   14 ++-
 include/net/bluetooth/l2cap.h     |  260 +++++++++----------------------------
 2 files changed, 73 insertions(+), 201 deletions(-)
include/net/bluetooth/bluetooth.h +0 -0
index 262ebd1..a667cb8 100644
@@ -215,14 +215,24 @@ void bt_accept_unlink(struct sock *sk);
 struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
 
Quoted 4 lines

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 218

Quoted 2 lines
include/net/bluetooth/bluetooth.h +1 -0
 /* Skb helpers */
+struct bt_l2cap_control {

I would call this struct l2cap_ctrl only. Much smaller.

Ok.

Quoted 12 lines

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 219

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u8  frame_type;

This could be frame_type:1, only one bit is needed here.

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 220

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u8  final;

final:1

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 221

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u8  sar;

sar:2

Quoted 6 lines

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 222

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u8  super;

super:2

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 223

Quoted 1 line
include/net/bluetooth/bluetooth.h +1 -0
+	__u16 reqseq;

go on..

Will convert to a bitfield.

Quoted 6 lines
Quoted 6 lines
include/net/bluetooth/bluetooth.h +5 -0
+	__u16 txseq;
+	__u8  poll;
+	__u8  fcs;
+};
+
 struct bt_skb_cb {
Quoted 8 lines

include/net/bluetooth/bluetooth.h void bt_accept_unlink(struct sock *sk); · line 233

Quoted 5 lines
include/net/bluetooth/bluetooth.h +0 -1
 	__u8 pkt_type;
 	__u8 incoming;
 	__u16 expect;
-	__u16 tx_seq;
 	__u8 retries;

I would put retries inside l2cap_ctrl. It says how many times we sent that frame, looks a type of information that fits there.

Sure. That l2cap_ctrl struct was originally just ERTM control field stuff, but fcs got in there. retries might as well too.

Quoted 6 lines
Quoted 6 lines
include/net/bluetooth/bluetooth.h +1 -1
-	__u8 sar;
 	__u8 force_active;
+	struct bt_l2cap_control control;
 };
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
 
Quoted 11 lines

include/net/bluetooth/l2cap.h line 6

Quoted 9 lines
include/net/bluetooth/l2cap.h +1 -0
index d6d8ec8..a499b60 100644
@@ -3,6 +3,7 @@
    Copyright (C) 2000-2001 Qualcomm Incorporated
    Copyright (C) 2009-2010 Gustavo F. Padovan <[email protected]>
    Copyright (C) 2010 Google Inc.
+   Copyright (c) 2012 Code Aurora Forum.  All rights reserved.

Leave the Copyright note to when you really add code to l2cap.c

Ok.

Quoted 46 lines
Quoted 46 lines
include/net/bluetooth/l2cap.h +9 -0
    Written 2000,2001 by Maxim Krasnyansky <[email protected]>
 
@@ -44,6 +45,9 @@
 #define L2CAP_DEFAULT_MAX_SDU_SIZE	0xFFFF
 #define L2CAP_DEFAULT_SDU_ITIME		0xFFFFFFFF
 #define L2CAP_DEFAULT_ACC_LAT		0xFFFFFFFF
+#define L2CAP_BREDR_MAX_PAYLOAD		1019    /* 3-DH5 packet */
+#define L2CAP_MAX_ERTM_QUEUED		5
+#define L2CAP_MIN_ERTM_QUEUED		2
 
 #define L2CAP_DISC_TIMEOUT             (100)
 #define L2CAP_DISC_REJ_TIMEOUT         (5000)  /*  5 seconds */
@@ -139,6 +143,8 @@ struct l2cap_conninfo {
 
 #define L2CAP_CTRL_TXSEQ_SHIFT		1
 #define L2CAP_CTRL_SUPER_SHIFT		2
+#define L2CAP_CTRL_POLL_SHIFT		4
+#define L2CAP_CTRL_FINAL_SHIFT		7
 #define L2CAP_CTRL_REQSEQ_SHIFT		8
 #define L2CAP_CTRL_SAR_SHIFT		14
 
@@ -152,9 +158,11 @@ struct l2cap_conninfo {
 #define L2CAP_EXT_CTRL_FINAL		0x00000002
 #define L2CAP_EXT_CTRL_FRAME_TYPE	0x00000001 /* I- or S-Frame */
 
+#define L2CAP_EXT_CTRL_FINAL_SHIFT	1
 #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_POLL_SHIFT	18
 #define L2CAP_EXT_CTRL_TXSEQ_SHIFT	18
 
 /* L2CAP Supervisory Function */
@@ -186,6 +194,8 @@ struct l2cap_hdr {
 #define L2CAP_FCS_SIZE		2
 #define L2CAP_SDULEN_SIZE	2
 #define L2CAP_PSMLEN_SIZE	2
+#define L2CAP_ENH_CTRL_SIZE	2
+#define L2CAP_EXT_CTRL_SIZE	4
 
 struct l2cap_cmd_hdr {
 	__u8       code;
@@ -401,9 +411,12 @@ struct l2cap_conn_param_update_rsp {
 #define L2CAP_CONN_PARAM_REJECTED	0x0001
 
Quoted 15 lines

include/net/bluetooth/l2cap.h struct l2cap_conn_param_update_rsp { · line 420

Quoted 11 lines
include/net/bluetooth/l2cap.h +6 -3
 /* ----- L2CAP channels and connections ----- */
-struct srej_list {
-	__u16	tx_seq;
-	struct list_head list;
+struct l2cap_seq_list {
+	__u16 head;
+	__u16 tail;
+	__u16 size;
+	__u16 mask;
+	__u16 *list;
 };

So I looked to the code and saw the big kalloc you do in the list element here that is 256KB if we use the maximum tx_win in both directions. I'm open to ideas here, I don't have any better.

It's pretty useless to have a tx_window any larger than a few hundred packets, if you're worried about maximum allocation maybe we should limit the the tx_window.

There is a tradeoff here, where we do a one-time allocation to ensure that the retransmit and srej lists can be searched in constant time and that list nodes don't have to be alloc'd and freed for every retransmitted packet. With typical tx_windows, it's only a few hundred bytes of overhead.

Quoted 29 lines
Quoted 29 lines
include/net/bluetooth/l2cap.h +6 -2
 struct l2cap_chan {
@@ -446,6 +459,9 @@ struct l2cap_chan {
 	__u16		monitor_timeout;
 	__u16		mps;
 
+	__u8		tx_state;
+	__u8		rx_state;
+
 	unsigned long	conf_state;
 	unsigned long	conn_state;
 	unsigned long	flags;
@@ -454,15 +470,16 @@ struct l2cap_chan {
 	__u16		expected_ack_seq;
 	__u16		expected_tx_seq;
 	__u16		buffer_seq;
-	__u16		buffer_seq_srej;
 	__u16		srej_save_reqseq;
+	__u16		last_acked_seq;
 	__u16		frames_sent;
 	__u16		unacked_frames;
 	__u8		retry_count;
-	__u8		num_acked;
+	__u16		srej_queue_next;
 	__u16		sdu_len;
 	struct sk_buff	*sdu;
 	struct sk_buff	*sdu_last_frag;
+	atomic_t	ertm_queued;
 
Quoted 9 lines

include/net/bluetooth/l2cap.h struct l2cap_chan { · line 506

Quoted 7 lines
include/net/bluetooth/l2cap.h +1 -0
 	__u16		remote_tx_win;
 	__u8		remote_max_tx;
@@ -486,11 +503,13 @@ struct l2cap_chan {
 	struct delayed_work	retrans_timer;
 	struct delayed_work	monitor_timer;
 	struct delayed_work	ack_timer;
+	struct work_struct	tx_work;

Do we really need another work in the L2CAP code?

I'll address this in my reply to your other email.

Quoted 12 lines
Quoted 12 lines
include/net/bluetooth/l2cap.h +2 -1
 	struct sk_buff		*tx_send_head;
 	struct sk_buff_head	tx_q;
 	struct sk_buff_head	srej_q;
-	struct list_head	srej_l;
+	struct l2cap_seq_list	srej_list;
+	struct l2cap_seq_list	retrans_list;
 
 	struct list_head list;
 	struct list_head global_l;
@@ -645,200 +664,43 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
 
Quoted 14 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 656

Quoted 11 lines
include/net/bluetooth/l2cap.h +0 -9
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
-#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
-		msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
-#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
-#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
-		msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
-#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
-#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
-		msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
-#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)

So, I was expecting a patch that we could build without the l2cap.c code so we could apply it and move on, but this one completely breaks the build.

My goal with this patch was to get feedback on some of the names. I'll aim for something independently buildable in the next iteration.

Quoted 2 lines

Also I noted that you just turned some of macros here in functions in l2cap.c. Why? Keep those as is for the next round of patches, no unnecessary changes here.

Some of the updated functions have more code than seems appropriate for a macro, and it seemed best to have them all in one place.

Quoted 179 lines
Quoted 179 lines
include/net/bluetooth/l2cap.h +0 -178
-
-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;
-
-	sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
-
-	if (sub < 0)
-		sub += 64;
-
-	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;
-}
-
-static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
-						L2CAP_EXT_CTRL_TXSEQ_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
-}
-
-static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
-							L2CAP_EXT_CTRL_TXSEQ;
-	else
-		return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
-}
-
-static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
-	else
-		return ctrl & L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u32 __set_sframe(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_FRAME_TYPE;
-	else
-		return L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
-}
 
-static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
-	else
-		return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
-}
-
-static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
-{
-	return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
-}
-
-static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_SAR;
-	else
-		return L2CAP_CTRL_SAR;
-}
-
-static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
-						L2CAP_EXT_CTRL_SUPER_SHIFT;
-	else
-		return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
-}
-
-static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
-						L2CAP_EXT_CTRL_SUPERVISE;
-	else
-		return (super << L2CAP_CTRL_SUPER_SHIFT) &
-							L2CAP_CTRL_SUPERVISE;
-}
-
-static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_FINAL;
-	else
-		return L2CAP_CTRL_FINAL;
-}
-
-static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_FINAL;
-	else
-		return ctrl & L2CAP_CTRL_FINAL;
-}
-
-static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_CTRL_POLL;
-	else
-		return L2CAP_CTRL_POLL;
-}
-
-static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return ctrl & L2CAP_EXT_CTRL_POLL;
-	else
-		return ctrl & L2CAP_CTRL_POLL;
-}
-
-static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return get_unaligned_le32(p);
-	else
-		return get_unaligned_le16(p);
-}
-
-static inline 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 __u8 __ctrl_size(struct l2cap_chan *chan)
Quoted 8 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 841

Quoted 6 lines
include/net/bluetooth/l2cap.h +0 -6
-{
-	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-		return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
-	else
-		return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
-}

Are we going to replace the Extended Window Size implemetation too?

The state machine code makes frequent use of the l2cap_ctrl struct, so all these functions are not needed. All packing and unpacking of the control headers is done one time in one place.

Quoted 18 lines
Quoted 18 lines
include/net/bluetooth/l2cap.h +18 -0
+#define L2CAP_SEQ_LIST_CLEAR       0xFFFF
+#define L2CAP_SEQ_LIST_TAIL        0x8000
+
+#define L2CAP_ERTM_TX_STATE_XMIT          0x01
+#define L2CAP_ERTM_TX_STATE_WAIT_F        0x02
+
+#define L2CAP_ERTM_RX_STATE_RECV                    0x01
+#define L2CAP_ERTM_RX_STATE_SREJ_SENT               0x02
+
+#define L2CAP_ERTM_TXSEQ_EXPECTED        0x00
+#define L2CAP_ERTM_TXSEQ_EXPECTED_SREJ   0x01
+#define L2CAP_ERTM_TXSEQ_UNEXPECTED      0x02
+#define L2CAP_ERTM_TXSEQ_UNEXPECTED_SREJ 0x03
+#define L2CAP_ERTM_TXSEQ_DUPLICATE       0x04
+#define L2CAP_ERTM_TXSEQ_DUPLICATE_SREJ  0x05
+#define L2CAP_ERTM_TXSEQ_INVALID         0x06
+#define L2CAP_ERTM_TXSEQ_INVALID_IGNORE  0x07
+
Quoted 8 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 691

Quoted 6 lines
include/net/bluetooth/l2cap.h +6 -0
+#define L2CAP_ERTM_EVENT_DATA_REQUEST          0x01
+#define L2CAP_ERTM_EVENT_LOCAL_BUSY_DETECTED   0x02
+#define L2CAP_ERTM_EVENT_LOCAL_BUSY_CLEAR      0x03
+#define L2CAP_ERTM_EVENT_RECV_REQSEQ_AND_FBIT  0x04
+#define L2CAP_ERTM_EVENT_RECV_FBIT             0x05
+#define L2CAP_ERTM_EVENT_RETRANS_TIMER_EXPIRES 0x06
			...RETRANS_TO

Ok

Quoted 3 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 692

Quoted 1 line
include/net/bluetooth/l2cap.h +1 -0
+#define L2CAP_ERTM_EVENT_MONITOR_TIMER_EXPIRES 0x07
			...MONITOR_TO

Ok.

Quoted 11 lines

include/net/bluetooth/l2cap.h static inline bool l2cap_clear_timer(struct l2cap_chan *chan, · line 699

Quoted 7 lines
include/net/bluetooth/l2cap.h +7 -0
+#define L2CAP_ERTM_EVENT_EXPLICIT_POLL         0x08
+#define L2CAP_ERTM_EVENT_RECV_IFRAME           0x09
+#define L2CAP_ERTM_EVENT_RECV_RR               0x0a
+#define L2CAP_ERTM_EVENT_RECV_REJ              0x0b
+#define L2CAP_ERTM_EVENT_RECV_RNR              0x0c
+#define L2CAP_ERTM_EVENT_RECV_SREJ             0x0d
+#define L2CAP_ERTM_EVENT_RECV_FRAME            0x0e

When we started ERTM we decided to let "_ERTM_" out of the macro names, can we go that way? Shorter names are better.

Quoted 1 line

Also s/EVENT/EV/

Will do. Thanks for the review.

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

#12 lore raw

RFC 2/2 Bluetooth: L2CAP ERTM state machine replacement

In reply to Mat Martineau

The previous ERTM implementation had a handler for each frame type, and each handler had to figure out what the current state was and handle each frame accordingly.

This implementation has a state machine that chooses an execution path first based on the receive or transmit state, then each state has handlers for the frame types. This is easier to match up with the spec, which is defined similarly.

---

Refer to https://www.codeaurora.org/gitweb/quic/bluetooth/?p=bluetooth-next.git;a=commit;h=bf897e8a45c3eefbb72e5057b0512f4392bffdba

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

#13 lore raw

Re: [RFC 2/2] Bluetooth: L2CAP ERTM state machine replacement

Hi Mat,

Quoted 10 lines · Mat Martineau

The previous ERTM implementation had a handler for each frame type, and each handler had to figure out what the current state was and handle each frame accordingly.

This implementation has a state machine that chooses an execution path first based on the receive or transmit state, then each state has handlers for the frame types. This is easier to match up with the spec, which is defined similarly.

<snip>

@@ -1245,7 +1457,8 @@ int __l2cap_wait_ack(struct sock *sk)

        add_wait_queue(sk_sleep(sk), &wait);
        set_current_state(TASK_INTERRUPTIBLE);
-       while (chan->unacked_frames > 0 && chan->conn) {
+       while (chan->unacked_frames > 0 && chan->conn &&
+               atomic_read(&chan->ertm_queued)) {
                if (!timeo)
                        timeo = HZ/5;

Can we have unacked_frames > 0 and nothing queued? Or have I misinterpreted?

<snip>

+ BT_DBG("Sent txseq %d", (int)control->txseq);

-               skb = skb_queue_next(&chan->tx_q, skb);
+               chan->next_tx_seq = __next_seq(chan->next_tx_seq, chan);
+               chan->frames_sent += 1;
+               sent += 1;

Nitpick here. frames_sent++ and sent++ ? Happens in other places as well so I won't copy all of them here.

<snip>

- if (bt_cb(skb)->retries == 1) {
- chan->unacked_frames++;

+               l2cap_chan_hold(chan);
+               sock_hold(chan->sk);
+               tx_skb->sk = chan->sk;

Do we really need these? Do we always have chan->sk? (We have that in l2cap_ertm_send() and l2cap_ertm_resend()).

<snip>

+ keep_sk = schedule_work(&chan->tx_work);

Would make sense to schedule this in hdev->workqueue?

<snip>

+static void l2cap_ertm_tx_worker(struct work_struct *work)
{

Why do we need this worker?

- int ret;
+ struct l2cap_chan *chan =
+ container_of(work, struct l2cap_chan, tx_work);

- if (!skb_queue_empty(&chan->tx_q))
- chan->tx_send_head = chan->tx_q.next;
+ BT_DBG("%p", chan);

-       chan->next_tx_seq = chan->expected_ack_seq;
-       ret = l2cap_ertm_send(chan);
-       return ret;
+       lock_sock(chan->sk);
+       l2cap_ertm_send(chan);
+       release_sock(chan->sk);

Can't we just use l2cap_chan_lock()/l2cap_chan_unlock() here? (I'm assuming you saw the patches creating a lock in l2cap_chan to protect it) Do we always have sk?

+ sock_put(chan->sk);
+ l2cap_chan_put(chan);
}

<snip>

+static void l2cap_monitor_timeout(struct work_struct *work) +{
+ struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+ monitor_timer.work);
+ struct sock *sk = chan->sk;
+
+ BT_DBG("chan %p", chan);
+
+ lock_sock(sk);
+
+ if (!chan->conn) {

+               release_sock(sk);
+               l2cap_chan_put(chan);
+               return;

+ }
+
+ l2cap_ertm_tx(chan, 0, 0, L2CAP_ERTM_EVENT_MONITOR_TIMER_EXPIRES);
+
+ release_sock(sk);
+ l2cap_chan_put(chan);
+}

Here we might need to use l2cap_chan_lock/unlock instead of lock_sock/release_sock.

+static void l2cap_retrans_timeout(struct work_struct *work) +{
+ struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+ retrans_timer.work);
+ struct sock *sk = chan->sk;
+
+ BT_DBG("chan %p", chan);
+
+ lock_sock(sk);
+
+ if (!chan->conn) {

+               release_sock(sk);
+               l2cap_chan_put(chan);
+               return;
+       }
+
+       l2cap_ertm_tx(chan, 0, 0, L2CAP_ERTM_EVENT_RETRANS_TIMER_EXPIRES);
+       release_sock(sk);
+       l2cap_chan_put(chan);

And here as well.

Ok, that's it for now. Have you run this code through PTS or any other test? I haven't checked the actual bits of ERTM but since we're replacing the current state machine code we need to be somewhat sure this code is as good as or even better than the current one. Introducing too many regressions would be really bad IMHO.

Thanks,
Regards,

Signature · 5 lines
Ulisses Furquim
ProFUSION embedded systems
http://profusion.mobi
Mobile: +55 19 9250 0942
Skype: ulissesffs
#14 lore raw

Re: [RFC 2/2] Bluetooth: L2CAP ERTM state machine replacement

Quoted 26 lines · Ulisses Furquim

Hi Mat,

Quoted 10 lines · Mat Martineau

The previous ERTM implementation had a handler for each frame type, and each handler had to figure out what the current state was and handle each frame accordingly.

This implementation has a state machine that chooses an execution path first based on the receive or transmit state, then each state has handlers for the frame types. This is easier to match up with the spec, which is defined similarly.

<snip>

(quoted diff) +2 -1
@@ -1245,7 +1457,8 @@ int __l2cap_wait_ack(struct sock *sk)
 
         add_wait_queue(sk_sleep(sk),&wait);
         set_current_state(TASK_INTERRUPTIBLE);
-       while (chan->unacked_frames>  0&&  chan->conn) {
+       while (chan->unacked_frames>  0&&  chan->conn&&
+               atomic_read(&chan->ertm_queued)) {
                 if (!timeo)
                         timeo = HZ/5;
 
Quoted 1 line

Can we have unacked_frames> 0 and nothing queued? Or have I misinterpreted?

In normal operation, there should be unacked frames when ertm_queued is non-zero. I think I ran in to a corner case with AMP, where unacked_frames can be forced to 0 during a channel move. There are AMP components to the state machine that are not included in this patch.

Quoted 10 lines

<snip>

(quoted diff) +4 -1
+               BT_DBG("Sent txseq %d", (int)control->txseq);
 
-               skb = skb_queue_next(&chan->tx_q, skb);
+               chan->next_tx_seq = __next_seq(chan->next_tx_seq, chan);
+               chan->frames_sent += 1;
+               sent += 1;
Quoted 2 lines

Nitpick here. frames_sent++ and sent++ ? Happens in other places as well so I won't copy all of them here.

Ok, will fix.

Quoted 11 lines

<snip>

(quoted diff) +3 -2
-               if (bt_cb(skb)->retries == 1) {
-                       chan->unacked_frames++;
+               l2cap_chan_hold(chan);
+               sock_hold(chan->sk);
+               tx_skb->sk = chan->sk;

Do we really need these? Do we always have chan->sk? (We have that in l2cap_ertm_send() and l2cap_ertm_resend()).

The upstream ERTM code still relies on having chan->sk, so I didn't try to finish splitting channels & sockets within this patch. skb destructors expect to have an sk pointer, so it is critical to modify these reference counts so the socket and chan are around when the skb leaves the hci tx queue.

Quoted 6 lines

<snip>

+ keep_sk = schedule_work(&chan->tx_work);

Would make sense to schedule this in hdev->workqueue?

It's a tradeoff. If this is scheduled on hdev->workqueue, then that workqueue can get blocked waiting for the socket lock. If these are scheduled on the system workqueue, there is potential for more latency (but it hasn't been a problem in practice, even with AMP data rates).

Quoted 7 lines

<snip>

+static void l2cap_ertm_tx_worker(struct work_struct *work)
{

Why do we need this worker?

To control the depth of the hci tx queue. Without this, you end up with an entire tx window of iframes queued up at the hci layer. When an sframe shows up from the remote device and you have to retransmit, or when an sframe needs to be sent, then retransmissions and sframes have to get queued behind that full tx window of iframes. It adds a HUGE amount of latency in those situations, which leads to ERTM timeouts and disconnects that are not necessary. ERTM works much, much better with lossy connections (like AMP) if it does not flood the hci tx queue.

We had a discussion on the list about how to solve this. The idea is to push most queuing up to the L2CAP layer, and have the hci scheduler call up to L2CAP to fetch frames. However, this hasn't been implemented yet.

Quoted 16 lines
(quoted diff) +6 -6
-       int ret;
+       struct l2cap_chan *chan =
+               container_of(work, struct l2cap_chan, tx_work);
 
-       if (!skb_queue_empty(&chan->tx_q))
-               chan->tx_send_head = chan->tx_q.next;
+       BT_DBG("%p", chan);
 
-       chan->next_tx_seq = chan->expected_ack_seq;
-       ret = l2cap_ertm_send(chan);
-       return ret;
+       lock_sock(chan->sk);
+       l2cap_ertm_send(chan);
+       release_sock(chan->sk);
Quoted 3 lines

Can't we just use l2cap_chan_lock()/l2cap_chan_unlock() here? (I'm assuming you saw the patches creating a lock in l2cap_chan to protect it) Do we always have sk?

l2cap_chan_lock() is pretty new! Yes, I should use that to guard the ERTM state.

Right now, we do still always have sk, but that is changing (as it should).

Quoted 28 lines
(quoted diff) +23 -0
+       sock_put(chan->sk);
+       l2cap_chan_put(chan);
  }
 
<snip>
 
+static void l2cap_monitor_timeout(struct work_struct *work)
+{
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       monitor_timer.work);
+       struct sock *sk = chan->sk;
+
+       BT_DBG("chan %p", chan);
+
+       lock_sock(sk);
+
+       if (!chan->conn) {
+               release_sock(sk);
+               l2cap_chan_put(chan);
+               return;
+       }
+
+       l2cap_ertm_tx(chan, 0, 0, L2CAP_ERTM_EVENT_MONITOR_TIMER_EXPIRES);
+
+       release_sock(sk);
+       l2cap_chan_put(chan);
+}
Quoted 2 lines

Here we might need to use l2cap_chan_lock/unlock instead of lock_sock/release_sock.

Agreed.

Quoted 21 lines
(quoted diff) +19 -0
+static void l2cap_retrans_timeout(struct work_struct *work)
+{
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       retrans_timer.work);
+       struct sock *sk = chan->sk;
+
+       BT_DBG("chan %p", chan);
+
+       lock_sock(sk);
+
+       if (!chan->conn) {
+               release_sock(sk);
+               l2cap_chan_put(chan);
+               return;
+       }
+
+       l2cap_ertm_tx(chan, 0, 0, L2CAP_ERTM_EVENT_RETRANS_TIMER_EXPIRES);
+       release_sock(sk);
+       l2cap_chan_put(chan);
Quoted 7 lines

And here as well.

Ok, that's it for now. Have you run this code through PTS or any other test? I haven't checked the actual bits of ERTM but since we're replacing the current state machine code we need to be somewhat sure this code is as good as or even better than the current one. Introducing too many regressions would be really bad IMHO.

The kernel I'm porting from is qualified, listed, interop'd, UPF'd, and heavily tested -- but I haven't validated this port yet. I will definitely run this through PTS and test against other ERTM implementations before we merge the changes.

Signature · 3 lines
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
#15 lore raw

Re: [RFC 2/2] Bluetooth: L2CAP ERTM state machine replacement

Hi Mat,

On Fri, Feb 24, 2012 at 10:08 PM, Mat Martineau <[email protected]> wr= ote:

Quoted 32 lines · Ulisses Furquim
Quoted 31 lines

Hi Mat,

Quoted 11 lines · On Thu, Feb 23, 2012 at 6:37 PM, Mat Martineau<[email protected]> =A0wrote:

The previous ERTM implementation had a handler for each frame type, and each handler had to figure out what the current state was and handle each frame accordingly.

This implementation has a state machine that chooses an execution path first based on the receive or transmit state, then each state has handlers for the frame types. This is easier to match up with the spec, which is defined similarly.

<snip>

(quoted diff) +2 -1
@@ -1245,7 +1457,8 @@ int __l2cap_wait_ack(struct sock *sk)
 
 =A0 =A0 =A0 =A0 add_wait_queue(sk_sleep(sk),&wait);
 =A0 =A0 =A0 =A0 set_current_state(TASK_INTERRUPTIBLE);
- =A0 =A0 =A0 while (chan->unacked_frames> =A00&& =A0chan->conn) {
 
+ =A0 =A0 =A0 while (chan->unacked_frames> =A00&& =A0chan->conn&&
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 atomic_read(&chan->ertm_queued)) {
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!timeo)
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 timeo =3D HZ/5;
Quoted 6 lines
Quoted 2 lines

Can we have unacked_frames> =A00 and nothing queued? Or have I misinterpreted?

In normal operation, there should be unacked frames when ertm_queued is non-zero. =A0I think I ran in to a corner case with AMP, where unacked_fr=

ames

Quoted 1 line

can be forced to 0 during a channel move. =A0There are AMP components to =

the

Quoted 1 line

state machine that are not included in this patch.

Ok, I thought you might have a reason for that. Thanks.

Quoted 8 lines
Quoted 8 lines

<snip>

- =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (bt_cb(skb)->retries =3D=3D 1) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 chan->unacked_frames++;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 l2cap_chan_hold(chan);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 sock_hold(chan->sk);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 tx_skb->sk =3D chan->sk;

Quoted 4 lines
Quoted 2 lines

Do we really need these? Do we always have chan->sk? (We have that in l2cap_ertm_send() and l2cap_ertm_resend()).

The upstream ERTM code still relies on having chan->sk, so I didn't try t=

o

Quoted 4 lines

finish splitting channels & sockets within this patch. =A0skb destructors expect to have an sk pointer, so it is critical to modify these reference counts so the socket and chan are around when the skb leaves the hci tx queue.

If I'm not mistaken the skb destructor relies on sk only to be able to access chan, right? It'd be good if we could not rely on sk here. Andrei, what do you think?

Quoted 10 lines
Quoted 6 lines

<snip>

+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 keep_sk =3D schedule_work(&chan->tx_work);

Would make sense to schedule this in hdev->workqueue?

It's a tradeoff. =A0If this is scheduled on hdev->workqueue, then that workqueue can get blocked waiting for the socket lock. =A0If these are scheduled on the system workqueue, there is potential for more latency (b=

ut

Quoted 1 line

it hasn't been a problem in practice, even with AMP data rates).

Hmm. I just was wondering if we don't have any problems with tasks in both worqueues running simultaneously.

Quoted 9 lines
Quoted 7 lines

<snip>

+static void l2cap_ertm_tx_worker(struct work_struct *work) =A0{

Why do we need this worker?

To control the depth of the hci tx queue. =A0Without this, you end up wit=

h an

Quoted 3 lines

entire tx window of iframes queued up at the hci layer. =A0When an sframe shows up from the remote device and you have to retransmit, or when an sframe needs to be sent, then retransmissions and sframes have to get que=

ued

Quoted 1 line

behind that full tx window of iframes. =A0It adds a HUGE amount of latenc=

y in

Quoted 1 line

those situations, which leads to ERTM timeouts and disconnects that are n=

ot

Quoted 1 line

necessary. =A0ERTM works much, much better with lossy connections (like A=

MP)

Quoted 1 line

if it does not flood the hci tx queue.

Ok.

Quoted 1 line

We had a discussion on the list about how to solve this. =A0The idea is t=

o

Quoted 1 line

push most queuing up to the L2CAP layer, and have the hci scheduler call =

up

Quoted 1 line

to L2CAP to fetch frames. =A0However, this hasn't been implemented yet.

I see.

Quoted 4 lines
Quoted 4 lines

- =A0 =A0 =A0 int ret;
+ =A0 =A0 =A0 struct l2cap_chan *chan =3D
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 container_of(work, struct l2cap_chan, tx_w=

ork);

Quoted 12 lines
Quoted 12 lines

- =A0 =A0 =A0 if (!skb_queue_empty(&chan->tx_q))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 chan->tx_send_head =3D chan->tx_q.next;
+ =A0 =A0 =A0 BT_DBG("%p", chan);

- =A0 =A0 =A0 chan->next_tx_seq =3D chan->expected_ack_seq;
- =A0 =A0 =A0 ret =3D l2cap_ertm_send(chan);
- =A0 =A0 =A0 return ret;
+ =A0 =A0 =A0 lock_sock(chan->sk);
+ =A0 =A0 =A0 l2cap_ertm_send(chan);
+ =A0 =A0 =A0 release_sock(chan->sk);

Quoted 5 lines
Quoted 3 lines

Can't we just use l2cap_chan_lock()/l2cap_chan_unlock() here? (I'm assuming you saw the patches creating a lock in l2cap_chan to protect it) Do we always have sk?

l2cap_chan_lock() is pretty new! =A0Yes, I should use that to guard the E=

RTM

Quoted 3 lines

state.

Right now, we do still always have sk, but that is changing (as it should=

).

Ok. If we could not rely on sk here as well would be good.

Quoted 9 lines

Review

Quoted 9 lines

+ =A0 =A0 =A0 sock_put(chan->sk);
+ =A0 =A0 =A0 l2cap_chan_put(chan);
=A0}

<snip>

(quoted diff) +3 -0
+static void l2cap_monitor_timeout(struct work_struct *work)
+{
+ =A0 =A0 =A0 struct l2cap_chan *chan =3D container_of(work, struct l2ca=

p_chan,

Quoted 7 lines
Quoted 7 lines

+
monitor_timer.work);
+ =A0 =A0 =A0 struct sock *sk =3D chan->sk;

(quoted diff) +4 -0
+
+ =A0 =A0 =A0 BT_DBG("chan %p", chan);
+
+ =A0 =A0 =A0 lock_sock(sk);
Quoted 8 lines

Review

Quoted 8 lines
(quoted diff) +8 -0
+
+ =A0 =A0 =A0 if (!chan->conn) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_sock(sk);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 l2cap_chan_put(chan);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
+ =A0 =A0 =A0 }
+
+ =A0 =A0 =A0 l2cap_ertm_tx(chan, 0, 0, L2CAP_ERTM_EVENT_MONITOR_TIMER_E=

XPIRES);

Quoted 13 lines
Quoted 7 lines
(quoted diff) +4 -0
+
+ =A0 =A0 =A0 release_sock(sk);
+ =A0 =A0 =A0 l2cap_chan_put(chan);
+}

Here we might need to use l2cap_chan_lock/unlock instead of lock_sock/release_sock.

Agreed.

Quoted 1 line
Quoted 3 lines

Review

Quoted 3 lines
(quoted diff) +3 -0
+static void l2cap_retrans_timeout(struct work_struct *work)
+{
+ =A0 =A0 =A0 struct l2cap_chan *chan =3D container_of(work, struct l2ca=

p_chan,

Quoted 7 lines
Quoted 7 lines

+
retrans_timer.work);
+ =A0 =A0 =A0 struct sock *sk =3D chan->sk;

(quoted diff) +4 -0
+
+ =A0 =A0 =A0 BT_DBG("chan %p", chan);
+
+ =A0 =A0 =A0 lock_sock(sk);
Quoted 8 lines

Review

Quoted 8 lines
(quoted diff) +8 -0
+
+ =A0 =A0 =A0 if (!chan->conn) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_sock(sk);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 l2cap_chan_put(chan);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
+ =A0 =A0 =A0 }
+
+ =A0 =A0 =A0 l2cap_ertm_tx(chan, 0, 0, L2CAP_ERTM_EVENT_RETRANS_TIMER_E=

XPIRES);

Quoted 12 lines
Quoted 10 lines

+ =A0 =A0 =A0 release_sock(sk);
+ =A0 =A0 =A0 l2cap_chan_put(chan);

And here as well.

Ok, that's it for now. Have you run this code through PTS or any other test? I haven't checked the actual bits of ERTM but since we're replacing the current state machine code we need to be somewhat sure this code is as good as or even better than the current one. Introducing too many regressions would be really bad IMHO.

Quoted 2 lines

The kernel I'm porting from is qualified, listed, interop'd, UPF'd, and heavily tested -- but I haven't validated this port yet. =A0I will defini=

tely

Quoted 1 line

run this through PTS and test against other ERTM implementations before w=

e

Quoted 1 line

merge the changes.

I'm aware your kernel is on a very good state but as you said this is a port to upstream. And that's why I also said "too many regressions" because some we might not be able to see now. And running through PTS and maybe against your qualified kernel would be good, yes.

Thank you,
Best regards,

--=20
Ulisses Furquim
ProFUSION embedded systems
http://profusion.mobi
Mobile: +55 19 9250 0942
Skype: ulissesffs

#16 lore raw

Re: [RFC 2/2] Bluetooth: L2CAP ERTM state machine replacement

Hi all,

Quoted 17 lines · Ulisses Furquim
Quoted 8 lines
Quoted 8 lines

<snip>

-               if (bt_cb(skb)->retries == 1) {
-                       chan->unacked_frames++;
+               l2cap_chan_hold(chan);
+               sock_hold(chan->sk);
+               tx_skb->sk = chan->sk;

Quoted 8 lines
Quoted 2 lines

Do we really need these? Do we always have chan->sk? (We have that in l2cap_ertm_send() and l2cap_ertm_resend()).

The upstream ERTM code still relies on having chan->sk, so I didn't try to finish splitting channels & sockets within this patch.  skb destructors expect to have an sk pointer, so it is critical to modify these reference counts so the socket and chan are around when the skb leaves the hci tx queue.

Quoted 3 lines

If I'm not mistaken the skb destructor relies on sk only to be able to access chan, right? It'd be good if we could not rely on sk here. Andrei, what do you think?

I believe that ERTM should not use sk. The places where we still use sk shall be corrected IMO.

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines

-       int ret;
+       struct l2cap_chan *chan =
+               container_of(work, struct l2cap_chan, tx_work);

-       if (!skb_queue_empty(&chan->tx_q))
-               chan->tx_send_head = chan->tx_q.next;
+       BT_DBG("%p", chan);

-       chan->next_tx_seq = chan->expected_ack_seq;
-       ret = l2cap_ertm_send(chan);
-       return ret;
+       lock_sock(chan->sk);
+       l2cap_ertm_send(chan);
+       release_sock(chan->sk);

Can't we just use l2cap_chan_lock()/l2cap_chan_unlock() here? (I'm assuming you saw the patches creating a lock in l2cap_chan to protect it) Do we always have sk?

Quoted 6 lines
Quoted 4 lines

l2cap_chan_lock() is pretty new!  Yes, I should use that to guard the ERTM state.

Right now, we do still always have sk, but that is changing (as it should).

Ok. If we could not rely on sk here as well would be good.

Good that we agree here.

Best regards
Andrei Emeltchenko

#17 lore raw

Re: [RFC 2/2] Bluetooth: L2CAP ERTM state machine replacement

In reply to Mat Martineau

Hi Mat,

Quoted 99 lines · Mat Martineau
Quoted 26 lines · Ulisses Furquim

Hi Mat,

Quoted 10 lines · Mat Martineau

The previous ERTM implementation had a handler for each frame type, and each handler had to figure out what the current state was and handle each frame accordingly.

This implementation has a state machine that chooses an execution path first based on the receive or transmit state, then each state has handlers for the frame types. This is easier to match up with the spec, which is defined similarly.

<snip>

(quoted diff) +2 -1
@@ -1245,7 +1457,8 @@ int __l2cap_wait_ack(struct sock *sk)
 
        add_wait_queue(sk_sleep(sk),&wait);
        set_current_state(TASK_INTERRUPTIBLE);
-       while (chan->unacked_frames>  0&&  chan->conn) {
+       while (chan->unacked_frames>  0&&  chan->conn&&
+               atomic_read(&chan->ertm_queued)) {
                if (!timeo)
                        timeo = HZ/5;
 
Quoted 1 line

Can we have unacked_frames> 0 and nothing queued? Or have I misinterpreted?

In normal operation, there should be unacked frames when ertm_queued is non-zero. I think I ran in to a corner case with AMP, where unacked_frames can be forced to 0 during a channel move. There are AMP components to the state machine that are not included in this patch.

Quoted 10 lines

<snip>

(quoted diff) +4 -1
+               BT_DBG("Sent txseq %d", (int)control->txseq);
 
-               skb = skb_queue_next(&chan->tx_q, skb);
+               chan->next_tx_seq = __next_seq(chan->next_tx_seq, chan);
+               chan->frames_sent += 1;
+               sent += 1;
Quoted 2 lines

Nitpick here. frames_sent++ and sent++ ? Happens in other places as well so I won't copy all of them here.

Ok, will fix.

Quoted 11 lines

<snip>

(quoted diff) +3 -2
-               if (bt_cb(skb)->retries == 1) {
-                       chan->unacked_frames++;
+               l2cap_chan_hold(chan);
+               sock_hold(chan->sk);
+               tx_skb->sk = chan->sk;

Do we really need these? Do we always have chan->sk? (We have that in l2cap_ertm_send() and l2cap_ertm_resend()).

The upstream ERTM code still relies on having chan->sk, so I didn't try to finish splitting channels & sockets within this patch. skb destructors expect to have an sk pointer, so it is critical to modify these reference counts so the socket and chan are around when the skb leaves the hci tx queue.

Quoted 6 lines

<snip>

+ keep_sk = schedule_work(&chan->tx_work);

Would make sense to schedule this in hdev->workqueue?

It's a tradeoff. If this is scheduled on hdev->workqueue, then that workqueue can get blocked waiting for the socket lock. If these are scheduled on the system workqueue, there is potential for more latency (but it hasn't been a problem in practice, even with AMP data rates).

Quoted 7 lines

<snip>

+static void l2cap_ertm_tx_worker(struct work_struct *work)
{

Why do we need this worker?

To control the depth of the hci tx queue. Without this, you end up with an entire tx window of iframes queued up at the hci layer. When an sframe shows up from the remote device and you have to retransmit, or when an sframe needs to be sent, then retransmissions and sframes have to get queued behind that full tx window of iframes. It adds a HUGE amount of latency in those situations, which leads to ERTM timeouts and disconnects that are not necessary. ERTM works much, much better with lossy connections (like AMP) if it does not flood the hci tx queue.

Quoted 4 lines

We had a discussion on the list about how to solve this. The idea is to push most queuing up to the L2CAP layer, and have the hci scheduler call up to L2CAP to fetch frames. However, this hasn't been implemented yet.

Ok, I can see why you added tx_work now. We really need to move to the new proposal here.

Also I think the most important thing here is not point out wrong stuff in this huge patch but find ways to split it in many patches. If we could get a cleaner and rebased patch fixing the unnecessary renames and functions move, etc. that would be good for us. :)

Gustavo

#18 lore raw

Re: [RFC 2/2] Bluetooth: L2CAP ERTM state machine replacement

Quoted 103 lines · Gustavo Padovan

Hi Mat,

Quoted 99 lines · Mat Martineau
Quoted 26 lines · Ulisses Furquim

Hi Mat,

Quoted 10 lines · Mat Martineau

The previous ERTM implementation had a handler for each frame type, and each handler had to figure out what the current state was and handle each frame accordingly.

This implementation has a state machine that chooses an execution path first based on the receive or transmit state, then each state has handlers for the frame types. This is easier to match up with the spec, which is defined similarly.

<snip>

(quoted diff) +2 -1
@@ -1245,7 +1457,8 @@ int __l2cap_wait_ack(struct sock *sk)
 
        add_wait_queue(sk_sleep(sk),&wait);
        set_current_state(TASK_INTERRUPTIBLE);
-       while (chan->unacked_frames>  0&&  chan->conn) {
+       while (chan->unacked_frames>  0&&  chan->conn&&
+               atomic_read(&chan->ertm_queued)) {
                if (!timeo)
                        timeo = HZ/5;
 
Quoted 1 line

Can we have unacked_frames> 0 and nothing queued? Or have I misinterpreted?

In normal operation, there should be unacked frames when ertm_queued is non-zero. I think I ran in to a corner case with AMP, where unacked_frames can be forced to 0 during a channel move. There are AMP components to the state machine that are not included in this patch.

Quoted 10 lines

<snip>

(quoted diff) +4 -1
+               BT_DBG("Sent txseq %d", (int)control->txseq);
 
-               skb = skb_queue_next(&chan->tx_q, skb);
+               chan->next_tx_seq = __next_seq(chan->next_tx_seq, chan);
+               chan->frames_sent += 1;
+               sent += 1;
Quoted 2 lines

Nitpick here. frames_sent++ and sent++ ? Happens in other places as well so I won't copy all of them here.

Ok, will fix.

Quoted 11 lines

<snip>

(quoted diff) +3 -2
-               if (bt_cb(skb)->retries == 1) {
-                       chan->unacked_frames++;
+               l2cap_chan_hold(chan);
+               sock_hold(chan->sk);
+               tx_skb->sk = chan->sk;

Do we really need these? Do we always have chan->sk? (We have that in l2cap_ertm_send() and l2cap_ertm_resend()).

The upstream ERTM code still relies on having chan->sk, so I didn't try to finish splitting channels & sockets within this patch. skb destructors expect to have an sk pointer, so it is critical to modify these reference counts so the socket and chan are around when the skb leaves the hci tx queue.

Quoted 6 lines

<snip>

+ keep_sk = schedule_work(&chan->tx_work);

Would make sense to schedule this in hdev->workqueue?

It's a tradeoff. If this is scheduled on hdev->workqueue, then that workqueue can get blocked waiting for the socket lock. If these are scheduled on the system workqueue, there is potential for more latency (but it hasn't been a problem in practice, even with AMP data rates).

Quoted 7 lines

<snip>

+static void l2cap_ertm_tx_worker(struct work_struct *work)
{

Why do we need this worker?

To control the depth of the hci tx queue. Without this, you end up with an entire tx window of iframes queued up at the hci layer. When an sframe shows up from the remote device and you have to retransmit, or when an sframe needs to be sent, then retransmissions and sframes have to get queued behind that full tx window of iframes. It adds a HUGE amount of latency in those situations, which leads to ERTM timeouts and disconnects that are not necessary. ERTM works much, much better with lossy connections (like AMP) if it does not flood the hci tx queue.

Quoted 7 lines
Quoted 4 lines

We had a discussion on the list about how to solve this. The idea is to push most queuing up to the L2CAP layer, and have the hci scheduler call up to L2CAP to fetch frames. However, this hasn't been implemented yet.

Ok, I can see why you added tx_work now. We really need to move to the new proposal here.

I was hoping we could use this callback method for now, then implement the new proposal. It seems better to have ERTM working well from the start. Both designs have callbacks to L2CAP (this one actually makes fewer callbacks). If you want me to rip out the skb destructor callbacks, I can do it now.

Quoted 4 lines

Also I think the most important thing here is not point out wrong stuff in this huge patch but find ways to split it in many patches. If we could get a cleaner and rebased patch fixing the unnecessary renames and functions move, etc. that would be good for us. :)

Now that I have the input for l2cap.h, I'll update l2cap_core.c and start splitting it up. My understanding from earlier discussion of this ERTM change is that there are a few independent changes that can be added without breaking the current ERTM implementation, but the big changes will have to add inactive code in parallel. After all the code is there, we will make it active and remove the old code. Let me know if I've misunderstood.

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

maintainer
#19 lore raw

Re: [RFC 2/2] Bluetooth: L2CAP ERTM state machine replacement

Hi Mat,

Quoted 101 lines
Quoted 101 lines
Quoted 100 lines
Quoted 24 lines · Mat Martineau
Quoted 10 lines

The previous ERTM implementation had a handler for each frame type, and each handler had to figure out what the current state was and handle each frame accordingly.

This implementation has a state machine that chooses an execution path first based on the receive or transmit state, then each state has handlers for the frame types. This is easier to match up with the spec, which is defined similarly.

<snip>

(quoted diff) +2 -1
@@ -1245,7 +1457,8 @@ int __l2cap_wait_ack(struct sock *sk)
 
        add_wait_queue(sk_sleep(sk),&wait);
        set_current_state(TASK_INTERRUPTIBLE);
-       while (chan->unacked_frames>  0&&  chan->conn) {
+       while (chan->unacked_frames>  0&&  chan->conn&&
+               atomic_read(&chan->ertm_queued)) {
                if (!timeo)
                        timeo = HZ/5;
 
Quoted 1 line

Can we have unacked_frames> 0 and nothing queued? Or have I misinterpreted?

In normal operation, there should be unacked frames when ertm_queued is non-zero. I think I ran in to a corner case with AMP, where unacked_frames can be forced to 0 during a channel move. There are AMP components to the state machine that are not included in this patch.

Quoted 10 lines

<snip>

(quoted diff) +4 -1
+               BT_DBG("Sent txseq %d", (int)control->txseq);
 
-               skb = skb_queue_next(&chan->tx_q, skb);
+               chan->next_tx_seq = __next_seq(chan->next_tx_seq, chan);
+               chan->frames_sent += 1;
+               sent += 1;
Quoted 2 lines

Nitpick here. frames_sent++ and sent++ ? Happens in other places as well so I won't copy all of them here.

Ok, will fix.

Quoted 11 lines

<snip>

(quoted diff) +3 -2
-               if (bt_cb(skb)->retries == 1) {
-                       chan->unacked_frames++;
+               l2cap_chan_hold(chan);
+               sock_hold(chan->sk);
+               tx_skb->sk = chan->sk;

Do we really need these? Do we always have chan->sk? (We have that in l2cap_ertm_send() and l2cap_ertm_resend()).

The upstream ERTM code still relies on having chan->sk, so I didn't try to finish splitting channels & sockets within this patch. skb destructors expect to have an sk pointer, so it is critical to modify these reference counts so the socket and chan are around when the skb leaves the hci tx queue.

Quoted 6 lines

<snip>

+ keep_sk = schedule_work(&chan->tx_work);

Would make sense to schedule this in hdev->workqueue?

It's a tradeoff. If this is scheduled on hdev->workqueue, then that workqueue can get blocked waiting for the socket lock. If these are scheduled on the system workqueue, there is potential for more latency (but it hasn't been a problem in practice, even with AMP data rates).

Quoted 7 lines

<snip>

+static void l2cap_ertm_tx_worker(struct work_struct *work)
{

Why do we need this worker?

To control the depth of the hci tx queue. Without this, you end up with an entire tx window of iframes queued up at the hci layer. When an sframe shows up from the remote device and you have to retransmit, or when an sframe needs to be sent, then retransmissions and sframes have to get queued behind that full tx window of iframes. It adds a HUGE amount of latency in those situations, which leads to ERTM timeouts and disconnects that are not necessary. ERTM works much, much better with lossy connections (like AMP) if it does not flood the hci tx queue.

We had a discussion on the list about how to solve this. The idea is to push most queuing up to the L2CAP layer, and have the hci scheduler call up to L2CAP to fetch frames. However, this hasn't been implemented yet.

Quoted 8 lines
Quoted 2 lines

Ok, I can see why you added tx_work now. We really need to move to the new proposal here.

I was hoping we could use this callback method for now, then implement the new proposal. It seems better to have ERTM working well from the start. Both designs have callbacks to L2CAP (this one actually makes fewer callbacks). If you want me to rip out the skb destructor callbacks, I can do it now.

how much effort would it be? I am fine with doing this a little bit later on if this would take too much time. Give me an idea how complicated the change would be at this time.

Quoted 5 lines
Quoted 4 lines

Also I think the most important thing here is not point out wrong stuff in this huge patch but find ways to split it in many patches. If we could get a cleaner and rebased patch fixing the unnecessary renames and functions move, etc. that would be good for us. :)

Quoted 7 lines

Now that I have the input for l2cap.h, I'll update l2cap_core.c and start splitting it up. My understanding from earlier discussion of this ERTM change is that there are a few independent changes that can be added without breaking the current ERTM implementation, but the big changes will have to add inactive code in parallel. After all the code is there, we will make it active and remove the old code. Let me know if I've misunderstood.

That sounds perfectly fine to. Small changes that can be done right now without breaking the current code should go in right away. Like some renaming, moving of code, cleanup and so.

After that, lets add the extra code you need, activate it, and then delete the unused code.

Regards

Marcel

#20 lore raw

Re: [RFC 2/2] Bluetooth: L2CAP ERTM state machine replacement

Quoted 112 lines · Marcel Holtmann

Hi Mat,

Quoted 101 lines
Quoted 101 lines
Quoted 100 lines
Quoted 24 lines · Mat Martineau
Quoted 10 lines

The previous ERTM implementation had a handler for each frame type, and each handler had to figure out what the current state was and handle each frame accordingly.

This implementation has a state machine that chooses an execution path first based on the receive or transmit state, then each state has handlers for the frame types. This is easier to match up with the spec, which is defined similarly.

<snip>

(quoted diff) +2 -1
@@ -1245,7 +1457,8 @@ int __l2cap_wait_ack(struct sock *sk)
 
        add_wait_queue(sk_sleep(sk),&wait);
        set_current_state(TASK_INTERRUPTIBLE);
-       while (chan->unacked_frames>  0&&  chan->conn) {
+       while (chan->unacked_frames>  0&&  chan->conn&&
+               atomic_read(&chan->ertm_queued)) {
                if (!timeo)
                        timeo = HZ/5;
 
Quoted 1 line

Can we have unacked_frames> 0 and nothing queued? Or have I misinterpreted?

In normal operation, there should be unacked frames when ertm_queued is non-zero. I think I ran in to a corner case with AMP, where unacked_frames can be forced to 0 during a channel move. There are AMP components to the state machine that are not included in this patch.

Quoted 10 lines

<snip>

(quoted diff) +4 -1
+               BT_DBG("Sent txseq %d", (int)control->txseq);
 
-               skb = skb_queue_next(&chan->tx_q, skb);
+               chan->next_tx_seq = __next_seq(chan->next_tx_seq, chan);
+               chan->frames_sent += 1;
+               sent += 1;
Quoted 2 lines

Nitpick here. frames_sent++ and sent++ ? Happens in other places as well so I won't copy all of them here.

Ok, will fix.

Quoted 11 lines

<snip>

(quoted diff) +3 -2
-               if (bt_cb(skb)->retries == 1) {
-                       chan->unacked_frames++;
+               l2cap_chan_hold(chan);
+               sock_hold(chan->sk);
+               tx_skb->sk = chan->sk;

Do we really need these? Do we always have chan->sk? (We have that in l2cap_ertm_send() and l2cap_ertm_resend()).

The upstream ERTM code still relies on having chan->sk, so I didn't try to finish splitting channels & sockets within this patch. skb destructors expect to have an sk pointer, so it is critical to modify these reference counts so the socket and chan are around when the skb leaves the hci tx queue.

Quoted 6 lines

<snip>

+ keep_sk = schedule_work(&chan->tx_work);

Would make sense to schedule this in hdev->workqueue?

It's a tradeoff. If this is scheduled on hdev->workqueue, then that workqueue can get blocked waiting for the socket lock. If these are scheduled on the system workqueue, there is potential for more latency (but it hasn't been a problem in practice, even with AMP data rates).

Quoted 7 lines

<snip>

+static void l2cap_ertm_tx_worker(struct work_struct *work)
{

Why do we need this worker?

To control the depth of the hci tx queue. Without this, you end up with an entire tx window of iframes queued up at the hci layer. When an sframe shows up from the remote device and you have to retransmit, or when an sframe needs to be sent, then retransmissions and sframes have to get queued behind that full tx window of iframes. It adds a HUGE amount of latency in those situations, which leads to ERTM timeouts and disconnects that are not necessary. ERTM works much, much better with lossy connections (like AMP) if it does not flood the hci tx queue.

We had a discussion on the list about how to solve this. The idea is to push most queuing up to the L2CAP layer, and have the hci scheduler call up to L2CAP to fetch frames. However, this hasn't been implemented yet.

Quoted 8 lines
Quoted 2 lines

Ok, I can see why you added tx_work now. We really need to move to the new proposal here.

I was hoping we could use this callback method for now, then implement the new proposal. It seems better to have ERTM working well from the start. Both designs have callbacks to L2CAP (this one actually makes fewer callbacks). If you want me to rip out the skb destructor callbacks, I can do it now.

Quoted 3 lines

how much effort would it be? I am fine with doing this a little bit later on if this would take too much time. Give me an idea how complicated the change would be at this time.

It's easy to remove, but hard to replace. ERTM does not work well with packet loss if this code is removed and HCI queuing is left alone.

Quoted 13 lines
Quoted 5 lines
Quoted 4 lines

Also I think the most important thing here is not point out wrong stuff in this huge patch but find ways to split it in many patches. If we could get a cleaner and rebased patch fixing the unnecessary renames and functions move, etc. that would be good for us. :)

Quoted 7 lines

Now that I have the input for l2cap.h, I'll update l2cap_core.c and start splitting it up. My understanding from earlier discussion of this ERTM change is that there are a few independent changes that can be added without breaking the current ERTM implementation, but the big changes will have to add inactive code in parallel. After all the code is there, we will make it active and remove the old code. Let me know if I've misunderstood.

Quoted 6 lines

That sounds perfectly fine to. Small changes that can be done right now without breaking the current code should go in right away. Like some renaming, moving of code, cleanup and so.

After that, lets add the extra code you need, activate it, and then delete the unused code.

Ok.

Regards,

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