diff options
-rw-r--r-- | net/bluetooth/l2cap.c | 119 |
1 files changed, 112 insertions, 7 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 1c35c328181d..cfd672419315 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -3329,12 +3329,111 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_ | |||
3329 | __skb_queue_tail(SREJ_QUEUE(sk), skb); | 3329 | __skb_queue_tail(SREJ_QUEUE(sk), skb); |
3330 | } | 3330 | } |
3331 | 3331 | ||
3332 | static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) | 3332 | static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) |
3333 | { | ||
3334 | struct l2cap_pinfo *pi = l2cap_pi(sk); | ||
3335 | struct sk_buff *_skb; | ||
3336 | int err = 0; | ||
3337 | |||
3338 | switch (control & L2CAP_CTRL_SAR) { | ||
3339 | case L2CAP_SDU_UNSEGMENTED: | ||
3340 | if (pi->conn_state & L2CAP_CONN_SAR_SDU) | ||
3341 | goto drop; | ||
3342 | |||
3343 | err = sock_queue_rcv_skb(sk, skb); | ||
3344 | if (!err) | ||
3345 | return err; | ||
3346 | |||
3347 | break; | ||
3348 | |||
3349 | case L2CAP_SDU_START: | ||
3350 | if (pi->conn_state & L2CAP_CONN_SAR_SDU) | ||
3351 | goto drop; | ||
3352 | |||
3353 | pi->sdu_len = get_unaligned_le16(skb->data); | ||
3354 | skb_pull(skb, 2); | ||
3355 | |||
3356 | if (pi->sdu_len > pi->imtu) | ||
3357 | goto disconnect; | ||
3358 | |||
3359 | pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); | ||
3360 | if (!pi->sdu) { | ||
3361 | err = -ENOMEM; | ||
3362 | break; | ||
3363 | } | ||
3364 | |||
3365 | memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); | ||
3366 | |||
3367 | pi->conn_state |= L2CAP_CONN_SAR_SDU; | ||
3368 | pi->partial_sdu_len = skb->len; | ||
3369 | break; | ||
3370 | |||
3371 | case L2CAP_SDU_CONTINUE: | ||
3372 | if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) | ||
3373 | goto disconnect; | ||
3374 | |||
3375 | if (!pi->sdu) | ||
3376 | goto disconnect; | ||
3377 | |||
3378 | memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); | ||
3379 | |||
3380 | pi->partial_sdu_len += skb->len; | ||
3381 | if (pi->partial_sdu_len > pi->sdu_len) | ||
3382 | goto drop; | ||
3383 | |||
3384 | break; | ||
3385 | |||
3386 | case L2CAP_SDU_END: | ||
3387 | if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) | ||
3388 | goto disconnect; | ||
3389 | |||
3390 | if (!pi->sdu) | ||
3391 | goto disconnect; | ||
3392 | |||
3393 | memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); | ||
3394 | |||
3395 | pi->conn_state &= ~L2CAP_CONN_SAR_SDU; | ||
3396 | pi->partial_sdu_len += skb->len; | ||
3397 | |||
3398 | if (pi->partial_sdu_len > pi->imtu) | ||
3399 | goto drop; | ||
3400 | |||
3401 | if (pi->partial_sdu_len != pi->sdu_len) | ||
3402 | goto drop; | ||
3403 | |||
3404 | _skb = skb_clone(pi->sdu, GFP_ATOMIC); | ||
3405 | err = sock_queue_rcv_skb(sk, _skb); | ||
3406 | if (err < 0) | ||
3407 | kfree_skb(_skb); | ||
3408 | |||
3409 | kfree_skb(pi->sdu); | ||
3410 | break; | ||
3411 | } | ||
3412 | |||
3413 | kfree_skb(skb); | ||
3414 | return err; | ||
3415 | |||
3416 | drop: | ||
3417 | kfree_skb(pi->sdu); | ||
3418 | pi->sdu = NULL; | ||
3419 | |||
3420 | disconnect: | ||
3421 | l2cap_send_disconn_req(pi->conn, sk); | ||
3422 | kfree_skb(skb); | ||
3423 | return 0; | ||
3424 | } | ||
3425 | |||
3426 | static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) | ||
3333 | { | 3427 | { |
3334 | struct l2cap_pinfo *pi = l2cap_pi(sk); | 3428 | struct l2cap_pinfo *pi = l2cap_pi(sk); |
3335 | struct sk_buff *_skb; | 3429 | struct sk_buff *_skb; |
3336 | int err = -EINVAL; | 3430 | int err = -EINVAL; |
3337 | 3431 | ||
3432 | /* | ||
3433 | * TODO: We have to notify the userland if some data is lost with the | ||
3434 | * Streaming Mode. | ||
3435 | */ | ||
3436 | |||
3338 | switch (control & L2CAP_CTRL_SAR) { | 3437 | switch (control & L2CAP_CTRL_SAR) { |
3339 | case L2CAP_SDU_UNSEGMENTED: | 3438 | case L2CAP_SDU_UNSEGMENTED: |
3340 | if (pi->conn_state & L2CAP_CONN_SAR_SDU) { | 3439 | if (pi->conn_state & L2CAP_CONN_SAR_SDU) { |
@@ -3429,7 +3528,7 @@ static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) | |||
3429 | 3528 | ||
3430 | skb = skb_dequeue(SREJ_QUEUE(sk)); | 3529 | skb = skb_dequeue(SREJ_QUEUE(sk)); |
3431 | control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; | 3530 | control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; |
3432 | l2cap_sar_reassembly_sdu(sk, skb, control); | 3531 | l2cap_ertm_reassembly_sdu(sk, skb, control); |
3433 | l2cap_pi(sk)->buffer_seq_srej = | 3532 | l2cap_pi(sk)->buffer_seq_srej = |
3434 | (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; | 3533 | (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; |
3435 | tx_seq++; | 3534 | tx_seq++; |
@@ -3566,7 +3665,7 @@ expected: | |||
3566 | 3665 | ||
3567 | pi->buffer_seq = (pi->buffer_seq + 1) % 64; | 3666 | pi->buffer_seq = (pi->buffer_seq + 1) % 64; |
3568 | 3667 | ||
3569 | err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); | 3668 | err = l2cap_ertm_reassembly_sdu(sk, skb, rx_control); |
3570 | if (err < 0) | 3669 | if (err < 0) |
3571 | return err; | 3670 | return err; |
3572 | 3671 | ||
@@ -3790,8 +3889,10 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk | |||
3790 | * Receiver will miss it and start proper recovery | 3889 | * Receiver will miss it and start proper recovery |
3791 | * procedures and ask retransmission. | 3890 | * procedures and ask retransmission. |
3792 | */ | 3891 | */ |
3793 | if (len > pi->mps) | 3892 | if (len > pi->mps) { |
3893 | l2cap_send_disconn_req(pi->conn, sk); | ||
3794 | goto drop; | 3894 | goto drop; |
3895 | } | ||
3795 | 3896 | ||
3796 | if (l2cap_check_fcs(pi, skb)) | 3897 | if (l2cap_check_fcs(pi, skb)) |
3797 | goto drop; | 3898 | goto drop; |
@@ -3813,13 +3914,17 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk | |||
3813 | } | 3914 | } |
3814 | 3915 | ||
3815 | if (__is_iframe(control)) { | 3916 | if (__is_iframe(control)) { |
3816 | if (len < 4) | 3917 | if (len < 4) { |
3918 | l2cap_send_disconn_req(pi->conn, sk); | ||
3817 | goto drop; | 3919 | goto drop; |
3920 | } | ||
3818 | 3921 | ||
3819 | l2cap_data_channel_iframe(sk, control, skb); | 3922 | l2cap_data_channel_iframe(sk, control, skb); |
3820 | } else { | 3923 | } else { |
3821 | if (len != 0) | 3924 | if (len != 0) { |
3925 | l2cap_send_disconn_req(pi->conn, sk); | ||
3822 | goto drop; | 3926 | goto drop; |
3927 | } | ||
3823 | 3928 | ||
3824 | l2cap_data_channel_sframe(sk, control, skb); | 3929 | l2cap_data_channel_sframe(sk, control, skb); |
3825 | } | 3930 | } |
@@ -3850,7 +3955,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk | |||
3850 | else | 3955 | else |
3851 | pi->expected_tx_seq = (tx_seq + 1) % 64; | 3956 | pi->expected_tx_seq = (tx_seq + 1) % 64; |
3852 | 3957 | ||
3853 | l2cap_sar_reassembly_sdu(sk, skb, control); | 3958 | l2cap_streaming_reassembly_sdu(sk, skb, control); |
3854 | 3959 | ||
3855 | goto done; | 3960 | goto done; |
3856 | 3961 | ||