?? tcp_input.c
字號:
#endif (void) tcp_output(tp); tp->snd_cwnd = tp->snd_ssthresh + tp->t_maxseg * tp->t_dupacks; if (SEQ_GT(onxt, tp->snd_nxt)) tp->snd_nxt = onxt; goto drop; } else if (tp->t_dupacks > tcprexmtthresh) { tp->snd_cwnd += tp->t_maxseg;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_WARNING event */ WV_NET_PORTOUT_EVENT_2 (NET_CORE_EVENT, WV_NET_WARNING, 13, 6, tp->t_inpcb->inp_lport, tp->t_inpcb->inp_fport, WV_NETEVENT_TCPIN_SENDFAIL, WV_NET_RECV, so->so_fd, tp->t_dupacks)#endif /* INCLUDE_WVNET */#endif (void) tcp_output(tp); goto drop; } } else tp->t_dupacks = 0; break; } /* * If the congestion window was inflated to account * for the other side's cached packets, retract it. */ if (tp->t_dupacks > tcprexmtthresh && tp->snd_cwnd > tp->snd_ssthresh) tp->snd_cwnd = tp->snd_ssthresh; 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 we have a timestamp reply, update smoothed * round trip time. If no timestamp is present but * 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 (ts_present) tcp_xmit_timer(tp, tcp_now-ts_ecr+1); else if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp,tp->t_rtt); /* * 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; 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 * (maxseg * (maxseg / cwnd) per packet). */ { register u_int cw = tp->snd_cwnd; register u_int incr = tp->t_maxseg; if (cw > tp->snd_ssthresh) incr = incr * incr / cw; tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale); } 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; } else { sbdrop(&so->so_snd, acked); tp->snd_wnd -= acked; ourfinisacked = 0; } if ((so->so_snd.sb_want > 0) || (so->so_snd.sb_sel) || (sowakeupHook != NULL)) { if (sbspace (&so->so_snd) >= so->so_snd.sb_lowat) 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] = tcp_maxidle; }#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_PORTIN_EVENT_1 (NET_AUX_EVENT, WV_NET_INFO, 33, 15, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_SENDCLOSED, WV_NET_RECV, so->so_fd)#endif /* INCLUDE_WVNET */#endif 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) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_PORTIN_EVENT_1 (NET_AUX_EVENT, WV_NET_INFO, 34, 16, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_CLOSEWAIT, WV_NET_RECV, so->so_fd)#endif /* INCLUDE_WVNET */#endif 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) { tp = tcp_close(tp); 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:#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_PORTIN_EVENT_2 (NET_AUX_EVENT, WV_NET_INFO, 37, 19, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_CLOSE_RESTART, WV_NET_RECV, so->so_fd, TRUE)#endif /* INCLUDE_WVNET */#endif 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. * * More specifically, update the window when: * 1) The ACK flag is set, and either: * a) The segment contains new data (snd_wl1 < ti_seq) OR * b) The segment is a repeat (snd_wl1 == ti_seq). * * 2) In case 1b), one of the following conditions also applies: * a) The segment acknowledges more data (snd_wl2 < ti_ack) OR * b) No new data is acknowledged, but the window size increases. * * The wl2 == ti_ack test might be redundant since the received * ACK value can't realistically decrease when snd_wl1 == ti_seq. */ 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 && tiwin > tp->snd_wnd)) ) )) { /* keep track of pure window updates */ if (ti->ti_len == 0 && tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) tcpstat.tcps_rcvwinupd++; tp->snd_wnd = tiwin; 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 (in one of two places). */ 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 && (so->so_options & SO_OOBINLINE) == 0) tcp_pulloutofband(so, ti, m); } 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); } 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) { if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { socantrcvmore(so); tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; } switch (tp->t_state) { /* * In ESTABLISHED state * enter the CLOSE_WAIT state. */ case TCPS_SYN_RECEIVED: break; /* avoid SYN+FIN death */ case TCPS_ESTABLISHED: #ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_PORTIN_EVENT_1 (NET_AUX_EVENT, WV_NET_INFO, 35, 17, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_RECVCLOSED, WV_NET_RECV, so->so_fd)#endif /* INCLUDE_WVNET */#endif 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:#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_PORTIN_EVENT_1 (NET_AUX_EVENT, WV_NET_INFO, 36, 18, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_CLOSING, WV_NET_RECV, so->so_fd)#endif /* INCLUDE_WVNET */#endif 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:#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_PORTIN_EVENT_1 (NET_AUX_EVENT, WV_NET_INFO, 34, 16, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_CLOSEWAIT, WV_NET_RECV, so->so_fd)#endif /* INCLUDE_WVNET */#endif 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:#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_PORTIN_EVENT_2 (NET_AUX_EVENT, WV_NET_INFO, 37, 19, ti->ti_sport, ti->ti_dport, WV_NETEVENT_TCPIN_CLOSE_RESTART, WV_NET_RECV, so->so_fd, FALSE)#endif /* INCLUDE_WVNET */#endif 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.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -