📄 tcp_input.c
字号:
static voidtcp_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. */static voidtcp_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. */static voidtcp_xmit_timer(tp, rtt) register struct tcpcb *tp; short rtt;{ register int delta; tcpstat.tcps_rttupdated++; tp->t_rttupdated++; if (tp->t_srtt != 0) { /* * srtt is stored as fixed point with 5 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) << TCP_DELTA_SHIFT) - (tp->t_srtt >> (TCP_RTT_SHIFT - TCP_DELTA_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 4 bits after the * binary point (scaled by 16). 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 - TCP_DELTA_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), max(tp->t_rttmin, rtt + 2), 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. */voidtcp_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; } ifp = rt->rt_ifp; 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. */inttcp_mssopt(tp) struct tcpcb *tp;{ struct rtentry *rt; rt = tcp_rtlookup(tp->t_inpcb); if (rt == NULL) return tcp_mssdflt; return rt->rt_ifp->if_mtu - sizeof(struct tcpiphdr);}#endif /* TUBA_INCLUDE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -