📄 tcp_input.c
字号:
tcp_dooptions(tp, cp, cnt, ti, to)
struct tcpcb *tp;
u_char *cp;
int cnt;
struct tcpiphdr *ti;
struct tcpopt *to;
{
u_short mss = 0;
int opt, optlen;
for (; cnt > 0; cnt -= optlen, cp += optlen) {
opt = cp[0];
if (opt == TCPOPT_EOL)
break;
if (opt == TCPOPT_NOP)
optlen = 1;
else {
optlen = cp[1];
if (optlen <= 0)
break;
}
switch (opt) {
default:
continue;
case TCPOPT_MAXSEG:
if (optlen != TCPOLEN_MAXSEG)
continue;
if (!(ti->ti_flags & TH_SYN))
continue;
bcopy((char *) cp + 2, (char *) &mss, sizeof(mss));
NTOHS(mss);
break;
case TCPOPT_WINDOW:
if (optlen != TCPOLEN_WINDOW)
continue;
if (!(ti->ti_flags & TH_SYN))
continue;
tp->t_flags |= TF_RCVD_SCALE;
tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT);
break;
case TCPOPT_TIMESTAMP:
if (optlen != TCPOLEN_TIMESTAMP)
continue;
to->to_flag |= TOF_TS;
bcopy((char *)cp + 2,
(char *)&to->to_tsval, sizeof(to->to_tsval));
NTOHL(to->to_tsval);
bcopy((char *)cp + 6,
(char *)&to->to_tsecr, sizeof(to->to_tsecr));
NTOHL(to->to_tsecr);
/*
* A timestamp received in a SYN makes
* it ok to send timestamp requests and replies.
*/
if (ti->ti_flags & TH_SYN) {
tp->t_flags |= TF_RCVD_TSTMP;
tp->ts_recent = to->to_tsval;
tp->ts_recent_age = tcp_now;
}
break;
case TCPOPT_CC:
if (optlen != TCPOLEN_CC)
continue;
to->to_flag |= TOF_CC;
bcopy((char *)cp + 2,
(char *)&to->to_cc, sizeof(to->to_cc));
NTOHL(to->to_cc);
/*
* A CC or CC.new option received in a SYN makes
* it ok to send CC in subsequent segments.
*/
if (ti->ti_flags & TH_SYN)
tp->t_flags |= TF_RCVD_CC;
break;
case TCPOPT_CCNEW:
if (optlen != TCPOLEN_CC)
continue;
if (!(ti->ti_flags & TH_SYN))
continue;
to->to_flag |= TOF_CCNEW;
bcopy((char *)cp + 2,
(char *)&to->to_cc, sizeof(to->to_cc));
NTOHL(to->to_cc);
/*
* A CC or CC.new option received in a SYN makes
* it ok to send CC in subsequent segments.
*/
tp->t_flags |= TF_RCVD_CC;
break;
case TCPOPT_CCECHO:
if (optlen != TCPOLEN_CC)
continue;
if (!(ti->ti_flags & TH_SYN))
continue;
to->to_flag |= TOF_CCECHO;
bcopy((char *)cp + 2,
(char *)&to->to_ccecho, sizeof(to->to_ccecho));
NTOHL(to->to_ccecho);
break;
}
}
if (ti->ti_flags & TH_SYN)
tcp_mss(tp, mss); /* sets t_maxseg */
}
/*
* Pull out of band byte out of a segment so
* it doesn't appear in the user's data queue.
* It is still reflected in the segment length for
* sequencing purposes.
*/
void
tcp_pulloutofband(so, ti, m)
struct socket *so;
struct tcpiphdr *ti;
register struct mbuf *m;
{
int cnt = ti->ti_urp - 1;
while (cnt >= 0) {
if (m->m_len > cnt) {
char *cp = mtod(m, caddr_t) + cnt;
struct tcpcb *tp = sototcpcb(so);
tp->t_iobc = *cp;
tp->t_oobflags |= TCPOOB_HAVEDATA;
bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1));
m->m_len--;
return;
}
cnt -= m->m_len;
m = m->m_next;
if (m == 0)
break;
}
panic("tcp_pulloutofband");
}
/*
* Collect new round-trip time estimate
* and update averages and current timeout.
*/
void
tcp_xmit_timer(tp, rtt)
register struct tcpcb *tp;
short rtt;
{
register short delta;
tcpstat.tcps_rttupdated++;
tp->t_rttupdated++;
if (tp->t_srtt != 0) {
/*
* srtt is stored as fixed point with 3 bits after the
* binary point (i.e., scaled by 8). The following magic
* is equivalent to the smoothing algorithm in rfc793 with
* an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
* point). Adjust rtt to origin 0.
*/
delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
if ((tp->t_srtt += delta) <= 0)
tp->t_srtt = 1;
/*
* We accumulate a smoothed rtt variance (actually, a
* smoothed mean difference), then set the retransmit
* timer to smoothed rtt + 4 times the smoothed variance.
* rttvar is stored as fixed point with 2 bits after the
* binary point (scaled by 4). The following is
* equivalent to rfc793 smoothing with an alpha of .75
* (rttvar = rttvar*3/4 + |delta| / 4). This replaces
* rfc793's wired-in beta.
*/
if (delta < 0)
delta = -delta;
delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT);
if ((tp->t_rttvar += delta) <= 0)
tp->t_rttvar = 1;
} else {
/*
* No rtt measurement yet - use the unsmoothed rtt.
* Set the variance to half the rtt (so our first
* retransmit happens at 3*rtt).
*/
tp->t_srtt = rtt << TCP_RTT_SHIFT;
tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);
}
tp->t_rtt = 0;
tp->t_rxtshift = 0;
/*
* the retransmit should happen at rtt + 4 * rttvar.
* Because of the way we do the smoothing, srtt and rttvar
* will each average +1/2 tick of bias. When we compute
* the retransmit timer, we want 1/2 tick of rounding and
* 1 extra tick because of +-1/2 tick uncertainty in the
* firing of the timer. The bias will give us exactly the
* 1.5 tick we need. But, because the bias is
* statistical, we have to test that we don't drop below
* the minimum feasible timer (which is 2 ticks).
*/
TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
tp->t_rttmin, TCPTV_REXMTMAX);
/*
* We received an ack for a packet that wasn't retransmitted;
* it is probably safe to discard any error indications we've
* received recently. This isn't quite right, but close enough
* for now (a route might have failed after we sent a segment,
* and the return path might not be symmetrical).
*/
tp->t_softerror = 0;
}
/*
* Determine a reasonable value for maxseg size.
* If the route is known, check route for mtu.
* If none, use an mss that can be handled on the outgoing
* interface without forcing IP to fragment; if bigger than
* an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES
* to utilize large mbufs. If no route is found, route has no mtu,
* or the destination isn't local, use a default, hopefully conservative
* size (usually 512 or the default IP max size, but no more than the mtu
* of the interface), as we can't discover anything about intervening
* gateways or networks. We also initialize the congestion/slow start
* window to be a single segment if the destination isn't local.
* While looking at the routing entry, we also initialize other path-dependent
* parameters from pre-set or cached values in the routing entry.
*
* Also take into account the space needed for options that we
* send regularly. Make maxseg shorter by that amount to assure
* that we can send maxseg amount of data even when the options
* are present. Store the upper limit of the length of options plus
* data in maxopd.
*
* NOTE that this routine is only called when we process an incoming
* segment, for outgoing segments only tcp_mssopt is called.
*
* In case of T/TCP, we call this routine during implicit connection
* setup as well (offer = -1), to initialize maxseg from the cached
* MSS of our peer.
*/
void
tcp_mss(tp, offer)
struct tcpcb *tp;
int offer;
{
register struct rtentry *rt;
struct ifnet *ifp;
register int rtt, mss;
u_long bufsize;
struct inpcb *inp;
struct socket *so;
struct rmxp_tao *taop;
int origoffer = offer;
inp = tp->t_inpcb;
if ((rt = tcp_rtlookup(inp)) == NULL) {
tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
return;
}
#ifndef __REACTOS__
ifp = rt->rt_ifp;
#endif
so = inp->inp_socket;
taop = rmx_taop(rt->rt_rmx);
/*
* Offer == -1 means that we didn't receive SYN yet,
* use cached value in that case;
*/
if (offer == -1)
offer = taop->tao_mssopt;
/*
* Offer == 0 means that there was no MSS on the SYN segment,
* in this case we use tcp_mssdflt.
*/
if (offer == 0)
offer = tcp_mssdflt;
else
/*
* Sanity check: make sure that maxopd will be large
* enough to allow some data on segments even is the
* all the option space is used (40bytes). Otherwise
* funny things may happen in tcp_output.
*/
offer = max(offer, 64);
taop->tao_mssopt = offer;
/*
* While we're here, check if there's an initial rtt
* or rttvar. Convert from the route-table units
* to scaled multiples of the slow timeout timer.
*/
if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
/*
* XXX the lock bit for RTT indicates that the value
* is also a minimum value; this is subject to time.
*/
if (rt->rt_rmx.rmx_locks & RTV_RTT)
tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SLOWHZ);
tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
tcpstat.tcps_usedrtt++;
if (rt->rt_rmx.rmx_rttvar) {
tp->t_rttvar = rt->rt_rmx.rmx_rttvar /
(RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
tcpstat.tcps_usedrttvar++;
} else {
/* default variation is +- 1 rtt */
tp->t_rttvar =
tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE;
}
TCPT_RANGESET(tp->t_rxtcur,
((tp->t_srtt >> 2) + tp->t_rttvar) >> 1,
tp->t_rttmin, TCPTV_REXMTMAX);
}
/*
* if there's an mtu associated with the route, use it
*/
if (rt->rt_rmx.rmx_mtu)
mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
else
{
mss = ifp->if_mtu - sizeof(struct tcpiphdr);
if (!in_localaddr(inp->inp_faddr))
mss = min(mss, tcp_mssdflt);
}
mss = min(mss, offer);
/*
* maxopd stores the maximum length of data AND options
* in a segment; maxseg is the amount of data in a normal
* segment. We need to store this value (maxopd) apart
* from maxseg, because now every segment carries options
* and thus we normally have somewhat less data in segments.
*/
tp->t_maxopd = mss;
/*
* In case of T/TCP, origoffer==-1 indicates, that no segments
* were received yet. In this case we just guess, otherwise
* we do the same as before T/TCP.
*/
if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
(origoffer == -1 ||
(tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP))
mss -= TCPOLEN_TSTAMP_APPA;
if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC &&
(origoffer == -1 ||
(tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC))
mss -= TCPOLEN_CC_APPA;
#if (MCLBYTES & (MCLBYTES - 1)) == 0
if (mss > MCLBYTES)
mss &= ~(MCLBYTES-1);
#else
if (mss > MCLBYTES)
mss = mss / MCLBYTES * MCLBYTES;
#endif
/*
* If there's a pipesize, change the socket buffer
* to that size. Make the socket buffers an integral
* number of mss units; if the mss is larger than
* the socket buffer, decrease the mss.
*/
#ifdef RTV_SPIPE
if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0)
#endif
bufsize = so->so_snd.sb_hiwat;
if (bufsize < mss)
mss = bufsize;
else {
bufsize = roundup(bufsize, mss);
if (bufsize > sb_max)
bufsize = sb_max;
(void)sbreserve(&so->so_snd, bufsize);
}
tp->t_maxseg = mss;
#ifdef RTV_RPIPE
if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0)
#endif
bufsize = so->so_rcv.sb_hiwat;
if (bufsize > mss) {
bufsize = roundup(bufsize, mss);
if (bufsize > sb_max)
bufsize = sb_max;
(void)sbreserve(&so->so_rcv, bufsize);
}
/*
* Don't force slow-start on local network.
*/
if (!in_localaddr(inp->inp_faddr))
tp->snd_cwnd = mss;
if (rt->rt_rmx.rmx_ssthresh) {
/*
* There's some sort of gateway or interface
* buffer limit on the path. Use this to set
* the slow start threshhold, but set the
* threshold to no less than 2*mss.
*/
tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh);
tcpstat.tcps_usedssthresh++;
}
}
/*
* Determine the MSS option to send on an outgoing SYN.
*/
int
tcp_mssopt(tp)
struct tcpcb *tp;
{
struct rtentry *rt;
rt = tcp_rtlookup(tp->t_inpcb);
if (rt == NULL)
return tcp_mssdflt;
#ifndef __REACTOS__
return rt->rt_ifp->if_mtu - sizeof(struct tcpiphdr);
#else
return tcp_mssdflt;
#endif
}
#endif /* TUBA_INCLUDE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -