📄 tcp_input.c
字号:
PRINTXTID(1, ("T_DISCONNECT (#2) \n")); } }#endif XTI freeondrop = 0; tp = tcp_drop(tp, ECONNREFUSED); if (smp && smp_owner(&so->lk_socket) == 0){ dropsocket = 0; goto drop; } goto drop; case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT:#ifdef XTI /* set T_DISCONNECT bit on in socket struct field * so->so_xticb.xti_evtarray when so->so_xticb.xti_epvalid and * *->xti_evtenabled are on. */ if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */ if (so->so_xticb.xti_evtenabled) { so->so_xticb.xti_evtarray[XTI_EVT_T_DISCONNECT]++; PRINTXTID(1, ("T_DISCONNECT (#3) \n")); } }#endif XTI freeondrop = 0; tp = tcp_drop(tp, ECONNRESET); if (smp && smp_owner(&so->lk_socket) == 0){ dropsocket = 0; goto drop; } goto drop; case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT:#ifdef XTI /* set T_DISCONNECT bit on in socket struct field * so->so_xticb.xti_evtarray when so->so_xticb.xti_epvalid and * *->xti_evtenabled are on. */ if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */ if (so->so_xticb.xti_evtenabled) { so->so_xticb.xti_evtarray[XTI_EVT_T_DISCONNECT]++; PRINTXTID(1, ("T_DISCONNECT (#4) \n")); } }#endif XTI freeondrop = 0; tp = tcp_close(tp);#ifdef TCPLOOPBACK case TCPS_CLOSED:#endif if (smp && smp_owner(&so->lk_socket) == 0){ dropsocket = 0; goto drop; } goto drop; } /* * If a SYN is in the window, then this is an * error and we send an RST and drop the connection. */ /* tcp_drop cannot be called before dropwithreset without * guaranteeing a good socket and tp. Duplicate all * dropwithreset here, but change where tcp_drop() is called. */ if (tiflags & TH_SYN) { if ((tiflags & TH_RST) || in_broadcast(ti->ti_dst)){ goto drop; } if (tiflags & TH_ACK){ tcp_respond(tp,ti,(tcp_seq)0,ti->ti_ack, TH_RST, so); } else { if (tiflags & TH_SYN) ti->ti_len++; tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK, so); } tp = tcp_drop(tp, ECONNRESET); if (om) { (void) m_free(om); } if (dropsocket) { if (smp && smp_owner(&so->lk_socket) == 1) (void) soabort(so); if (smp && smp_owner(&so->lk_socket)) smp_unlock(&so->lk_socket); if ( !smp ) (void) soabort(so); } else { if (smp && smp_owner(&so->lk_socket)) smp_unlock(&so->lk_socket); } return; } /* * If the ACK bit is off we drop the segment and return. */ if ((tiflags & TH_ACK) == 0){ goto drop; } /* * Ack processing. */ switch (tp->t_state) { /* * In SYN_RECEIVED state if the ack ACKs our SYN then enter * ESTABLISHED state and continue processing, otherwise * send an RST. */ case TCPS_SYN_RECEIVED: if (SEQ_GT(tp->snd_una, ti->ti_ack) || SEQ_GT(ti->ti_ack, tp->snd_max)){ goto dropwithreset; } TCPSTAT(tcps_connects++);#ifdef XTI if (!(tp->t_acceptmode))#endif XTI soisconnected(so); tp->t_state = TCPS_ESTABLISHED; tp->t_maxseg = MIN(tp->t_maxseg, tcp_mss(tp)); (void) tcp_reass(tp, (struct tcpiphdr *)0); tp->snd_wl1 = ti->ti_seq - 1; /* fall into ... */ /* * In ESTABLISHED state: drop duplicate ACKs; ACK out of range * ACKs. If the ack is in the range * tp->snd_una < ti->ti_ack <= tp->snd_max * then advance tp->snd_una to ti->ti_ack and drop * data from the retransmission queue. If this ACK reflects * more up to date window information we update our window information. */ case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { if (ti->ti_len == 0 && ti->ti_win == tp->snd_wnd) { TCPSTAT(tcps_rcvdupack++); /* * If we have outstanding data (not a * window probe), this is a completely * duplicate ack (ie, window info didn't * change), the ack is the biggest we've * seen and we've seen exactly our rexmt * threshhold of them, assume a packet * has been dropped and retransmit it. * Kludge snd_nxt & the congestion * window so we send only this one * packet. If this packet fills the * only hole in the receiver's seq. * space, the next real ack will fully * open our window. This means we * have to do the usual slow-start to * not overwhelm an intermediate gateway * with a burst of packets. Leave * here with the congestion window set * to allow 2 packets on the next real * ack and the exp-to-linear thresh * set for half the current window * size (since we know we're losing at * the current window size). */ if (tp->t_timer[TCPT_REXMT] == 0 || ti->ti_ack != tp->snd_una) tp->t_dupacks = 0; else if (++tp->t_dupacks == tcprexmtthresh) { tcp_seq onxt = tp->snd_nxt; u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; if (win < 2) win = 2; tp->snd_ssthresh = win * tp->t_maxseg; tp->t_timer[TCPT_REXMT] = 0; tp->t_rtt = 0; tp->snd_nxt = ti->ti_ack; tp->snd_cwnd = tp->t_maxseg; (void) tcp_output(tp); if (SEQ_GT(onxt, tp->snd_nxt)) tp->snd_nxt = onxt; goto drop; } } else tp->t_dupacks = 0; break; } tp->t_dupacks = 0; if (SEQ_GT(ti->ti_ack, tp->snd_max)) { TCPSTAT(tcps_rcvacktoomuch++); goto dropafterack; } acked = ti->ti_ack - tp->snd_una; TCPSTAT(tcps_rcvackpack++); TCPSTAT(tcps_rcvackbyte += acked); /* * If transmit timer is running and timed sequence * number was acked, update smoothed round trip time. * Since we now have an rtt measurement, cancel the * timer backoff (cf., Phil Karn's retransmit alg.). * Recompute the initial retransmit timer. */ if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { TCPSTAT(tcps_rttupdated++); if (tp->t_srtt != 0) { register short delta; /* * 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 t_rtt to origin 0. */ tp->t_rtt--; delta = tp->t_rtt - (tp->t_srtt >> 3); 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 + 2 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 >> 2); 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 2*rtt) */ tp->t_srtt = tp->t_rtt << 3; tp->t_rttvar = tp->t_rtt << 1; } tp->t_rtt = 0; tp->t_rxtshift = 0; TCPT_RANGESET(tp->t_rxtcur, ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1, TCPTV_MIN, TCPTV_REXMTMAX); } /* * If all outstanding data is acked, stop retransmit * timer and remember to restart (more output or persist). * If there is more data to be acked, restart retransmit * timer, using current (possibly backed-off) value. */ if (ti->ti_ack == tp->snd_max) { tp->t_timer[TCPT_REXMT] = 0; tp->t_rxtshift = 0; /* reset to initial value */ needoutput = 1; } else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; /* * When new data is acked, open the congestion window. * If the window gives us less than ssthresh packets * in flight, open exponentially (maxseg per packet). * Otherwise open linearly (maxseg per window, * or maxseg^2 / cwnd per packet). */ { u_int incr = tp->t_maxseg; if (tp->snd_cwnd > tp->snd_ssthresh) incr = MAX(incr * incr / tp->snd_cwnd, 1); tp->snd_cwnd = MIN(tp->snd_cwnd + incr, 65535); /* XXX */ } if (acked > so->so_snd.sb_cc) { tp->snd_wnd -= so->so_snd.sb_cc; sbdrop(&so->so_snd, (int)so->so_snd.sb_cc); ourfinisacked = 1;#ifdef XTI if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */ if (so->so_xticb.xti_evtenabled) { if (so->so_xticb.xti_blocked) { /* flow controlled EWOULDBLOCK */ so->so_xticb.xti_blocked = 0; /* unblocked */ so->so_xticb.xti_evtarray[XTI_EVT_T_GODATA]++; so->so_xticb.xti_evtarray[XTI_EVT_T_GOEXDATA]++; PRINTXTID(1, ("T_GODATA (#1) \n")); PRINTXTID(1, ("T_GOEXDATA (#1) \n")); } } } #endif XTI } else { sbdrop(&so->so_snd, acked); tp->snd_wnd -= acked; ourfinisacked = 0;#ifdef XTI if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */ if (so->so_xticb.xti_evtenabled) { if (so->so_xticb.xti_blocked) { /* flow controlled EWOULDBLOCK */ so->so_xticb.xti_blocked = 0; /* unblocked */ so->so_xticb.xti_evtarray[XTI_EVT_T_GODATA]++; so->so_xticb.xti_evtarray[XTI_EVT_T_GOEXDATA]++; PRINTXTID(1, ("T_GODATA (#2) \n")); PRINTXTID(1, ("T_GOEXDATA (#2) \n")); } } } #endif XTI } if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel) sowwakeup(so); tp->snd_una = ti->ti_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; switch (tp->t_state) { /* * In FIN_WAIT_1 STATE in addition to the processing * for the ESTABLISHED state if our FIN is now acknowledged * then enter FIN_WAIT_2. */ case TCPS_FIN_WAIT_1: if (ourfinisacked) { /* * If we can't receive any more * data, then closing user can proceed. * Starting the timer is contrary to the * specification, but if we don't get a FIN * we'll hang forever. */ if (so->so_state & SS_CANTRCVMORE) { soisdisconnected(so); tp->t_timer[TCPT_2MSL] = TCPTV_MAXIDLE; } tp->t_state = TCPS_FIN_WAIT_2; } break; /* * In CLOSING STATE in addition to the processing for * the ESTABLISHED state if the ACK acknowledges our FIN * then enter the TIME-WAIT state, otherwise ignore * the segment. */ case TCPS_CLOSING: if (ourfinisacked) { tp->t_state = TCPS_TIME_WAIT; tcp_canceltimers(tp); tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; soisdisconnected(so); } break; /* * In LAST_ACK, we may still be waiting for data to drain * and/or to be acked, as well as for the ack of our FIN. * If our FIN is now acknowledged, delete the TCB, * enter the closed state and return. */ case TCPS_LAST_ACK: if (ourfinisacked) { freeondrop = 0; tp = tcp_close(tp); if ( smp && smp_owner(&so->lk_socket) == 0){ dropsocket = 0; goto drop; } goto drop; } break; /* * In TIME_WAIT state the only thing that should arrive * is a retransmission of the remote FIN. Acknowledge * it and restart the finack timer. */ case TCPS_TIME_WAIT: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; goto dropafterack; } }step6: /* * Update window information. * Don't look at window if no ACK: TAC's send garbage on first SYN. */ if ((tiflags & TH_ACK) && (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd))) { /* keep track of pure window updates */ if (ti->ti_len == 0 && tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd) TCPSTAT(tcps_rcvwinupd++); tp->snd_wnd = ti->ti_win; tp->snd_wl1 = ti->ti_seq; tp->snd_wl2 = ti->ti_ack; if (tp->snd_wnd > tp->max_sndwnd) tp->max_sndwnd = tp->snd_wnd; needoutput = 1; } /* * Process segments with URG. */ if ((tiflags & TH_URG) && ti->ti_urp && TCPS_HAVERCVDFIN(tp->t_state) == 0) { /* * This is a kludge, but if we receive and accept * random urgent pointers, we'll crash in * soreceive. It's hard to imagine someone * actually wanting to send this much urgent data. */ if (ti->ti_urp + so->so_rcv.sb_cc > SB_MAX) { ti->ti_urp = 0; /* XXX */ tiflags &= ~TH_URG; /* XXX */ goto dodata; /* XXX */ } /* * If this segment advances the known urgent pointer, * then mark the data stream. This should not happen * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since * a FIN has been received from the remote side. * In these states we ignore the URG. * * According to RFC961 (Assigned Protocols), * the urgent pointer points to the last octet * of urgent data. We continue, however, * to consider it to indicate the first octet * of data past the urgent section * as the original spec states. */ if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { tp->rcv_up = ti->ti_seq + ti->ti_urp; so->so_oobmark = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt) - 1; if (so->so_oobmark == 0) so->so_state |= SS_RCVATMARK; sohasoutofband(so); tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); } /* * Remove out of band data so doesn't get presented to user. * This can happen independent of advancing the URG pointer, * but if two URG's are pending at once, some out-of-band * data may creep in... ick. */ if (ti->ti_urp <= ti->ti_len &&#ifdef XTI (so->so_options & SO_OOBINLINE) == 0) { PRINTXTID(32, ("Calling tcp_pulloobxti\n")); tcp_pulloobxti(so, ti); } else /* * Because they don't present oob data to user * we must update our event structures. */ { /* For now do not touch event info sbdrop(&so->so_exrcv, so->so_exrcv.sb_cc); so->so_xticb.xti_evtarray[XTI_EVT_T_EXDATA] = 0; */ }#else (so->so_options & SO_OOBINLINE) == 0) tcp_pulloutofband(so, ti);#endif XTI } else /* * If no out of band data is expected, * pull receive urgent pointer along * with the receive window. */ if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) tp->rcv_up = tp->rcv_nxt;dodata: /* XXX */ /* * Process the segment text, merging it into the TCP sequencing queue, * and arranging for acknowledgment of receipt if necessary. * This process logically involves adjusting tp->rcv_wnd as data * is presented to the user (this happens in tcp_usrreq.c, * case PRU_RCVD). If a FIN has already been received on this * connection then we just ignore the text. */ if ((ti->ti_len || (tiflags&TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { TCP_REASS(tp, ti, m, so, tiflags); if (tcpnodelack == 0) tp->t_flags |= TF_DELACK; else tp->t_flags |= TF_ACKNOW; /* * Note the amount of data that peer has sent into * our window, in order to estimate the sender's * buffer size. */ len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); if (len > tp->max_rcvd) tp->max_rcvd = len; } else { m_freem(m); tiflags &= ~TH_FIN; } /* * If FIN is received ACK the FIN and let the user know * that the connection is closing. */ if ((tiflags & TH_FIN) || /* 1/91.us. According to rfc793, the normal tcp state transitions * on close are: * (side1) ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -