Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_output.c
Show First 20 Lines • Show All 179 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Tcp output routine: figure out what should be sent and send it. | * Tcp output routine: figure out what should be sent and send it. | ||||
*/ | */ | ||||
int | int | ||||
tcp_output(struct tcpcb *tp) | tcp_output(struct tcpcb *tp) | ||||
{ | { | ||||
struct socket *so = tp->t_inpcb->inp_socket; | struct socket *so = tp->t_inpcb->inp_socket; | ||||
long len; | int32_t len; | ||||
uint32_t recwin, sendwin; | uint32_t recwin, sendwin; | ||||
int off, flags, error = 0; /* Keep compiler happy */ | int off, flags, error = 0; /* Keep compiler happy */ | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ip *ip = NULL; | struct ip *ip = NULL; | ||||
struct ipovly *ipov = NULL; | struct ipovly *ipov = NULL; | ||||
struct tcphdr *th; | struct tcphdr *th; | ||||
u_char opt[TCP_MAXOLEN]; | u_char opt[TCP_MAXOLEN]; | ||||
unsigned ipoptlen, optlen, hdrlen; | unsigned ipoptlen, optlen, hdrlen; | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | again: | ||||
* Still in sack recovery , reset rxmit flag to zero. | * Still in sack recovery , reset rxmit flag to zero. | ||||
*/ | */ | ||||
sack_rxmit = 0; | sack_rxmit = 0; | ||||
sack_bytes_rxmt = 0; | sack_bytes_rxmt = 0; | ||||
len = 0; | len = 0; | ||||
p = NULL; | p = NULL; | ||||
if ((tp->t_flags & TF_SACK_PERMIT) && IN_FASTRECOVERY(tp->t_flags) && | if ((tp->t_flags & TF_SACK_PERMIT) && IN_FASTRECOVERY(tp->t_flags) && | ||||
(p = tcp_sack_output(tp, &sack_bytes_rxmt))) { | (p = tcp_sack_output(tp, &sack_bytes_rxmt))) { | ||||
long cwin; | uint32_t cwin; | ||||
lstewart: The think I agree with your offline comment about consistency - either make this signed, or… | |||||
cwin = min(tp->snd_wnd, tp->snd_cwnd) - sack_bytes_rxmt; | cwin = | ||||
if (cwin < 0) | imax(min(tp->snd_wnd, tp->snd_cwnd) - sack_bytes_rxmt, 0); | ||||
cwin = 0; | |||||
/* Do not retransmit SACK segments beyond snd_recover */ | /* Do not retransmit SACK segments beyond snd_recover */ | ||||
if (SEQ_GT(p->end, tp->snd_recover)) { | if (SEQ_GT(p->end, tp->snd_recover)) { | ||||
/* | /* | ||||
* (At least) part of sack hole extends beyond | * (At least) part of sack hole extends beyond | ||||
* snd_recover. Check to see if we can rexmit data | * snd_recover. Check to see if we can rexmit data | ||||
* for this hole. | * for this hole. | ||||
*/ | */ | ||||
if (SEQ_GEQ(p->rxmit, tp->snd_recover)) { | if (SEQ_GEQ(p->rxmit, tp->snd_recover)) { | ||||
/* | /* | ||||
* Can't rexmit any more data for this hole. | * Can't rexmit any more data for this hole. | ||||
* That data will be rexmitted in the next | * That data will be rexmitted in the next | ||||
* sack recovery episode, when snd_recover | * sack recovery episode, when snd_recover | ||||
* moves past p->rxmit. | * moves past p->rxmit. | ||||
*/ | */ | ||||
p = NULL; | p = NULL; | ||||
goto after_sack_rexmit; | goto after_sack_rexmit; | ||||
} else | } else | ||||
/* Can rexmit part of the current hole */ | /* Can rexmit part of the current hole */ | ||||
len = ((long)ulmin(cwin, | len = ((int32_t)ulmin(cwin, | ||||
lstewartUnsubmitted Not Done Inline ActionsWhy not min() here and lines 306, 379? lstewart: Why not min() here and lines 306, 379? | |||||
tp->snd_recover - p->rxmit)); | tp->snd_recover - p->rxmit)); | ||||
} else | } else | ||||
len = ((long)ulmin(cwin, p->end - p->rxmit)); | len = ((int32_t)ulmin(cwin, p->end - p->rxmit)); | ||||
off = p->rxmit - tp->snd_una; | off = p->rxmit - tp->snd_una; | ||||
KASSERT(off >= 0,("%s: sack block to the left of una : %d", | KASSERT(off >= 0,("%s: sack block to the left of una : %d", | ||||
__func__, off)); | __func__, off)); | ||||
if (len > 0) { | if (len > 0) { | ||||
sack_rxmit = 1; | sack_rxmit = 1; | ||||
sendalot = 1; | sendalot = 1; | ||||
TCPSTAT_INC(tcps_sack_rexmits); | TCPSTAT_INC(tcps_sack_rexmits); | ||||
TCPSTAT_ADD(tcps_sack_rexmit_bytes, | TCPSTAT_ADD(tcps_sack_rexmit_bytes, | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | after_sack_rexmit: | ||||
* be set to snd_una, the offset will be 0, and the length may | * be set to snd_una, the offset will be 0, and the length may | ||||
* wind up 0. | * wind up 0. | ||||
* | * | ||||
* If sack_rxmit is true we are retransmitting from the scoreboard | * If sack_rxmit is true we are retransmitting from the scoreboard | ||||
* in which case len is already set. | * in which case len is already set. | ||||
*/ | */ | ||||
if (sack_rxmit == 0) { | if (sack_rxmit == 0) { | ||||
if (sack_bytes_rxmt == 0) | if (sack_bytes_rxmt == 0) | ||||
len = ((long)ulmin(sbavail(&so->so_snd), sendwin) - | len = ((int32_t)ulmin(sbavail(&so->so_snd), sendwin) - | ||||
off); | off); | ||||
else { | else { | ||||
long cwin; | int32_t cwin; | ||||
/* | /* | ||||
* We are inside of a SACK recovery episode and are | * We are inside of a SACK recovery episode and are | ||||
* sending new data, having retransmitted all the | * sending new data, having retransmitted all the | ||||
* data possible in the scoreboard. | * data possible in the scoreboard. | ||||
*/ | */ | ||||
len = ((long)min(sbavail(&so->so_snd), tp->snd_wnd) - | len = ((int32_t)min(sbavail(&so->so_snd), tp->snd_wnd) - | ||||
off); | off); | ||||
/* | /* | ||||
* Don't remove this (len > 0) check ! | * Don't remove this (len > 0) check ! | ||||
* We explicitly check for len > 0 here (although it | * We explicitly check for len > 0 here (although it | ||||
* isn't really necessary), to work around a gcc | * isn't really necessary), to work around a gcc | ||||
* optimization issue - to force gcc to compute | * optimization issue - to force gcc to compute | ||||
* len above. Without this check, the computation | * len above. Without this check, the computation | ||||
* of len is bungled by the optimizer. | * of len is bungled by the optimizer. | ||||
*/ | */ | ||||
if (len > 0) { | if (len > 0) { | ||||
cwin = tp->snd_cwnd - | cwin = tp->snd_cwnd - | ||||
(tp->snd_nxt - tp->sack_newdata) - | (tp->snd_nxt - tp->sack_newdata) - | ||||
sack_bytes_rxmt; | sack_bytes_rxmt; | ||||
if (cwin < 0) | if (cwin < 0) | ||||
cwin = 0; | cwin = 0; | ||||
len = lmin(len, cwin); | len = imin(len, cwin); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Lop off SYN bit if it has already been sent. However, if this | * Lop off SYN bit if it has already been sent. However, if this | ||||
* is SYN-SENT state and if segment contains data and if we don't | * is SYN-SENT state and if segment contains data and if we don't | ||||
* know that foreign host supports TAO, suppress sending segment. | * know that foreign host supports TAO, suppress sending segment. | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | if (len) { | ||||
* NOTE! on localhost connections an 'ack' from the remote | * NOTE! on localhost connections an 'ack' from the remote | ||||
* end may occur synchronously with the output and cause | * end may occur synchronously with the output and cause | ||||
* us to flush a buffer queued with moretocome. XXX | * us to flush a buffer queued with moretocome. XXX | ||||
* | * | ||||
* note: the len + off check is almost certainly unnecessary. | * note: the len + off check is almost certainly unnecessary. | ||||
*/ | */ | ||||
if (!(tp->t_flags & TF_MORETOCOME) && /* normal case */ | if (!(tp->t_flags & TF_MORETOCOME) && /* normal case */ | ||||
(idle || (tp->t_flags & TF_NODELAY)) && | (idle || (tp->t_flags & TF_NODELAY)) && | ||||
len + off >= sbavail(&so->so_snd) && | (uint32_t)len + (uint32_t)off >= sbavail(&so->so_snd) && | ||||
lstewartUnsubmitted Not Done Inline Actions(uint32_t)(len + off) here and elsewhere below perhaps? lstewart: (uint32_t)(len + off) here and elsewhere below perhaps? | |||||
(tp->t_flags & TF_NOPUSH) == 0) { | (tp->t_flags & TF_NOPUSH) == 0) { | ||||
goto send; | goto send; | ||||
} | } | ||||
if (tp->t_flags & TF_FORCEDATA) /* typ. timeout case */ | if (tp->t_flags & TF_FORCEDATA) /* typ. timeout case */ | ||||
goto send; | goto send; | ||||
if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) | if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) | ||||
goto send; | goto send; | ||||
if (SEQ_LT(tp->snd_nxt, tp->snd_max)) /* retransmit case */ | if (SEQ_LT(tp->snd_nxt, tp->snd_max)) /* retransmit case */ | ||||
▲ Show 20 Lines • Show All 340 Lines • ▼ Show 20 Lines | if (tso) { | ||||
} | } | ||||
/* | /* | ||||
* Prevent the last segment from being | * Prevent the last segment from being | ||||
* fractional unless the send sockbuf can be | * fractional unless the send sockbuf can be | ||||
* emptied: | * emptied: | ||||
*/ | */ | ||||
max_len = (tp->t_maxseg - optlen); | max_len = (tp->t_maxseg - optlen); | ||||
if ((off + len) < sbavail(&so->so_snd)) { | if (((uint32_t)off + (uint32_t)len) < | ||||
sbavail(&so->so_snd)) { | |||||
moff = len % max_len; | moff = len % max_len; | ||||
if (moff != 0) { | if (moff != 0) { | ||||
len -= moff; | len -= moff; | ||||
sendalot = 1; | sendalot = 1; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Start the m_copy functions from the closest mbuf | * Start the m_copy functions from the closest mbuf | ||||
* to the offset in the socket buffer chain. | * to the offset in the socket buffer chain. | ||||
*/ | */ | ||||
mb = sbsndptr(&so->so_snd, off, len, &moff); | mb = sbsndptr(&so->so_snd, off, len, &moff); | ||||
if (len <= MHLEN - hdrlen - max_linkhdr) { | if (len <= MHLEN - hdrlen - max_linkhdr) { | ||||
m_copydata(mb, moff, (int)len, | m_copydata(mb, moff, len, | ||||
mtod(m, caddr_t) + hdrlen); | mtod(m, caddr_t) + hdrlen); | ||||
m->m_len += len; | m->m_len += len; | ||||
} else { | } else { | ||||
m->m_next = m_copy(mb, moff, (int)len); | m->m_next = m_copy(mb, moff, len); | ||||
if (m->m_next == NULL) { | if (m->m_next == NULL) { | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
(void) m_free(m); | (void) m_free(m); | ||||
error = ENOBUFS; | error = ENOBUFS; | ||||
sack_rxmit = 0; | sack_rxmit = 0; | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If we're sending everything we've got, set PUSH. | * If we're sending everything we've got, set PUSH. | ||||
* (This will keep happy those implementations which only | * (This will keep happy those implementations which only | ||||
* give data to the user when a buffer fills or | * give data to the user when a buffer fills or | ||||
* a PUSH comes in.) | * a PUSH comes in.) | ||||
*/ | */ | ||||
if ((off + len == sbused(&so->so_snd)) && !(flags & TH_SYN)) | if (((uint32_t)off + (uint32_t)len == sbused(&so->so_snd)) && | ||||
!(flags & TH_SYN)) | |||||
flags |= TH_PUSH; | flags |= TH_PUSH; | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
} else { | } else { | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
if (tp->t_flags & TF_ACKNOW) | if (tp->t_flags & TF_ACKNOW) | ||||
TCPSTAT_INC(tcps_sndacks); | TCPSTAT_INC(tcps_sndacks); | ||||
else if (flags & (TH_SYN|TH_FIN|TH_RST)) | else if (flags & (TH_SYN|TH_FIN|TH_RST)) | ||||
TCPSTAT_INC(tcps_sndctrl); | TCPSTAT_INC(tcps_sndctrl); | ||||
▲ Show 20 Lines • Show All 212 Lines • ▼ Show 20 Lines | if (tso) { | ||||
KASSERT(len > tp->t_maxseg - optlen, | KASSERT(len > tp->t_maxseg - optlen, | ||||
("%s: len <= tso_segsz", __func__)); | ("%s: len <= tso_segsz", __func__)); | ||||
m->m_pkthdr.csum_flags |= CSUM_TSO; | m->m_pkthdr.csum_flags |= CSUM_TSO; | ||||
m->m_pkthdr.tso_segsz = tp->t_maxseg - optlen; | m->m_pkthdr.tso_segsz = tp->t_maxseg - optlen; | ||||
} | } | ||||
#ifdef IPSEC | #ifdef IPSEC | ||||
KASSERT(len + hdrlen + ipoptlen - ipsec_optlen == m_length(m, NULL), | KASSERT(len + hdrlen + ipoptlen - ipsec_optlen == m_length(m, NULL), | ||||
("%s: mbuf chain shorter than expected: %ld + %u + %u - %u != %u", | ("%s: mbuf chain shorter than expected: %d + %u + %u - %u != %u", | ||||
__func__, len, hdrlen, ipoptlen, ipsec_optlen, m_length(m, NULL))); | __func__, len, hdrlen, ipoptlen, ipsec_optlen, | ||||
m_length(m, NULL))); | |||||
#else | #else | ||||
KASSERT(len + hdrlen + ipoptlen == m_length(m, NULL), | KASSERT(len + hdrlen + ipoptlen == m_length(m, NULL), | ||||
("%s: mbuf chain shorter than expected: %ld + %u + %u != %u", | ("%s: mbuf chain shorter than expected: %d + %u + %u != %u", | ||||
__func__, len, hdrlen, ipoptlen, m_length(m, NULL))); | __func__, len, hdrlen, ipoptlen, m_length(m, NULL))); | ||||
#endif | #endif | ||||
Done Inline ActionsAehm, no; change the format specifier, don't cast! bz: Aehm, no; change the format specifier, don't cast! | |||||
Done Inline ActionsYou're going to see this in several of my reviews. The "right thing" (TM) to do is to use the PRId32 macro. But, I didn't want to do that, since we don't use it anywhere else in the kernel code. But, thinking through this more, an int format specifier should work for this. We don't have platforms with ints less than 32 bits, and aren't likely to get one in the future. I'll get all those reviews updated and resubmit. jtl: You're going to see this in several of my reviews. The "right thing" (TM) to do is to use the… | |||||
/* Run HHOOK_TCP_ESTABLISHED_OUT helper hooks. */ | /* Run HHOOK_TCP_ESTABLISHED_OUT helper hooks. */ | ||||
hhook_run_tcp_est_out(tp, th, &to, len, tso); | hhook_run_tcp_est_out(tp, th, &to, len, tso); | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
/* | /* | ||||
* Trace. | * Trace. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 501 Lines • Show Last 20 Lines |
The think I agree with your offline comment about consistency - either make this signed, or change elsewhere to unsigned.