Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_output.c
Show First 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
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; | ||||
int32_t 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 */ | ||||
u_int if_hw_tsomaxsegcount = 0; | |||||
u_int if_hw_tsomaxsegsize; | |||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ip *ip = NULL; | struct ip *ip = NULL; | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
struct ipovly *ipov = NULL; | struct ipovly *ipov = NULL; | ||||
#endif | #endif | ||||
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 654 Lines • ▼ Show 20 Lines | #endif /* TCP_SIGNATURE */ | ||||
* Clear the FIN bit because we cut off the tail of | * Clear the FIN bit because we cut off the tail of | ||||
* the segment. | * the segment. | ||||
*/ | */ | ||||
if (len + optlen + ipoptlen > tp->t_maxseg) { | if (len + optlen + ipoptlen > tp->t_maxseg) { | ||||
flags &= ~TH_FIN; | flags &= ~TH_FIN; | ||||
if (tso) { | if (tso) { | ||||
u_int if_hw_tsomax; | u_int if_hw_tsomax; | ||||
u_int if_hw_tsomaxsegcount; | |||||
u_int if_hw_tsomaxsegsize; | |||||
struct mbuf *mb; | |||||
u_int moff; | u_int moff; | ||||
int max_len; | int max_len; | ||||
/* extract TSO information */ | /* extract TSO information */ | ||||
if_hw_tsomax = tp->t_tsomax; | if_hw_tsomax = tp->t_tsomax; | ||||
if_hw_tsomaxsegcount = tp->t_tsomaxsegcount; | if_hw_tsomaxsegcount = tp->t_tsomaxsegcount; | ||||
if_hw_tsomaxsegsize = tp->t_tsomaxsegsize; | if_hw_tsomaxsegsize = tp->t_tsomaxsegsize; | ||||
Show All 15 Lines | if (tso) { | ||||
max_linkhdr); | max_linkhdr); | ||||
if (max_len <= 0) { | if (max_len <= 0) { | ||||
len = 0; | len = 0; | ||||
} else if (len > max_len) { | } else if (len > max_len) { | ||||
sendalot = 1; | sendalot = 1; | ||||
len = max_len; | len = max_len; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Check if we should limit by maximum segment | |||||
* size and count: | |||||
*/ | |||||
if (if_hw_tsomaxsegcount != 0 && | |||||
if_hw_tsomaxsegsize != 0) { | |||||
/* | |||||
* Subtract one segment for the LINK | |||||
* and TCP/IP headers mbuf that will | |||||
* be prepended to this mbuf chain | |||||
* after the code in this section | |||||
* limits the number of mbufs in the | |||||
* chain to if_hw_tsomaxsegcount. | |||||
*/ | |||||
if_hw_tsomaxsegcount -= 1; | |||||
max_len = 0; | |||||
mb = sbsndmbuf(&so->so_snd, off, &moff); | |||||
while (mb != NULL && max_len < len) { | |||||
u_int mlen; | |||||
u_int frags; | |||||
/* | |||||
* Get length of mbuf fragment | |||||
* and how many hardware frags, | |||||
* rounded up, it would use: | |||||
*/ | |||||
mlen = (mb->m_len - moff); | |||||
frags = howmany(mlen, | |||||
if_hw_tsomaxsegsize); | |||||
/* Handle special case: Zero Length Mbuf */ | |||||
if (frags == 0) | |||||
frags = 1; | |||||
/* | |||||
* Check if the fragment limit | |||||
* will be reached or exceeded: | |||||
*/ | |||||
if (frags >= if_hw_tsomaxsegcount) { | |||||
max_len += min(mlen, | |||||
if_hw_tsomaxsegcount * | |||||
if_hw_tsomaxsegsize); | |||||
break; | |||||
} | |||||
max_len += mlen; | |||||
if_hw_tsomaxsegcount -= frags; | |||||
moff = 0; | |||||
mb = mb->m_next; | |||||
} | |||||
if (max_len <= 0) { | |||||
len = 0; | |||||
} else if (len > max_len) { | |||||
sendalot = 1; | |||||
len = max_len; | |||||
} | |||||
} | |||||
/* | |||||
* 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 (((uint32_t)off + (uint32_t)len) < | if (((uint32_t)off + (uint32_t)len) < | ||||
sbavail(&so->so_snd)) { | sbavail(&so->so_snd)) { | ||||
moff = len % max_len; | moff = len % max_len; | ||||
Show All 17 Lines | if (tso) { | ||||
* Send the FIN in a separate segment | * Send the FIN in a separate segment | ||||
* after the bulk sending is done. | * after the bulk sending is done. | ||||
* We don't trust the TSO implementations | * We don't trust the TSO implementations | ||||
* to clear the FIN flag on all but the | * to clear the FIN flag on all but the | ||||
* last segment. | * last segment. | ||||
*/ | */ | ||||
if (tp->t_flags & TF_NEEDFIN) | if (tp->t_flags & TF_NEEDFIN) | ||||
sendalot = 1; | sendalot = 1; | ||||
} else { | } else { | ||||
len = tp->t_maxseg - optlen - ipoptlen; | len = tp->t_maxseg - optlen - ipoptlen; | ||||
sendalot = 1; | sendalot = 1; | ||||
if (dont_sendalot) | if (dont_sendalot) | ||||
sendalot = 0; | sendalot = 0; | ||||
} | } | ||||
} else | } else | ||||
tso = 0; | tso = 0; | ||||
Show All 18 Lines | /*#endif*/ | ||||
/* | /* | ||||
* Grab a header mbuf, attaching a copy of data to | * Grab a header mbuf, attaching a copy of data to | ||||
* be transmitted, and initialize the header from | * be transmitted, and initialize the header from | ||||
* the template for sends on this connection. | * the template for sends on this connection. | ||||
*/ | */ | ||||
if (len) { | if (len) { | ||||
struct mbuf *mb; | struct mbuf *mb; | ||||
struct sockbuf *msb; | |||||
u_int moff; | u_int moff; | ||||
if ((tp->t_flags & TF_FORCEDATA) && len == 1) | if ((tp->t_flags & TF_FORCEDATA) && len == 1) | ||||
TCPSTAT_INC(tcps_sndprobe); | TCPSTAT_INC(tcps_sndprobe); | ||||
else if (SEQ_LT(tp->snd_nxt, tp->snd_max) || sack_rxmit) { | else if (SEQ_LT(tp->snd_nxt, tp->snd_max) || sack_rxmit) { | ||||
tp->t_sndrexmitpack++; | tp->t_sndrexmitpack++; | ||||
TCPSTAT_INC(tcps_sndrexmitpack); | TCPSTAT_INC(tcps_sndrexmitpack); | ||||
TCPSTAT_ADD(tcps_sndrexmitbyte, len); | TCPSTAT_ADD(tcps_sndrexmitbyte, len); | ||||
Show All 17 Lines | #endif | ||||
m->m_data += max_linkhdr; | m->m_data += max_linkhdr; | ||||
m->m_len = hdrlen; | m->m_len = hdrlen; | ||||
/* | /* | ||||
* 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_noadv(&so->so_snd, off, &moff); | ||||
if (len <= MHLEN - hdrlen - max_linkhdr) { | if (len <= MHLEN - hdrlen - max_linkhdr) { | ||||
m_copydata(mb, moff, len, | m_copydata(mb, moff, len, | ||||
mtod(m, caddr_t) + hdrlen); | mtod(m, caddr_t) + hdrlen); | ||||
if (SEQ_LT(tp->snd_nxt, tp->snd_max)) | |||||
sbsndptr_adv(&so->so_snd, mb, len); | |||||
m->m_len += len; | m->m_len += len; | ||||
} else { | } else { | ||||
m->m_next = m_copym(mb, moff, len, M_NOWAIT); | if (SEQ_LT(tp->snd_nxt, tp->snd_max)) | ||||
msb = NULL; | |||||
else | |||||
msb = &so->so_snd; | |||||
m->m_next = tcp_m_copym(mb, moff, | |||||
&len, if_hw_tsomaxsegcount, | |||||
if_hw_tsomaxsegsize, msb); | |||||
if (len <= (tp->t_maxseg - optlen)) { | |||||
/* | |||||
* Must have ran out of mbufs for the copy | |||||
* shorten it to no longer need tso. Lets | |||||
* not put on sendalot since we are low on | |||||
* mbufs. | |||||
*/ | |||||
tso = 0; | |||||
} | |||||
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; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 971 Lines • Show Last 20 Lines |