diff options
author | Gustavo F. Padovan <gustavo@las.ic.unicamp.br> | 2009-08-20 21:25:58 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-08-22 17:53:58 -0400 |
commit | c74e560cd0101455f1889515e1527e4c2e266113 (patch) | |
tree | a828b646b60578c1e90580da0d92e5d1ee7e7981 /net/bluetooth | |
parent | 1c2acffb76d4bc5fd27c4ea55cc27ad8ead10f9a (diff) |
Bluetooth: Add support for Segmentation and Reassembly of SDUs
ERTM should use Segmentation and Reassembly to break down a SDU in many
PDUs on sending data to the other side.
On sending packets we queue all 'segments' until end of segmentation and
just the add them to the queue for sending. On receiving we create a new
SKB with the SDU reassembled.
Initially based on a patch from Nathan Holstein <nathan@lampreynetworks.com>
Signed-off-by: Gustavo F. Padovan <gustavo@las.ic.unicamp.br>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/l2cap.c | 170 |
1 files changed, 154 insertions, 16 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 45b8697a7398..167e02532697 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -1334,7 +1334,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *ms | |||
1334 | return skb; | 1334 | return skb; |
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control) | 1337 | static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) |
1338 | { | 1338 | { |
1339 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | 1339 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; |
1340 | struct sk_buff *skb; | 1340 | struct sk_buff *skb; |
@@ -1343,6 +1343,9 @@ static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg | |||
1343 | 1343 | ||
1344 | BT_DBG("sk %p len %d", sk, (int)len); | 1344 | BT_DBG("sk %p len %d", sk, (int)len); |
1345 | 1345 | ||
1346 | if (sdulen) | ||
1347 | hlen += 2; | ||
1348 | |||
1346 | count = min_t(unsigned int, (conn->mtu - hlen), len); | 1349 | count = min_t(unsigned int, (conn->mtu - hlen), len); |
1347 | skb = bt_skb_send_alloc(sk, count + hlen, | 1350 | skb = bt_skb_send_alloc(sk, count + hlen, |
1348 | msg->msg_flags & MSG_DONTWAIT, &err); | 1351 | msg->msg_flags & MSG_DONTWAIT, &err); |
@@ -1354,6 +1357,8 @@ static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg | |||
1354 | lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); | 1357 | lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); |
1355 | lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); | 1358 | lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); |
1356 | put_unaligned_le16(control, skb_put(skb, 2)); | 1359 | put_unaligned_le16(control, skb_put(skb, 2)); |
1360 | if (sdulen) | ||
1361 | put_unaligned_le16(sdulen, skb_put(skb, 2)); | ||
1357 | 1362 | ||
1358 | err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); | 1363 | err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); |
1359 | if (unlikely(err < 0)) { | 1364 | if (unlikely(err < 0)) { |
@@ -1363,6 +1368,54 @@ static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg | |||
1363 | return skb; | 1368 | return skb; |
1364 | } | 1369 | } |
1365 | 1370 | ||
1371 | static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len) | ||
1372 | { | ||
1373 | struct l2cap_pinfo *pi = l2cap_pi(sk); | ||
1374 | struct sk_buff *skb; | ||
1375 | struct sk_buff_head sar_queue; | ||
1376 | u16 control; | ||
1377 | size_t size = 0; | ||
1378 | |||
1379 | __skb_queue_head_init(&sar_queue); | ||
1380 | control = L2CAP_SDU_START; | ||
1381 | skb = l2cap_create_ertm_pdu(sk, msg, pi->max_pdu_size, control, len); | ||
1382 | if (IS_ERR(skb)) | ||
1383 | return PTR_ERR(skb); | ||
1384 | |||
1385 | __skb_queue_tail(&sar_queue, skb); | ||
1386 | len -= pi->max_pdu_size; | ||
1387 | size +=pi->max_pdu_size; | ||
1388 | control = 0; | ||
1389 | |||
1390 | while (len > 0) { | ||
1391 | size_t buflen; | ||
1392 | |||
1393 | if (len > pi->max_pdu_size) { | ||
1394 | control |= L2CAP_SDU_CONTINUE; | ||
1395 | buflen = pi->max_pdu_size; | ||
1396 | } else { | ||
1397 | control |= L2CAP_SDU_END; | ||
1398 | buflen = len; | ||
1399 | } | ||
1400 | |||
1401 | skb = l2cap_create_ertm_pdu(sk, msg, buflen, control, 0); | ||
1402 | if (IS_ERR(skb)) { | ||
1403 | skb_queue_purge(&sar_queue); | ||
1404 | return PTR_ERR(skb); | ||
1405 | } | ||
1406 | |||
1407 | __skb_queue_tail(&sar_queue, skb); | ||
1408 | len -= buflen; | ||
1409 | size += buflen; | ||
1410 | control = 0; | ||
1411 | } | ||
1412 | skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk)); | ||
1413 | if (sk->sk_send_head == NULL) | ||
1414 | sk->sk_send_head = sar_queue.next; | ||
1415 | |||
1416 | return size; | ||
1417 | } | ||
1418 | |||
1366 | static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) | 1419 | static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) |
1367 | { | 1420 | { |
1368 | struct sock *sk = sock->sk; | 1421 | struct sock *sk = sock->sk; |
@@ -1415,21 +1468,22 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms | |||
1415 | 1468 | ||
1416 | case L2CAP_MODE_ERTM: | 1469 | case L2CAP_MODE_ERTM: |
1417 | /* Entire SDU fits into one PDU */ | 1470 | /* Entire SDU fits into one PDU */ |
1418 | if (len <= pi->omtu) { | 1471 | if (len <= pi->max_pdu_size) { |
1419 | control = L2CAP_SDU_UNSEGMENTED; | 1472 | control = L2CAP_SDU_UNSEGMENTED; |
1420 | skb = l2cap_create_ertm_pdu(sk, msg, len, control); | 1473 | skb = l2cap_create_ertm_pdu(sk, msg, len, control, 0); |
1421 | if (IS_ERR(skb)) { | 1474 | if (IS_ERR(skb)) { |
1422 | err = PTR_ERR(skb); | 1475 | err = PTR_ERR(skb); |
1423 | goto done; | 1476 | goto done; |
1424 | } | 1477 | } |
1478 | __skb_queue_tail(TX_QUEUE(sk), skb); | ||
1479 | if (sk->sk_send_head == NULL) | ||
1480 | sk->sk_send_head = skb; | ||
1425 | } else { | 1481 | } else { |
1426 | /* FIXME: Segmentation will be added later */ | 1482 | /* Segment SDU into multiples PDUs */ |
1427 | err = -EINVAL; | 1483 | err = l2cap_sar_segment_sdu(sk, msg, len); |
1428 | goto done; | 1484 | if (err < 0) |
1485 | goto done; | ||
1429 | } | 1486 | } |
1430 | __skb_queue_tail(TX_QUEUE(sk), skb); | ||
1431 | if (sk->sk_send_head == NULL) | ||
1432 | sk->sk_send_head = skb; | ||
1433 | 1487 | ||
1434 | err = l2cap_ertm_send(sk); | 1488 | err = l2cap_ertm_send(sk); |
1435 | if (!err) | 1489 | if (!err) |
@@ -2007,7 +2061,7 @@ done: | |||
2007 | rfc.max_transmit = L2CAP_DEFAULT_MAX_RECEIVE; | 2061 | rfc.max_transmit = L2CAP_DEFAULT_MAX_RECEIVE; |
2008 | rfc.retrans_timeout = 0; | 2062 | rfc.retrans_timeout = 0; |
2009 | rfc.monitor_timeout = 0; | 2063 | rfc.monitor_timeout = 0; |
2010 | rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_RX_APDU); | 2064 | rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); |
2011 | 2065 | ||
2012 | l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, | 2066 | l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, |
2013 | sizeof(rfc), (unsigned long) &rfc); | 2067 | sizeof(rfc), (unsigned long) &rfc); |
@@ -2019,7 +2073,7 @@ done: | |||
2019 | rfc.max_transmit = 0; | 2073 | rfc.max_transmit = 0; |
2020 | rfc.retrans_timeout = 0; | 2074 | rfc.retrans_timeout = 0; |
2021 | rfc.monitor_timeout = 0; | 2075 | rfc.monitor_timeout = 0; |
2022 | rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_RX_APDU); | 2076 | rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); |
2023 | 2077 | ||
2024 | l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, | 2078 | l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, |
2025 | sizeof(rfc), (unsigned long) &rfc); | 2079 | sizeof(rfc), (unsigned long) &rfc); |
@@ -2808,6 +2862,86 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk | |||
2808 | kfree_skb(skb); | 2862 | kfree_skb(skb); |
2809 | } | 2863 | } |
2810 | 2864 | ||
2865 | static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) | ||
2866 | { | ||
2867 | struct l2cap_pinfo *pi = l2cap_pi(sk); | ||
2868 | struct sk_buff *_skb; | ||
2869 | int err = -EINVAL; | ||
2870 | |||
2871 | switch (control & L2CAP_CTRL_SAR) { | ||
2872 | case L2CAP_SDU_UNSEGMENTED: | ||
2873 | if (pi->conn_state & L2CAP_CONN_SAR_SDU) { | ||
2874 | kfree_skb(pi->sdu); | ||
2875 | break; | ||
2876 | } | ||
2877 | |||
2878 | err = sock_queue_rcv_skb(sk, skb); | ||
2879 | if (!err) | ||
2880 | return 0; | ||
2881 | |||
2882 | break; | ||
2883 | |||
2884 | case L2CAP_SDU_START: | ||
2885 | if (pi->conn_state & L2CAP_CONN_SAR_SDU) { | ||
2886 | kfree_skb(pi->sdu); | ||
2887 | break; | ||
2888 | } | ||
2889 | |||
2890 | pi->sdu_len = get_unaligned_le16(skb->data); | ||
2891 | skb_pull(skb, 2); | ||
2892 | |||
2893 | pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); | ||
2894 | if (!pi->sdu) { | ||
2895 | err = -ENOMEM; | ||
2896 | break; | ||
2897 | } | ||
2898 | |||
2899 | memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); | ||
2900 | |||
2901 | pi->conn_state |= L2CAP_CONN_SAR_SDU; | ||
2902 | pi->partial_sdu_len = skb->len; | ||
2903 | err = 0; | ||
2904 | break; | ||
2905 | |||
2906 | case L2CAP_SDU_CONTINUE: | ||
2907 | if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) | ||
2908 | break; | ||
2909 | |||
2910 | memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); | ||
2911 | |||
2912 | pi->partial_sdu_len += skb->len; | ||
2913 | if (pi->partial_sdu_len > pi->sdu_len) | ||
2914 | kfree_skb(pi->sdu); | ||
2915 | else | ||
2916 | err = 0; | ||
2917 | |||
2918 | break; | ||
2919 | |||
2920 | case L2CAP_SDU_END: | ||
2921 | if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) | ||
2922 | break; | ||
2923 | |||
2924 | memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); | ||
2925 | |||
2926 | pi->conn_state &= ~L2CAP_CONN_SAR_SDU; | ||
2927 | pi->partial_sdu_len += skb->len; | ||
2928 | |||
2929 | if (pi->partial_sdu_len == pi->sdu_len) { | ||
2930 | _skb = skb_clone(pi->sdu, GFP_ATOMIC); | ||
2931 | err = sock_queue_rcv_skb(sk, _skb); | ||
2932 | if (err < 0) | ||
2933 | kfree_skb(_skb); | ||
2934 | } | ||
2935 | kfree_skb(pi->sdu); | ||
2936 | err = 0; | ||
2937 | |||
2938 | break; | ||
2939 | } | ||
2940 | |||
2941 | kfree_skb(skb); | ||
2942 | return err; | ||
2943 | } | ||
2944 | |||
2811 | static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) | 2945 | static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) |
2812 | { | 2946 | { |
2813 | struct l2cap_pinfo *pi = l2cap_pi(sk); | 2947 | struct l2cap_pinfo *pi = l2cap_pi(sk); |
@@ -2820,11 +2954,11 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str | |||
2820 | if (tx_seq != pi->expected_tx_seq) | 2954 | if (tx_seq != pi->expected_tx_seq) |
2821 | return -EINVAL; | 2955 | return -EINVAL; |
2822 | 2956 | ||
2823 | pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; | 2957 | err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); |
2824 | err = sock_queue_rcv_skb(sk, skb); | 2958 | if (err < 0) |
2825 | if (err) | ||
2826 | return err; | 2959 | return err; |
2827 | 2960 | ||
2961 | pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; | ||
2828 | pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; | 2962 | pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; |
2829 | if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { | 2963 | if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { |
2830 | tx_control |= L2CAP_CTRL_FRAME_TYPE; | 2964 | tx_control |= L2CAP_CTRL_FRAME_TYPE; |
@@ -2860,7 +2994,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str | |||
2860 | static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) | 2994 | static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) |
2861 | { | 2995 | { |
2862 | struct sock *sk; | 2996 | struct sock *sk; |
2863 | u16 control; | 2997 | u16 control, len; |
2864 | int err; | 2998 | int err; |
2865 | 2999 | ||
2866 | sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); | 3000 | sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); |
@@ -2891,8 +3025,12 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk | |||
2891 | case L2CAP_MODE_ERTM: | 3025 | case L2CAP_MODE_ERTM: |
2892 | control = get_unaligned_le16(skb->data); | 3026 | control = get_unaligned_le16(skb->data); |
2893 | skb_pull(skb, 2); | 3027 | skb_pull(skb, 2); |
3028 | len = skb->len; | ||
2894 | 3029 | ||
2895 | if (l2cap_pi(sk)->imtu < skb->len) | 3030 | if (__is_sar_start(control)) |
3031 | len -= 2; | ||
3032 | |||
3033 | if (len > L2CAP_DEFAULT_MAX_PDU_SIZE) | ||
2896 | goto drop; | 3034 | goto drop; |
2897 | 3035 | ||
2898 | if (__is_iframe(control)) | 3036 | if (__is_iframe(control)) |