Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: Full support for receiving L2CAP SREJ frames

Support for receiving of SREJ frames as specified by the state table.

Signed-off-by: Gustavo F. Padovan <gustavo@las.ic.unicamp.br>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Gustavo F. Padovan and committed by
Marcel Holtmann
ef54fd93 8f17154f

+32 -1
+3
include/net/bluetooth/l2cap.h
··· 328 328 __u8 expected_tx_seq; 329 329 __u8 buffer_seq; 330 330 __u8 buffer_seq_srej; 331 + __u8 srej_save_reqseq; 331 332 __u8 unacked_frames; 332 333 __u8 retry_count; 333 334 __u8 num_to_ack; ··· 371 370 #define L2CAP_CONN_SAR_SDU 0x01 372 371 #define L2CAP_CONN_SREJ_SENT 0x02 373 372 #define L2CAP_CONN_WAIT_F 0x04 373 + #define L2CAP_CONN_SREJ_ACT 0x08 374 + #define L2CAP_CONN_SEND_PBIT 0x10 374 375 375 376 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ 376 377 jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
+29 -1
net/bluetooth/l2cap.c
··· 3241 3241 while (tx_seq != pi->expected_tx_seq) { 3242 3242 control = L2CAP_SUPER_SELECT_REJECT; 3243 3243 control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; 3244 + if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { 3245 + control |= L2CAP_CTRL_POLL; 3246 + pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; 3247 + } 3244 3248 l2cap_send_sframe(pi, control); 3245 3249 3246 3250 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); ··· 3303 3299 3304 3300 __skb_queue_head_init(SREJ_QUEUE(sk)); 3305 3301 l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); 3302 + 3303 + pi->conn_state |= L2CAP_CONN_SEND_PBIT; 3306 3304 3307 3305 l2cap_send_srejframe(sk, tx_seq); 3308 3306 } ··· 3376 3370 break; 3377 3371 3378 3372 case L2CAP_SUPER_SELECT_REJECT: 3379 - l2cap_retransmit_frame(sk, tx_seq); 3373 + if (rx_control & L2CAP_CTRL_POLL) { 3374 + l2cap_retransmit_frame(sk, tx_seq); 3375 + pi->expected_ack_seq = tx_seq; 3376 + l2cap_drop_acked_frames(sk); 3377 + l2cap_ertm_send(sk); 3378 + if (pi->conn_state & L2CAP_CONN_WAIT_F) { 3379 + pi->srej_save_reqseq = tx_seq; 3380 + pi->conn_state |= L2CAP_CONN_SREJ_ACT; 3381 + } 3382 + } else if (rx_control & L2CAP_CTRL_FINAL) { 3383 + if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && 3384 + pi->srej_save_reqseq == tx_seq) 3385 + pi->srej_save_reqseq &= ~L2CAP_CONN_SREJ_ACT; 3386 + else 3387 + l2cap_retransmit_frame(sk, tx_seq); 3388 + } 3389 + else { 3390 + l2cap_retransmit_frame(sk, tx_seq); 3391 + if (pi->conn_state & L2CAP_CONN_WAIT_F) { 3392 + pi->srej_save_reqseq = tx_seq; 3393 + pi->conn_state |= L2CAP_CONN_SREJ_ACT; 3394 + } 3395 + } 3380 3396 break; 3381 3397 3382 3398 case L2CAP_SUPER_RCV_NOT_READY: