📄 tcp_input.c
字号:
/* * In SYN_RECEIVED and ESTABLISHED STATES * enter the CLOSE_WAIT state. */ case TCPS_SYN_RECEIVED: case TCPS_ESTABLISHED: tp->t_state = TCPS_CLOSE_WAIT; break; /* * If still in FIN_WAIT_1 STATE FIN has not been acked so * enter the CLOSING state. */ case TCPS_FIN_WAIT_1: tp->t_state = TCPS_CLOSING; break; /* * In FIN_WAIT_2 state enter the TIME_WAIT state, * starting the time-wait timer, turning off the other * standard timers. */ case TCPS_FIN_WAIT_2: tp->t_state = TCPS_TIME_WAIT; tcp_canceltimers(tp); tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; soisdisconnected(so); break; /* * In TIME_WAIT state restart the 2 MSL time_wait timer. */ case TCPS_TIME_WAIT: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; break; } } if (so->so_options & SO_DEBUG) (*tcpTraceRtn)(TA_INPUT, ostate, tp, &tcp_saveti, 0); /* * Return any desired output. */ if (needoutput || (tp->t_flags & TF_ACKNOW)) (void) tcp_output(tp); return;dropafterack: /* * Generate an ACK dropping incoming segment if it occupies * sequence space, where the ACK reflects our state. */ if (tiflags & TH_RST) goto drop; m_freem(m); tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); return;dropwithreset: /* * Generate a RST, dropping incoming segment. * Make ACK acceptable to originator of segment. * Don't bother to respond if destination was broadcast/multicast. */ if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST) || IN_MULTICAST(ntohl(ti->ti_dst.s_addr))) goto drop; if (tiflags & TH_ACK) tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); else { if (tiflags & TH_SYN) ti->ti_len++; tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK); } /* MIB-II Count # of Resets Sent */ tcpOutRsts++; /* destroy temporarily created socket */ if (dropsocket) (void) soabort(so); return;drop: /* * Drop space held by incoming segment and return. */ if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) (*tcpTraceRtn)(TA_DROP, ostate, tp, &tcp_saveti, 0); m_freem(m); /* destroy temporarily created socket */ if (dropsocket) (void) soabort(so); return;#ifndef TUBA_INCLUDE}voidtcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr) struct tcpcb *tp; u_char *cp; int cnt; struct tcpiphdr *ti; int *ts_present; u_long *ts_val, *ts_ecr;{ u_short mss; 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); (void) tcp_mss(tp, mss); /* sets t_maxseg */ 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; *ts_present = 1; bcopy((char *)cp + 2, (char *) ts_val, sizeof(*ts_val)); NTOHL(*ts_val); bcopy((char *)cp + 6, (char *) ts_ecr, sizeof(*ts_ecr)); NTOHL(*ts_ecr); /* * 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 = *ts_val; tp->ts_recent_age = tcp_now; } break; } }}/* * 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. */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. */voidtcp_xmit_timer(tp, rtt) register struct tcpcb *tp; short rtt;{ register short delta; tcpstat.tcps_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 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. */inttcp_mss(tp, offer) register struct tcpcb *tp; u_int offer;{ struct route *ro; register struct rtentry *rt; struct ifnet *ifp; register int rtt, mss; u_long bufsize; struct inpcb *inp; struct socket *so; extern int tcp_mssdflt; inp = tp->t_inpcb; ro = &inp->inp_route; if ((rt = ro->ro_rt) == (struct rtentry *)0) { /* No route yet, so try to acquire one */ if (inp->inp_faddr.s_addr != INADDR_ANY) { ro->ro_dst.sa_family = AF_INET; ro->ro_dst.sa_len = sizeof(ro->ro_dst); ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = inp->inp_faddr; TOS_SET (&ro->ro_dst, inp->inp_ip.ip_tos); rtalloc(ro); } if ((rt = ro->ro_rt) == (struct rtentry *)0) return (tcp_mssdflt); } ifp = rt->rt_ifp; so = inp->inp_socket;#ifdef RTV_MTU /* if route characteristics exist ... */ /* * 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 MTU 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)); if (rt->rt_rmx.rmx_rttvar) tp->t_rttvar = rt->rt_rmx.rmx_rttvar / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); 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#endif /* RTV_MTU */ { mss = ifp->if_mtu - sizeof(struct tcpiphdr); if (!in_localaddr(inp->inp_faddr)) mss = min(mss, tcp_mssdflt); } /* * The current mss, t_maxseg, is initialized to the default value. * If we compute a smaller value, reduce the current mss. * If we compute a larger value, return it for use in sending * a max seg size option, but don't store it for use * unless we received an offer at least that large from peer. * However, do not accept offers under 32 bytes. */ if (offer) mss = min(mss, offer); mss = max(mss, 32); /* sanity */ if (mss < tp->t_maxseg || offer != 0) { /* * 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; tp->t_maxseg = mss;#ifdef RTV_RPIPE if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0)#endif bufsize = so->so_rcv.sb_hiwat; } tp->snd_cwnd = mss;#ifdef RTV_SSTHRESH 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); }#endif /* RTV_MTU */ return (mss);}#endif /* TUBA_INCLUDE */#ifdef TCP_DEBUG /* XXX just for debugging */void tcbShow ( FAST struct inpcb *pinPcb /* pointer to the pcb control block */ ) { struct tcpcb * pTcpCb; /* pointer to tcp Control block */ pTcpCb = (struct tcpcb *) pinPcb->inp_ppcb; printf ("send unacknowledged: %8u\n", pTcpCb->snd_una); printf ("send next: %8u\n", pTcpCb->snd_nxt); printf ("send window update seg seqnumber: %8u\n", pTcpCb->snd_wl1); printf ("send window updata seg ack number: %8u\n", pTcpCb->snd_wl2); printf ("send window: %8u\n", pTcpCb->snd_wnd); printf ("recv window: %8u\n", pTcpCb->rcv_wnd); printf ("recv next: %8u\n", pTcpCb->rcv_nxt); printf ("recv advertised window by other end: %8u\n", pTcpCb->rcv_adv); printf ("send highest sequence number sent: %8u\n", pTcpCb->snd_max); printf ("congestion controlled window: %8u\n", pTcpCb->snd_cwnd); printf ("congestion threshold: %8u\n", pTcpCb->snd_ssthresh); printf ("largest window peer has offered: %8u\n", pTcpCb->max_sndwnd); printf ("send scale %8u\n", pTcpCb->snd_scale) ; printf ("recv scale %8u\n", pTcpCb->rcv_scale) ; printf ("send pending window scale %8u\n", pTcpCb->request_r_scale) ; printf ("recv pending window scale %8u\n", pTcpCb->requested_s_scale) ; }#endif /* XXX just for debugging */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -