diff options
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/output.c | 142 |
1 files changed, 85 insertions, 57 deletions
diff --git a/net/sctp/output.c b/net/sctp/output.c index 94c110dcaf1d..e25e2e20b63d 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
@@ -61,8 +61,13 @@ | |||
61 | #include <net/sctp/checksum.h> | 61 | #include <net/sctp/checksum.h> |
62 | 62 | ||
63 | /* Forward declarations for private helpers. */ | 63 | /* Forward declarations for private helpers. */ |
64 | static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | 64 | static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, |
65 | struct sctp_chunk *chunk); | 65 | struct sctp_chunk *chunk); |
66 | static void sctp_packet_append_data(struct sctp_packet *packet, | ||
67 | struct sctp_chunk *chunk); | ||
68 | static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, | ||
69 | struct sctp_chunk *chunk, | ||
70 | u16 chunk_len); | ||
66 | 71 | ||
67 | /* Config a packet. | 72 | /* Config a packet. |
68 | * This appears to be a followup set of initializations. | 73 | * This appears to be a followup set of initializations. |
@@ -262,13 +267,20 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, | |||
262 | { | 267 | { |
263 | sctp_xmit_t retval = SCTP_XMIT_OK; | 268 | sctp_xmit_t retval = SCTP_XMIT_OK; |
264 | __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); | 269 | __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); |
265 | size_t psize; | ||
266 | size_t pmtu; | ||
267 | int too_big; | ||
268 | 270 | ||
269 | SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, | 271 | SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, |
270 | chunk); | 272 | chunk); |
271 | 273 | ||
274 | /* Data chunks are special. Before seeing what else we can | ||
275 | * bundle into this packet, check to see if we are allowed to | ||
276 | * send this DATA. | ||
277 | */ | ||
278 | if (sctp_chunk_is_data(chunk)) { | ||
279 | retval = sctp_packet_can_append_data(packet, chunk); | ||
280 | if (retval != SCTP_XMIT_OK) | ||
281 | goto finish; | ||
282 | } | ||
283 | |||
272 | /* Try to bundle AUTH chunk */ | 284 | /* Try to bundle AUTH chunk */ |
273 | retval = sctp_packet_bundle_auth(packet, chunk); | 285 | retval = sctp_packet_bundle_auth(packet, chunk); |
274 | if (retval != SCTP_XMIT_OK) | 286 | if (retval != SCTP_XMIT_OK) |
@@ -279,51 +291,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, | |||
279 | if (retval != SCTP_XMIT_OK) | 291 | if (retval != SCTP_XMIT_OK) |
280 | goto finish; | 292 | goto finish; |
281 | 293 | ||
282 | psize = packet->size; | 294 | /* Check to see if this chunk will fit into the packet */ |
283 | pmtu = ((packet->transport->asoc) ? | 295 | retval = sctp_packet_will_fit(packet, chunk, chunk_len); |
284 | (packet->transport->asoc->pathmtu) : | 296 | if (retval != SCTP_XMIT_OK) |
285 | (packet->transport->pathmtu)); | 297 | goto finish; |
286 | |||
287 | too_big = (psize + chunk_len > pmtu); | ||
288 | |||
289 | /* Decide if we need to fragment or resubmit later. */ | ||
290 | if (too_big) { | ||
291 | /* It's OK to fragmet at IP level if any one of the following | ||
292 | * is true: | ||
293 | * 1. The packet is empty (meaning this chunk is greater | ||
294 | * the MTU) | ||
295 | * 2. The chunk we are adding is a control chunk | ||
296 | * 3. The packet doesn't have any data in it yet and data | ||
297 | * requires authentication. | ||
298 | */ | ||
299 | if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) || | ||
300 | (!packet->has_data && chunk->auth)) { | ||
301 | /* We no longer do re-fragmentation. | ||
302 | * Just fragment at the IP layer, if we | ||
303 | * actually hit this condition | ||
304 | */ | ||
305 | packet->ipfragok = 1; | ||
306 | goto append; | ||
307 | |||
308 | } else { | ||
309 | retval = SCTP_XMIT_PMTU_FULL; | ||
310 | goto finish; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | append: | ||
315 | /* We believe that this chunk is OK to add to the packet (as | ||
316 | * long as we have the cwnd for it). | ||
317 | */ | ||
318 | 298 | ||
319 | /* DATA is a special case since we must examine both rwnd and cwnd | 299 | /* We believe that this chunk is OK to add to the packet */ |
320 | * before we send DATA. | ||
321 | */ | ||
322 | switch (chunk->chunk_hdr->type) { | 300 | switch (chunk->chunk_hdr->type) { |
323 | case SCTP_CID_DATA: | 301 | case SCTP_CID_DATA: |
324 | retval = sctp_packet_append_data(packet, chunk); | 302 | /* Account for the data being in the packet */ |
325 | if (SCTP_XMIT_OK != retval) | 303 | sctp_packet_append_data(packet, chunk); |
326 | goto finish; | ||
327 | /* Disallow SACK bundling after DATA. */ | 304 | /* Disallow SACK bundling after DATA. */ |
328 | packet->has_sack = 1; | 305 | packet->has_sack = 1; |
329 | /* Disallow AUTH bundling after DATA */ | 306 | /* Disallow AUTH bundling after DATA */ |
@@ -633,16 +610,15 @@ nomem: | |||
633 | * 2nd Level Abstractions | 610 | * 2nd Level Abstractions |
634 | ********************************************************************/ | 611 | ********************************************************************/ |
635 | 612 | ||
636 | /* This private function handles the specifics of appending DATA chunks. */ | 613 | /* This private function check to see if a chunk can be added */ |
637 | static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | 614 | static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, |
638 | struct sctp_chunk *chunk) | 615 | struct sctp_chunk *chunk) |
639 | { | 616 | { |
640 | sctp_xmit_t retval = SCTP_XMIT_OK; | 617 | sctp_xmit_t retval = SCTP_XMIT_OK; |
641 | size_t datasize, rwnd, inflight; | 618 | size_t datasize, rwnd, inflight, flight_size; |
642 | struct sctp_transport *transport = packet->transport; | 619 | struct sctp_transport *transport = packet->transport; |
643 | __u32 max_burst_bytes; | 620 | __u32 max_burst_bytes; |
644 | struct sctp_association *asoc = transport->asoc; | 621 | struct sctp_association *asoc = transport->asoc; |
645 | struct sctp_sock *sp = sctp_sk(asoc->base.sk); | ||
646 | struct sctp_outq *q = &asoc->outqueue; | 622 | struct sctp_outq *q = &asoc->outqueue; |
647 | 623 | ||
648 | /* RFC 2960 6.1 Transmission of DATA Chunks | 624 | /* RFC 2960 6.1 Transmission of DATA Chunks |
@@ -659,7 +635,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
659 | */ | 635 | */ |
660 | 636 | ||
661 | rwnd = asoc->peer.rwnd; | 637 | rwnd = asoc->peer.rwnd; |
662 | inflight = asoc->outqueue.outstanding_bytes; | 638 | inflight = q->outstanding_bytes; |
639 | flight_size = transport->flight_size; | ||
663 | 640 | ||
664 | datasize = sctp_data_size(chunk); | 641 | datasize = sctp_data_size(chunk); |
665 | 642 | ||
@@ -682,8 +659,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
682 | * cwnd = flightsize + Max.Burst * MTU | 659 | * cwnd = flightsize + Max.Burst * MTU |
683 | */ | 660 | */ |
684 | max_burst_bytes = asoc->max_burst * asoc->pathmtu; | 661 | max_burst_bytes = asoc->max_burst * asoc->pathmtu; |
685 | if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { | 662 | if ((flight_size + max_burst_bytes) < transport->cwnd) { |
686 | transport->cwnd = transport->flight_size + max_burst_bytes; | 663 | transport->cwnd = flight_size + max_burst_bytes; |
687 | SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " | 664 | SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " |
688 | "transport: %p, cwnd: %d, " | 665 | "transport: %p, cwnd: %d, " |
689 | "ssthresh: %d, flight_size: %d, " | 666 | "ssthresh: %d, flight_size: %d, " |
@@ -708,7 +685,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
708 | * ignore the value of cwnd and SHOULD NOT delay retransmission. | 685 | * ignore the value of cwnd and SHOULD NOT delay retransmission. |
709 | */ | 686 | */ |
710 | if (chunk->fast_retransmit != SCTP_NEED_FRTX) | 687 | if (chunk->fast_retransmit != SCTP_NEED_FRTX) |
711 | if (transport->flight_size >= transport->cwnd) { | 688 | if (flight_size >= transport->cwnd) { |
712 | retval = SCTP_XMIT_RWND_FULL; | 689 | retval = SCTP_XMIT_RWND_FULL; |
713 | goto finish; | 690 | goto finish; |
714 | } | 691 | } |
@@ -718,8 +695,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
718 | * if any previously transmitted data on the connection remains | 695 | * if any previously transmitted data on the connection remains |
719 | * unacknowledged. | 696 | * unacknowledged. |
720 | */ | 697 | */ |
721 | if (!sp->nodelay && sctp_packet_empty(packet) && | 698 | if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) && |
722 | q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { | 699 | inflight && sctp_state(asoc, ESTABLISHED)) { |
723 | unsigned len = datasize + q->out_qlen; | 700 | unsigned len = datasize + q->out_qlen; |
724 | 701 | ||
725 | /* Check whether this chunk and all the rest of pending | 702 | /* Check whether this chunk and all the rest of pending |
@@ -732,6 +709,19 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
732 | } | 709 | } |
733 | } | 710 | } |
734 | 711 | ||
712 | finish: | ||
713 | return retval; | ||
714 | } | ||
715 | |||
716 | /* This private function does management things when adding DATA chunk */ | ||
717 | static void sctp_packet_append_data(struct sctp_packet *packet, | ||
718 | struct sctp_chunk *chunk) | ||
719 | { | ||
720 | struct sctp_transport *transport = packet->transport; | ||
721 | size_t datasize = sctp_data_size(chunk); | ||
722 | struct sctp_association *asoc = transport->asoc; | ||
723 | u32 rwnd = asoc->peer.rwnd; | ||
724 | |||
735 | /* Keep track of how many bytes are in flight over this transport. */ | 725 | /* Keep track of how many bytes are in flight over this transport. */ |
736 | transport->flight_size += datasize; | 726 | transport->flight_size += datasize; |
737 | 727 | ||
@@ -754,7 +744,45 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
754 | /* Has been accepted for transmission. */ | 744 | /* Has been accepted for transmission. */ |
755 | if (!asoc->peer.prsctp_capable) | 745 | if (!asoc->peer.prsctp_capable) |
756 | chunk->msg->can_abandon = 0; | 746 | chunk->msg->can_abandon = 0; |
747 | } | ||
748 | |||
749 | static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, | ||
750 | struct sctp_chunk *chunk, | ||
751 | u16 chunk_len) | ||
752 | { | ||
753 | size_t psize; | ||
754 | size_t pmtu; | ||
755 | int too_big; | ||
756 | sctp_xmit_t retval = SCTP_XMIT_OK; | ||
757 | |||
758 | psize = packet->size; | ||
759 | pmtu = ((packet->transport->asoc) ? | ||
760 | (packet->transport->asoc->pathmtu) : | ||
761 | (packet->transport->pathmtu)); | ||
762 | |||
763 | too_big = (psize + chunk_len > pmtu); | ||
764 | |||
765 | /* Decide if we need to fragment or resubmit later. */ | ||
766 | if (too_big) { | ||
767 | /* It's OK to fragmet at IP level if any one of the following | ||
768 | * is true: | ||
769 | * 1. The packet is empty (meaning this chunk is greater | ||
770 | * the MTU) | ||
771 | * 2. The chunk we are adding is a control chunk | ||
772 | * 3. The packet doesn't have any data in it yet and data | ||
773 | * requires authentication. | ||
774 | */ | ||
775 | if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) || | ||
776 | (!packet->has_data && chunk->auth)) { | ||
777 | /* We no longer do re-fragmentation. | ||
778 | * Just fragment at the IP layer, if we | ||
779 | * actually hit this condition | ||
780 | */ | ||
781 | packet->ipfragok = 1; | ||
782 | } else { | ||
783 | retval = SCTP_XMIT_PMTU_FULL; | ||
784 | } | ||
785 | } | ||
757 | 786 | ||
758 | finish: | ||
759 | return retval; | 787 | return retval; |
760 | } | 788 | } |