diff options
Diffstat (limited to 'net/sctp/output.c')
-rw-r--r-- | net/sctp/output.c | 233 |
1 files changed, 136 insertions, 97 deletions
diff --git a/net/sctp/output.c b/net/sctp/output.c index c3f417f7ec6e..5cbda8f1ddfd 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
@@ -49,13 +49,10 @@ | |||
49 | #include <linux/ipv6.h> | 49 | #include <linux/ipv6.h> |
50 | #include <linux/init.h> | 50 | #include <linux/init.h> |
51 | #include <net/inet_ecn.h> | 51 | #include <net/inet_ecn.h> |
52 | #include <net/ip.h> | ||
52 | #include <net/icmp.h> | 53 | #include <net/icmp.h> |
53 | #include <net/net_namespace.h> | 54 | #include <net/net_namespace.h> |
54 | 55 | ||
55 | #ifndef TEST_FRAME | ||
56 | #include <net/tcp.h> | ||
57 | #endif /* TEST_FRAME (not defined) */ | ||
58 | |||
59 | #include <linux/socket.h> /* for sa_family_t */ | 56 | #include <linux/socket.h> /* for sa_family_t */ |
60 | #include <net/sock.h> | 57 | #include <net/sock.h> |
61 | 58 | ||
@@ -64,8 +61,24 @@ | |||
64 | #include <net/sctp/checksum.h> | 61 | #include <net/sctp/checksum.h> |
65 | 62 | ||
66 | /* Forward declarations for private helpers. */ | 63 | /* Forward declarations for private helpers. */ |
67 | 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); | ||
66 | static void sctp_packet_append_data(struct sctp_packet *packet, | ||
68 | struct sctp_chunk *chunk); | 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); | ||
71 | |||
72 | static void sctp_packet_reset(struct sctp_packet *packet) | ||
73 | { | ||
74 | packet->size = packet->overhead; | ||
75 | packet->has_cookie_echo = 0; | ||
76 | packet->has_sack = 0; | ||
77 | packet->has_data = 0; | ||
78 | packet->has_auth = 0; | ||
79 | packet->ipfragok = 0; | ||
80 | packet->auth = NULL; | ||
81 | } | ||
69 | 82 | ||
70 | /* Config a packet. | 83 | /* Config a packet. |
71 | * This appears to be a followup set of initializations. | 84 | * This appears to be a followup set of initializations. |
@@ -78,13 +91,8 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, | |||
78 | SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__, | 91 | SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__, |
79 | packet, vtag); | 92 | packet, vtag); |
80 | 93 | ||
94 | sctp_packet_reset(packet); | ||
81 | packet->vtag = vtag; | 95 | packet->vtag = vtag; |
82 | packet->has_cookie_echo = 0; | ||
83 | packet->has_sack = 0; | ||
84 | packet->has_auth = 0; | ||
85 | packet->has_data = 0; | ||
86 | packet->ipfragok = 0; | ||
87 | packet->auth = NULL; | ||
88 | 96 | ||
89 | if (ecn_capable && sctp_packet_empty(packet)) { | 97 | if (ecn_capable && sctp_packet_empty(packet)) { |
90 | chunk = sctp_get_ecne_prepend(packet->transport->asoc); | 98 | chunk = sctp_get_ecne_prepend(packet->transport->asoc); |
@@ -122,15 +130,9 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, | |||
122 | } | 130 | } |
123 | overhead += sizeof(struct sctphdr); | 131 | overhead += sizeof(struct sctphdr); |
124 | packet->overhead = overhead; | 132 | packet->overhead = overhead; |
125 | packet->size = overhead; | 133 | sctp_packet_reset(packet); |
126 | packet->vtag = 0; | 134 | packet->vtag = 0; |
127 | packet->has_cookie_echo = 0; | ||
128 | packet->has_sack = 0; | ||
129 | packet->has_auth = 0; | ||
130 | packet->has_data = 0; | ||
131 | packet->ipfragok = 0; | ||
132 | packet->malloced = 0; | 135 | packet->malloced = 0; |
133 | packet->auth = NULL; | ||
134 | return packet; | 136 | return packet; |
135 | } | 137 | } |
136 | 138 | ||
@@ -207,7 +209,7 @@ static sctp_xmit_t sctp_packet_bundle_auth(struct sctp_packet *pkt, | |||
207 | /* See if this is an auth chunk we are bundling or if | 209 | /* See if this is an auth chunk we are bundling or if |
208 | * auth is already bundled. | 210 | * auth is already bundled. |
209 | */ | 211 | */ |
210 | if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->auth) | 212 | if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->has_auth) |
211 | return retval; | 213 | return retval; |
212 | 214 | ||
213 | /* if the peer did not request this chunk to be authenticated, | 215 | /* if the peer did not request this chunk to be authenticated, |
@@ -237,18 +239,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt, | |||
237 | if (sctp_chunk_is_data(chunk) && !pkt->has_sack && | 239 | if (sctp_chunk_is_data(chunk) && !pkt->has_sack && |
238 | !pkt->has_cookie_echo) { | 240 | !pkt->has_cookie_echo) { |
239 | struct sctp_association *asoc; | 241 | struct sctp_association *asoc; |
242 | struct timer_list *timer; | ||
240 | asoc = pkt->transport->asoc; | 243 | asoc = pkt->transport->asoc; |
244 | timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; | ||
241 | 245 | ||
242 | if (asoc->a_rwnd > asoc->rwnd) { | 246 | /* If the SACK timer is running, we have a pending SACK */ |
247 | if (timer_pending(timer)) { | ||
243 | struct sctp_chunk *sack; | 248 | struct sctp_chunk *sack; |
244 | asoc->a_rwnd = asoc->rwnd; | 249 | asoc->a_rwnd = asoc->rwnd; |
245 | sack = sctp_make_sack(asoc); | 250 | sack = sctp_make_sack(asoc); |
246 | if (sack) { | 251 | if (sack) { |
247 | struct timer_list *timer; | ||
248 | retval = sctp_packet_append_chunk(pkt, sack); | 252 | retval = sctp_packet_append_chunk(pkt, sack); |
249 | asoc->peer.sack_needed = 0; | 253 | asoc->peer.sack_needed = 0; |
250 | timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; | 254 | if (del_timer(timer)) |
251 | if (timer_pending(timer) && del_timer(timer)) | ||
252 | sctp_association_put(asoc); | 255 | sctp_association_put(asoc); |
253 | } | 256 | } |
254 | } | 257 | } |
@@ -264,13 +267,20 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, | |||
264 | { | 267 | { |
265 | sctp_xmit_t retval = SCTP_XMIT_OK; | 268 | sctp_xmit_t retval = SCTP_XMIT_OK; |
266 | __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); | 269 | __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); |
267 | size_t psize; | ||
268 | size_t pmtu; | ||
269 | int too_big; | ||
270 | 270 | ||
271 | SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, | 271 | SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, |
272 | chunk); | 272 | chunk); |
273 | 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 | |||
274 | /* Try to bundle AUTH chunk */ | 284 | /* Try to bundle AUTH chunk */ |
275 | retval = sctp_packet_bundle_auth(packet, chunk); | 285 | retval = sctp_packet_bundle_auth(packet, chunk); |
276 | if (retval != SCTP_XMIT_OK) | 286 | if (retval != SCTP_XMIT_OK) |
@@ -281,57 +291,24 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, | |||
281 | if (retval != SCTP_XMIT_OK) | 291 | if (retval != SCTP_XMIT_OK) |
282 | goto finish; | 292 | goto finish; |
283 | 293 | ||
284 | psize = packet->size; | 294 | /* Check to see if this chunk will fit into the packet */ |
285 | pmtu = ((packet->transport->asoc) ? | 295 | retval = sctp_packet_will_fit(packet, chunk, chunk_len); |
286 | (packet->transport->asoc->pathmtu) : | 296 | if (retval != SCTP_XMIT_OK) |
287 | (packet->transport->pathmtu)); | 297 | goto finish; |
288 | |||
289 | too_big = (psize + chunk_len > pmtu); | ||
290 | |||
291 | /* Decide if we need to fragment or resubmit later. */ | ||
292 | if (too_big) { | ||
293 | /* It's OK to fragmet at IP level if any one of the following | ||
294 | * is true: | ||
295 | * 1. The packet is empty (meaning this chunk is greater | ||
296 | * the MTU) | ||
297 | * 2. The chunk we are adding is a control chunk | ||
298 | * 3. The packet doesn't have any data in it yet and data | ||
299 | * requires authentication. | ||
300 | */ | ||
301 | if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) || | ||
302 | (!packet->has_data && chunk->auth)) { | ||
303 | /* We no longer do re-fragmentation. | ||
304 | * Just fragment at the IP layer, if we | ||
305 | * actually hit this condition | ||
306 | */ | ||
307 | packet->ipfragok = 1; | ||
308 | goto append; | ||
309 | |||
310 | } else { | ||
311 | retval = SCTP_XMIT_PMTU_FULL; | ||
312 | goto finish; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | append: | ||
317 | /* We believe that this chunk is OK to add to the packet (as | ||
318 | * long as we have the cwnd for it). | ||
319 | */ | ||
320 | 298 | ||
321 | /* 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 */ |
322 | * before we send DATA. | ||
323 | */ | ||
324 | switch (chunk->chunk_hdr->type) { | 300 | switch (chunk->chunk_hdr->type) { |
325 | case SCTP_CID_DATA: | 301 | case SCTP_CID_DATA: |
326 | retval = sctp_packet_append_data(packet, chunk); | 302 | /* Account for the data being in the packet */ |
303 | sctp_packet_append_data(packet, chunk); | ||
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 */ |
330 | packet->has_auth = 1; | 307 | packet->has_auth = 1; |
331 | /* Let it be knows that packet has DATA in it */ | 308 | /* Let it be knows that packet has DATA in it */ |
332 | packet->has_data = 1; | 309 | packet->has_data = 1; |
333 | if (SCTP_XMIT_OK != retval) | 310 | /* timestamp the chunk for rtx purposes */ |
334 | goto finish; | 311 | chunk->sent_at = jiffies; |
335 | break; | 312 | break; |
336 | case SCTP_CID_COOKIE_ECHO: | 313 | case SCTP_CID_COOKIE_ECHO: |
337 | packet->has_cookie_echo = 1; | 314 | packet->has_cookie_echo = 1; |
@@ -365,7 +342,6 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
365 | struct sctp_transport *tp = packet->transport; | 342 | struct sctp_transport *tp = packet->transport; |
366 | struct sctp_association *asoc = tp->asoc; | 343 | struct sctp_association *asoc = tp->asoc; |
367 | struct sctphdr *sh; | 344 | struct sctphdr *sh; |
368 | __be32 crc32 = __constant_cpu_to_be32(0); | ||
369 | struct sk_buff *nskb; | 345 | struct sk_buff *nskb; |
370 | struct sctp_chunk *chunk, *tmp; | 346 | struct sctp_chunk *chunk, *tmp; |
371 | struct sock *sk; | 347 | struct sock *sk; |
@@ -407,13 +383,14 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
407 | sctp_assoc_sync_pmtu(asoc); | 383 | sctp_assoc_sync_pmtu(asoc); |
408 | } | 384 | } |
409 | } | 385 | } |
410 | nskb->dst = dst_clone(tp->dst); | 386 | dst = dst_clone(tp->dst); |
411 | if (!nskb->dst) | 387 | skb_dst_set(nskb, dst); |
388 | if (!dst) | ||
412 | goto no_route; | 389 | goto no_route; |
413 | dst = nskb->dst; | ||
414 | 390 | ||
415 | /* Build the SCTP header. */ | 391 | /* Build the SCTP header. */ |
416 | sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); | 392 | sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); |
393 | skb_reset_transport_header(nskb); | ||
417 | sh->source = htons(packet->source_port); | 394 | sh->source = htons(packet->source_port); |
418 | sh->dest = htons(packet->destination_port); | 395 | sh->dest = htons(packet->destination_port); |
419 | 396 | ||
@@ -470,7 +447,6 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
470 | } else | 447 | } else |
471 | chunk->resent = 1; | 448 | chunk->resent = 1; |
472 | 449 | ||
473 | chunk->sent_at = jiffies; | ||
474 | has_data = 1; | 450 | has_data = 1; |
475 | } | 451 | } |
476 | 452 | ||
@@ -530,16 +506,25 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
530 | * Note: Adler-32 is no longer applicable, as has been replaced | 506 | * Note: Adler-32 is no longer applicable, as has been replaced |
531 | * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>. | 507 | * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>. |
532 | */ | 508 | */ |
533 | if (!(dst->dev->features & NETIF_F_NO_CSUM)) { | 509 | if (!sctp_checksum_disable && |
534 | crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); | 510 | !(dst->dev->features & (NETIF_F_NO_CSUM | NETIF_F_SCTP_CSUM))) { |
535 | crc32 = sctp_end_cksum(crc32); | 511 | __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); |
536 | } else | 512 | |
537 | nskb->ip_summed = CHECKSUM_UNNECESSARY; | 513 | /* 3) Put the resultant value into the checksum field in the |
538 | 514 | * common header, and leave the rest of the bits unchanged. | |
539 | /* 3) Put the resultant value into the checksum field in the | 515 | */ |
540 | * common header, and leave the rest of the bits unchanged. | 516 | sh->checksum = sctp_end_cksum(crc32); |
541 | */ | 517 | } else { |
542 | sh->checksum = crc32; | 518 | if (dst->dev->features & NETIF_F_SCTP_CSUM) { |
519 | /* no need to seed psuedo checksum for SCTP */ | ||
520 | nskb->ip_summed = CHECKSUM_PARTIAL; | ||
521 | nskb->csum_start = (skb_transport_header(nskb) - | ||
522 | nskb->head); | ||
523 | nskb->csum_offset = offsetof(struct sctphdr, checksum); | ||
524 | } else { | ||
525 | nskb->ip_summed = CHECKSUM_UNNECESSARY; | ||
526 | } | ||
527 | } | ||
543 | 528 | ||
544 | /* IP layer ECN support | 529 | /* IP layer ECN support |
545 | * From RFC 2481 | 530 | * From RFC 2481 |
@@ -591,7 +576,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
591 | (*tp->af_specific->sctp_xmit)(nskb, tp); | 576 | (*tp->af_specific->sctp_xmit)(nskb, tp); |
592 | 577 | ||
593 | out: | 578 | out: |
594 | packet->size = packet->overhead; | 579 | sctp_packet_reset(packet); |
595 | return err; | 580 | return err; |
596 | no_route: | 581 | no_route: |
597 | kfree_skb(nskb); | 582 | kfree_skb(nskb); |
@@ -625,16 +610,15 @@ nomem: | |||
625 | * 2nd Level Abstractions | 610 | * 2nd Level Abstractions |
626 | ********************************************************************/ | 611 | ********************************************************************/ |
627 | 612 | ||
628 | /* This private function handles the specifics of appending DATA chunks. */ | 613 | /* This private function check to see if a chunk can be added */ |
629 | 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, |
630 | struct sctp_chunk *chunk) | 615 | struct sctp_chunk *chunk) |
631 | { | 616 | { |
632 | sctp_xmit_t retval = SCTP_XMIT_OK; | 617 | sctp_xmit_t retval = SCTP_XMIT_OK; |
633 | size_t datasize, rwnd, inflight; | 618 | size_t datasize, rwnd, inflight, flight_size; |
634 | struct sctp_transport *transport = packet->transport; | 619 | struct sctp_transport *transport = packet->transport; |
635 | __u32 max_burst_bytes; | 620 | __u32 max_burst_bytes; |
636 | struct sctp_association *asoc = transport->asoc; | 621 | struct sctp_association *asoc = transport->asoc; |
637 | struct sctp_sock *sp = sctp_sk(asoc->base.sk); | ||
638 | struct sctp_outq *q = &asoc->outqueue; | 622 | struct sctp_outq *q = &asoc->outqueue; |
639 | 623 | ||
640 | /* RFC 2960 6.1 Transmission of DATA Chunks | 624 | /* RFC 2960 6.1 Transmission of DATA Chunks |
@@ -651,7 +635,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
651 | */ | 635 | */ |
652 | 636 | ||
653 | rwnd = asoc->peer.rwnd; | 637 | rwnd = asoc->peer.rwnd; |
654 | inflight = asoc->outqueue.outstanding_bytes; | 638 | inflight = q->outstanding_bytes; |
639 | flight_size = transport->flight_size; | ||
655 | 640 | ||
656 | datasize = sctp_data_size(chunk); | 641 | datasize = sctp_data_size(chunk); |
657 | 642 | ||
@@ -674,8 +659,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
674 | * cwnd = flightsize + Max.Burst * MTU | 659 | * cwnd = flightsize + Max.Burst * MTU |
675 | */ | 660 | */ |
676 | max_burst_bytes = asoc->max_burst * asoc->pathmtu; | 661 | max_burst_bytes = asoc->max_burst * asoc->pathmtu; |
677 | if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { | 662 | if ((flight_size + max_burst_bytes) < transport->cwnd) { |
678 | transport->cwnd = transport->flight_size + max_burst_bytes; | 663 | transport->cwnd = flight_size + max_burst_bytes; |
679 | SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " | 664 | SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " |
680 | "transport: %p, cwnd: %d, " | 665 | "transport: %p, cwnd: %d, " |
681 | "ssthresh: %d, flight_size: %d, " | 666 | "ssthresh: %d, flight_size: %d, " |
@@ -700,7 +685,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
700 | * ignore the value of cwnd and SHOULD NOT delay retransmission. | 685 | * ignore the value of cwnd and SHOULD NOT delay retransmission. |
701 | */ | 686 | */ |
702 | if (chunk->fast_retransmit != SCTP_NEED_FRTX) | 687 | if (chunk->fast_retransmit != SCTP_NEED_FRTX) |
703 | if (transport->flight_size >= transport->cwnd) { | 688 | if (flight_size >= transport->cwnd) { |
704 | retval = SCTP_XMIT_RWND_FULL; | 689 | retval = SCTP_XMIT_RWND_FULL; |
705 | goto finish; | 690 | goto finish; |
706 | } | 691 | } |
@@ -710,20 +695,36 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
710 | * if any previously transmitted data on the connection remains | 695 | * if any previously transmitted data on the connection remains |
711 | * unacknowledged. | 696 | * unacknowledged. |
712 | */ | 697 | */ |
713 | if (!sp->nodelay && sctp_packet_empty(packet) && | 698 | if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) && |
714 | q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { | 699 | inflight && sctp_state(asoc, ESTABLISHED)) { |
715 | unsigned len = datasize + q->out_qlen; | 700 | unsigned max = transport->pathmtu - packet->overhead; |
701 | unsigned len = chunk->skb->len + q->out_qlen; | ||
716 | 702 | ||
717 | /* Check whether this chunk and all the rest of pending | 703 | /* Check whether this chunk and all the rest of pending |
718 | * data will fit or delay in hopes of bundling a full | 704 | * data will fit or delay in hopes of bundling a full |
719 | * sized packet. | 705 | * sized packet. |
706 | * Don't delay large message writes that may have been | ||
707 | * fragmeneted into small peices. | ||
720 | */ | 708 | */ |
721 | if (len < asoc->frag_point) { | 709 | if ((len < max) && (chunk->msg->msg_size < max)) { |
722 | retval = SCTP_XMIT_NAGLE_DELAY; | 710 | retval = SCTP_XMIT_NAGLE_DELAY; |
723 | goto finish; | 711 | goto finish; |
724 | } | 712 | } |
725 | } | 713 | } |
726 | 714 | ||
715 | finish: | ||
716 | return retval; | ||
717 | } | ||
718 | |||
719 | /* This private function does management things when adding DATA chunk */ | ||
720 | static void sctp_packet_append_data(struct sctp_packet *packet, | ||
721 | struct sctp_chunk *chunk) | ||
722 | { | ||
723 | struct sctp_transport *transport = packet->transport; | ||
724 | size_t datasize = sctp_data_size(chunk); | ||
725 | struct sctp_association *asoc = transport->asoc; | ||
726 | u32 rwnd = asoc->peer.rwnd; | ||
727 | |||
727 | /* Keep track of how many bytes are in flight over this transport. */ | 728 | /* Keep track of how many bytes are in flight over this transport. */ |
728 | transport->flight_size += datasize; | 729 | transport->flight_size += datasize; |
729 | 730 | ||
@@ -746,7 +747,45 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, | |||
746 | /* Has been accepted for transmission. */ | 747 | /* Has been accepted for transmission. */ |
747 | if (!asoc->peer.prsctp_capable) | 748 | if (!asoc->peer.prsctp_capable) |
748 | chunk->msg->can_abandon = 0; | 749 | chunk->msg->can_abandon = 0; |
750 | } | ||
751 | |||
752 | static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, | ||
753 | struct sctp_chunk *chunk, | ||
754 | u16 chunk_len) | ||
755 | { | ||
756 | size_t psize; | ||
757 | size_t pmtu; | ||
758 | int too_big; | ||
759 | sctp_xmit_t retval = SCTP_XMIT_OK; | ||
760 | |||
761 | psize = packet->size; | ||
762 | pmtu = ((packet->transport->asoc) ? | ||
763 | (packet->transport->asoc->pathmtu) : | ||
764 | (packet->transport->pathmtu)); | ||
765 | |||
766 | too_big = (psize + chunk_len > pmtu); | ||
767 | |||
768 | /* Decide if we need to fragment or resubmit later. */ | ||
769 | if (too_big) { | ||
770 | /* It's OK to fragmet at IP level if any one of the following | ||
771 | * is true: | ||
772 | * 1. The packet is empty (meaning this chunk is greater | ||
773 | * the MTU) | ||
774 | * 2. The chunk we are adding is a control chunk | ||
775 | * 3. The packet doesn't have any data in it yet and data | ||
776 | * requires authentication. | ||
777 | */ | ||
778 | if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) || | ||
779 | (!packet->has_data && chunk->auth)) { | ||
780 | /* We no longer do re-fragmentation. | ||
781 | * Just fragment at the IP layer, if we | ||
782 | * actually hit this condition | ||
783 | */ | ||
784 | packet->ipfragok = 1; | ||
785 | } else { | ||
786 | retval = SCTP_XMIT_PMTU_FULL; | ||
787 | } | ||
788 | } | ||
749 | 789 | ||
750 | finish: | ||
751 | return retval; | 790 | return retval; |
752 | } | 791 | } |