📄 tcp_input.c
字号:
} } else { /* didn't get lock on socket.... still back off if referenced*/ smp_unlock(&lk_tcb); waitcnt = 1000000; while (so->ref > 0 && waitcnt--) ; if (owner) owner=0; else smp_lock(&lk_tcb,LK_RETRY); goto findpcb; } inp_temp = in_pcblookup (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD); if (inp != inp_temp) { freeondrop = 0; smp_unlock(&so->lk_socket); /* We are unlocked so don't keep a messy socket pointer * around because it could confuse tcp_respond. */ so = NULL; if (owner){ smp_unlock(&lk_tcb); owner = 0; } goto dropwithreset; } if ( owner){ smp_unlock(&lk_tcb); } } /* * If the state is CLOSED (i.e., TCB does not exist) then * all data in the incoming segment is discarded. * If the TCB exists but is in CLOSED state, it is embryonic, * but should either do a listen or a connect soon. */ tp = intotcpcb(inp); if (tp == 0) goto dropwithreset;#ifdef XTI PRINTXTID(128, ("tcp_input: tp =%x,tp->t_state = %s\n",tp,tcpstates[tp->t_state])); if (ti->ti_flags) PRINTXTID(128, ("<")); if (ti->ti_flags & TH_FIN) PRINTXTID(128, ("FIN ")); if (ti->ti_flags & TH_SYN) PRINTXTID(128, ("SYN ")); if (ti->ti_flags & TH_RST) PRINTXTID(128, ("RST ")); if (ti->ti_flags & TH_PUSH) PRINTXTID(128, ("PSH ")); if (ti->ti_flags & TH_ACK) PRINTXTID(128, ("ACK ")); if (ti->ti_flags & TH_URG) PRINTXTID(128, ("URG ")); if (ti->ti_flags) PRINTXTID(128, (">\n"));#endif XTI if (tp->t_state == TCPS_CLOSED) goto drop; if (so->so_options & SO_DEBUG) { ostate = tp->t_state; tcp_saveti = *ti; } /* * Unlock the old and lock the new... */ if (so->so_options & SO_ACCEPTCONN) { so_tmp = sonewconn(so); if (so_tmp == 0) { freeondrop = 0; goto drop; } SO_LOCK(so_tmp); smp_unlock(&so->lk_socket); so = so_tmp; /* * This is ugly, but .... * * Mark socket as temporary until we're * committed to keeping it. The code at * ``drop'' and ``dropwithreset'' check the * flag dropsocket to see if the temporary * socket created here should be discarded. * We mark the socket as discardable until * we're committed to it below in TCPS_LISTEN. */ dropsocket++; inp = (struct inpcb *)so->so_pcb; inp->inp_laddr = ti->ti_dst; inp->inp_lport = ti->ti_dport; inp->inp_options = ip_srcroute(); tp = intotcpcb(inp); tp->t_state = TCPS_LISTEN; } /* * Segment received on connection. * Reset idle time and keep-alive timer. */ tp->t_idle = 0; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; /* * Process options if not in LISTEN state, * else do it below (after getting remote address). */ if (om && tp->t_state != TCPS_LISTEN) { tcp_dooptions(tp, om, ti); om = 0; } /* * Calculate amount of space in receive window, * and then do TCP input processing. * Receive window is amount of space in rcv queue, * but not less than advertised window. */ { int win; win = sbspace(&so->so_rcv); if (win < 0) win = 0; tp->rcv_wnd = MAX(win, (int)(tp->rcv_adv - tp->rcv_nxt)); } switch (tp->t_state) { /* * If the state is LISTEN then ignore segment if it contains an RST. * If the segment contains an ACK then it is bad and send a RST. * If it does not contain a SYN then it is not interesting; drop it. * Don't bother responding if the destination was a broadcast. * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial * tp->iss, and send a segment: * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. * Fill in remote peer address fields if not previously specified. * Enter SYN_RECEIVED state, and process any other fields of this * segment in this state. */ case TCPS_LISTEN: { struct mbuf *am; register struct sockaddr_in *sin; if (tiflags & TH_RST){ goto drop; } if (tiflags & TH_ACK){ goto dropwithreset; } if ((tiflags & TH_SYN) == 0){ goto drop;} if (in_broadcast(ti->ti_dst)){ goto drop; } am = m_get(M_DONTWAIT, MT_SONAME); if (am == NULL){ goto drop; } am->m_len = sizeof (struct sockaddr_in); sin = mtod(am, struct sockaddr_in *); sin->sin_family = AF_INET; sin->sin_addr = ti->ti_src; sin->sin_port = ti->ti_sport; laddr = inp->inp_laddr; if (inp->inp_laddr.s_addr == INADDR_ANY) inp->inp_laddr = ti->ti_dst; /* Call in_pcbconnect() with smp lock set */ /* 4.13.89.us Following if/else is brought * to you courtesy of the protocol timeout * timers. */ if (!owner){ if (in_pcbconnect(inp, am)) { inp->inp_laddr = laddr; (void) m_free(am); goto drop; } }else{ so->ref = 9; smp_unlock(&so->lk_socket); smp_lock(&lk_tcb, LK_RETRY); smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; if (in_pcbconnect(inp, am)) { smp_unlock(&lk_tcb); inp->inp_laddr = laddr; (void) m_free(am); goto drop; } smp_unlock(&lk_tcb); } (void) m_free(am); tp->t_template = tcp_template(tp); if (tp->t_template == 0) { tp = tcp_drop(tp, ENOBUFS); dropsocket = 0; if ( smp && smp_owner(&so->lk_socket) == 0){ dropsocket = 0; goto drop; } goto drop; } if (om) { tcp_dooptions(tp, om, ti); om = 0; } smp_lock(&lk_tcpiss, LK_RETRY); if (iss) tp->iss = iss; else tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; smp_unlock(&lk_tcpiss); tp->irs = ti->ti_seq; tcp_sendseqinit(tp); tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW;#ifdef XTI if (tp->t_acceptmode) { tp->t_flags &= ~(TF_ACKNOW); soisconnected(so); } /* bump T_LISTEN count in socket struct field * so->so_xticb.xti_evtarray when so->so_xticb.xti_epvalid and * *->evtenabled are on. */ if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */ /* load tcp options to be read by *_CONOPT */ tp->xti_inbound_qos.precedence = xti_precedence; tp->xti_inbound_qos.timeout = tp->xti_neg_qos.timeout; tp->xti_inbound_qos.max_seg_size = tp->t_maxseg; tp->xti_inbound_qos.secopt = xti_secopt; if (so->so_xticb.xti_evtenabled) { so->so_xticb.xti_evtarray[XTI_EVT_T_LISTEN]++; PRINTXTID(1, ("T_LISTEN (#1) \n")); } }#endif XTI tp->t_state = TCPS_SYN_RECEIVED; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; dropsocket = 0; /* committed to socket */ TCPSTAT(tcps_accepts++); goto trimthenstep6; } /* * If the state is SYN_SENT: * if seg contains an ACK, but not for our SYN, drop the input. * if seg contains a RST, then drop the connection. * if seg does not contain SYN, then drop it. * Otherwise this is an acceptable SYN segment * initialize tp->rcv_nxt and tp->irs * if seg contains ack then advance tp->snd_una * if SYN has been acked change to ESTABLISHED else SYN_RCVD state * arrange for segment to be acked (eventually) * continue processing rest of data/controls, beginning with URG */ case TCPS_SYN_SENT: if ((tiflags & TH_ACK) && (SEQ_LEQ(ti->ti_ack, tp->iss) || SEQ_GT(ti->ti_ack, tp->snd_max))) { goto dropwithreset; } if (tiflags & TH_RST) { if (tiflags & TH_ACK) { freeondrop = 0;#ifdef XTI /* set T_DISCONNECT bit on in socket struct field * so->so_xticb.xti_evtarray when so->so_xticb.xti_epvalid and * *->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 (#1) \n")); } }#endif XTI tp = tcp_drop(tp, ECONNREFUSED); if (smp && smp_owner(&so->lk_socket) == 0){ dropsocket = 0; goto drop; } } goto drop; } if ((tiflags & TH_SYN) == 0){ goto drop; } if (tiflags & TH_ACK) { tp->snd_una = ti->ti_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; } tp->t_timer[TCPT_REXMT] = 0; tp->irs = ti->ti_seq; tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW; if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { TCPSTAT(tcps_connects++); soisconnected(so); tp->t_state = TCPS_ESTABLISHED; tp->t_maxseg = MIN(tp->t_maxseg, tcp_mss(tp));#ifdef XTI /* set T_CONNECT 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_CONNECT]++; PRINTXTID(1, ("T_CONNECT (#1) \n")); } tp->xti_inbound_qos.precedence = xti_precedence; tp->xti_inbound_qos.timeout = tp->xti_neg_qos.timeout; tp->xti_inbound_qos.max_seg_size = tp->t_maxseg; tp->xti_inbound_qos.secopt = xti_secopt; }#endif XTI (void) tcp_reass(tp, (struct tcpiphdr *)0); /* * if we didn't have to retransmit the SYN, * use its rtt as our initial srtt & rtt var. */ if (tp->t_rtt) { tp->t_srtt = tp->t_rtt << 3; tp->t_rttvar = tp->t_rtt << 1; TCPT_RANGESET(tp->t_rxtcur, ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1, TCPTV_MIN, TCPTV_REXMTMAX); tp->t_rtt = 0; }#ifdef XTI } else { tp->t_state = TCPS_SYN_RECEIVED; /* set T_LISTEN 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 */ /* load tcp options to be read by *_CONOPT */ tp->xti_inbound_qos.precedence = xti_precedence; tp->xti_inbound_qos.timeout = tp->xti_neg_qos.timeout; tp->xti_inbound_qos.max_seg_size = tp->t_maxseg; tp->xti_inbound_qos.secopt = xti_secopt; if (so->so_xticb.xti_evtenabled) { so->so_xticb.xti_evtarray[XTI_EVT_T_LISTEN]++; PRINTXTID(1, ("T_LISTEN (#2) \n")); } } }#else } else tp->t_state = TCPS_SYN_RECEIVED;#endif XTItrimthenstep6: /* * Advance ti->ti_seq to correspond to first data byte. * If data, trim to stay within window, * dropping FIN if necessary. */ ti->ti_seq++; if (ti->ti_len > tp->rcv_wnd) { todrop = ti->ti_len - tp->rcv_wnd; m_adj(m, -todrop); ti->ti_len = tp->rcv_wnd; tiflags &= ~TH_FIN; TCPSTAT(tcps_rcvpackafterwin++); TCPSTAT(tcps_rcvbyteafterwin += todrop); } tp->snd_wl1 = ti->ti_seq - 1; tp->rcv_up = ti->ti_seq; goto step6; } /* * States other than LISTEN or SYN_SENT. * First check that at least some bytes of segment are within * receive window. If segment begins before rcv_nxt, * drop leading data (and SYN); if nothing left, just ack. */ todrop = tp->rcv_nxt - ti->ti_seq; if (todrop > 0) { if (tiflags & TH_SYN) { tiflags &= ~TH_SYN; ti->ti_seq++; if (ti->ti_urp > 1) ti->ti_urp--; else tiflags &= ~TH_URG; todrop--; } if (todrop > ti->ti_len || todrop == ti->ti_len && (tiflags&TH_FIN) == 0) {/* #ifdef TCP_COMPAT_42 */ /* * Don't toss RST in response to 4.2-style keepalive. */ if (ti->ti_seq == tp->rcv_nxt - 1 && tiflags & TH_RST){ goto do_rst;}/* #endif */ TCPSTAT(tcps_rcvduppack++); TCPSTAT(tcps_rcvdupbyte += ti->ti_len); todrop = ti->ti_len; tiflags &= ~TH_FIN; tp->t_flags |= TF_ACKNOW; } else { TCPSTAT(tcps_rcvpartduppack++); TCPSTAT(tcps_rcvpartdupbyte += todrop); } m_adj(m, todrop); ti->ti_seq += todrop; ti->ti_len -= todrop; if (ti->ti_urp > todrop) ti->ti_urp -= todrop; else { tiflags &= ~TH_URG; ti->ti_urp = 0; } } /* * If new data is received on a connection after the * user processes are gone, then RST the other end. */ if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { freeondrop = 0; TCPSTAT(tcps_rcvafterclose++); tp = tcp_close(tp); if ( smp && smp_owner(&so->lk_socket) == 0){ dropsocket = 0; /* The socket has been freed by tcp_close() * The above smp_owner check should be removed * The following line will prevent the machine * from panicing. */ so = NULL; goto dropwithreset; } goto dropwithreset; } if (tp->rcv_wnd == 0) { /* * If window is closed can only take segments at * window edge, and have to drop data and PUSH from * incoming segments. */ if (tp->rcv_nxt != ti->ti_seq) { TCPSTAT(tcps_rcvpackafterwin++); TCPSTAT(tcps_rcvbyteafterwin += ti->ti_len); goto dropafterack; } if (ti->ti_len > 0) { if (ti->ti_len == 1) TCPSTAT(tcps_rcvwinprobe++); else { TCPSTAT(tcps_rcvpackafterwin++); TCPSTAT(tcps_rcvbyteafterwin += ti->ti_len); } m_adj(m, ti->ti_len); ti->ti_len = 0; tiflags &= ~(TH_PUSH|TH_FIN); } } else { /* * If segment ends after window, drop trailing data * (and PUSH and FIN); if nothing left, just ACK. */ todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); if (todrop > 0) { if (todrop >= ti->ti_len) { /* * If a new connection request is received * while in TIME_WAIT, drop the old connection * and start over if the sequence numbers * are above the previous ones. */ if (tiflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT && SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { iss = tp->rcv_nxt + TCP_ISSINCR; (void) tcp_close(tp); /* sofree may not really free the * socket and will return with the old * socket locked. */ if (smp && smp_owner(&so->lk_socket)) smp_unlock(&so->lk_socket); goto findpcb; } if (todrop == 1) TCPSTAT(tcps_rcvwinprobe++); else { TCPSTAT(tcps_rcvpackafterwin++); TCPSTAT(tcps_rcvbyteafterwin += ti->ti_len); } goto dropafterack; } TCPSTAT(tcps_rcvpackafterwin++); TCPSTAT(tcps_rcvbyteafterwin += todrop); m_adj(m, -todrop); ti->ti_len -= todrop; tiflags &= ~(TH_PUSH|TH_FIN); } }/* #ifdef TCP_COMPAT_42 */do_rst:/* #endif */ /* * If the RST bit is set examine the state: * SYN_RECEIVED STATE: * If passive open, return to LISTEN state. * If active open, inform user that connection was refused. * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: * Inform user that connection was reset, and close tcb. * CLOSING, LAST_ACK, TIME_WAIT STATES * Close the tcb. */ if (tiflags&TH_RST) switch (tp->t_state) { case TCPS_SYN_RECEIVED:#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]++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -