Fix a bug where the overhead of the I-DATA chunk was not considered.

MFC after: 1 week
This commit is contained in:
Michael Tuexen 2017-01-24 21:30:31 +00:00
parent 824c5192ba
commit bd60638c98
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=312722

View File

@ -7080,11 +7080,9 @@ sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc, int so_l
}
}
static int
sctp_can_we_split_this(struct sctp_tcb *stcb,
uint32_t length,
uint32_t goal_mtu, uint32_t frag_point, int eeor_on)
static uint32_t
sctp_can_we_split_this(struct sctp_tcb *stcb, uint32_t length,
uint32_t space_left, uint32_t frag_point, int eeor_on)
{
/*
* Make a decision on if I should split a msg into multiple parts.
@ -7096,7 +7094,7 @@ sctp_can_we_split_this(struct sctp_tcb *stcb,
* entire thing, since it might be all the guy is putting in
* the hopper.
*/
if (goal_mtu >= length) {
if (space_left >= length) {
/*-
* If we have data outstanding,
* we get another chance when the sack
@ -7113,7 +7111,7 @@ sctp_can_we_split_this(struct sctp_tcb *stcb,
} else {
/* You can fill the rest */
return (goal_mtu);
return (space_left);
}
}
/*-
@ -7124,28 +7122,27 @@ sctp_can_we_split_this(struct sctp_tcb *stcb,
if (SCTP_SB_LIMIT_SND(stcb->sctp_socket) < frag_point) {
return (length);
}
if ((length <= goal_mtu) ||
((length - goal_mtu) < SCTP_BASE_SYSCTL(sctp_min_residual))) {
if ((length <= space_left) ||
((length - space_left) < SCTP_BASE_SYSCTL(sctp_min_residual))) {
/* Sub-optimial residual don't split in non-eeor mode. */
return (0);
}
/*
* If we reach here length is larger than the goal_mtu. Do we wish
* If we reach here length is larger than the space_left. Do we wish
* to split it for the sake of packet putting together?
*/
if (goal_mtu >= min(SCTP_BASE_SYSCTL(sctp_min_split_point), frag_point)) {
if (space_left >= min(SCTP_BASE_SYSCTL(sctp_min_split_point), frag_point)) {
/* Its ok to split it */
return (min(goal_mtu, frag_point));
return (min(space_left, frag_point));
}
/* Nope, can't split */
return (0);
}
static uint32_t
sctp_move_to_outqueue(struct sctp_tcb *stcb,
struct sctp_stream_out *strq,
uint32_t goal_mtu,
uint32_t space_left,
uint32_t frag_point,
int *giveup,
int eeor_mode,
@ -7306,7 +7303,7 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
sp->some_taken = 1;
}
} else {
to_move = sctp_can_we_split_this(stcb, length, goal_mtu, frag_point, eeor_mode);
to_move = sctp_can_we_split_this(stcb, length, space_left, frag_point, eeor_mode);
if (to_move) {
/*-
* We use a snapshot of length in case it
@ -7701,56 +7698,66 @@ sctp_fill_outqueue(struct sctp_tcb *stcb,
{
struct sctp_association *asoc;
struct sctp_stream_out *strq;
int goal_mtu, moved_how_much, total_moved = 0, bail = 0;
int giveup;
uint32_t space_left, moved, total_moved;
int bail, giveup;
SCTP_TCB_LOCK_ASSERT(stcb);
asoc = &stcb->asoc;
total_moved = 0;
switch (net->ro._l_addr.sa.sa_family) {
#ifdef INET
case AF_INET:
goal_mtu = net->mtu - SCTP_MIN_V4_OVERHEAD;
space_left = net->mtu - SCTP_MIN_V4_OVERHEAD;
break;
#endif
#ifdef INET6
case AF_INET6:
goal_mtu = net->mtu - SCTP_MIN_OVERHEAD;
space_left = net->mtu - SCTP_MIN_OVERHEAD;
break;
#endif
default:
/* TSNH */
goal_mtu = net->mtu;
space_left = net->mtu;
break;
}
/* Need an allowance for the data chunk header too */
if (stcb->asoc.idata_supported == 0) {
goal_mtu -= sizeof(struct sctp_data_chunk);
space_left -= sizeof(struct sctp_data_chunk);
} else {
goal_mtu -= sizeof(struct sctp_idata_chunk);
space_left -= sizeof(struct sctp_idata_chunk);
}
/* must make even word boundary */
goal_mtu &= 0xfffffffc;
space_left &= 0xfffffffc;
strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
while ((goal_mtu > 0) && strq) {
while ((space_left > 0) && (strq != NULL)) {
giveup = 0;
bail = 0;
moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point,
moved = sctp_move_to_outqueue(stcb, strq, space_left, frag_point,
&giveup, eeor_mode, &bail, so_locked);
stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved_how_much);
if ((giveup) || bail) {
stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved);
if ((giveup != 0) || (bail != 0)) {
break;
}
strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
if (strq == NULL) {
break;
total_moved += moved;
space_left -= moved;
if (stcb->asoc.idata_supported == 0) {
if (space_left >= sizeof(struct sctp_data_chunk)) {
space_left -= sizeof(struct sctp_data_chunk);
} else {
space_left = 0;
}
} else {
if (space_left >= sizeof(struct sctp_idata_chunk)) {
space_left -= sizeof(struct sctp_idata_chunk);
} else {
space_left = 0;
}
}
total_moved += moved_how_much;
goal_mtu -= (moved_how_much + sizeof(struct sctp_data_chunk));
goal_mtu &= 0xfffffffc;
space_left &= 0xfffffffc;
}
if (bail)
if (bail != 0)
*quit_now = 1;
stcb->asoc.ss_functions.sctp_ss_packet_done(stcb, net, asoc);