aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/output.c142
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. */
64static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, 64static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
65 struct sctp_chunk *chunk); 65 struct sctp_chunk *chunk);
66static void sctp_packet_append_data(struct sctp_packet *packet,
67 struct sctp_chunk *chunk);
68static 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
314append:
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 */
637static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, 614static 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
712finish:
713 return retval;
714}
715
716/* This private function does management things when adding DATA chunk */
717static 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
749static 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
758finish:
759 return retval; 787 return retval;
760} 788}