⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp_input.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 5 页
字号:
				so2 = sodropablereq(so);				if (so2) {					tcp_drop(sototcpcb(so2), ETIMEDOUT);					so2 = sonewconn(so, 0);				}				if (!so2)					goto drop;			}			so = so2;			/*			 * 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;			in_pcbrehash(inp);#if BSD>=43			inp->inp_options = ip_srcroute();#endif			tp = intotcpcb(inp);			tp->t_state = TCPS_LISTEN;			tp->t_flags |= tp0->t_flags & (TF_NOPUSH|TF_NOOPT);			/* Compute proper scaling value from buffer space */			while (tp->request_r_scale < TCP_MAX_WINSHIFT &&			   TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat)				tp->request_r_scale++;		}	}	/*	 * Segment received on connection.	 * Reset idle time and keep-alive timer.	 */	tp->t_idle = 0;	if (TCPS_HAVEESTABLISHED(tp->t_state))		tp->t_timer[TCPT_KEEP] = tcp_keepidle;	/*	 * Process options if not in LISTEN state,	 * else do it below (after getting remote address).	 */	if (tp->t_state != TCPS_LISTEN)		tcp_dooptions(tp, optp, optlen, ti, &to);	/*	 * Header prediction: check for the two common cases	 * of a uni-directional data xfer.  If the packet has	 * no control flags, is in-sequence, the window didn't	 * change and we're not retransmitting, it's a	 * candidate.  If the length is zero and the ack moved	 * forward, we're the sender side of the xfer.  Just	 * free the data acked & wake any higher level process	 * that was blocked waiting for space.  If the length	 * is non-zero and the ack didn't move, we're the	 * receiver side.  If we're getting packets in-order	 * (the reassembly queue is empty), add the data to	 * the socket buffer and note that we need a delayed ack.	 * Make sure that the hidden state-flags are also off.	 * Since we check for TCPS_ESTABLISHED above, it can only	 * be TH_NEEDSYN.	 */	if (tp->t_state == TCPS_ESTABLISHED &&	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&	    ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) &&	    ((to.to_flag & TOF_TS) == 0 ||	     TSTMP_GEQ(to.to_tsval, tp->ts_recent)) &&	    /*	     * Using the CC option is compulsory if once started:	     *   the segment is OK if no T/TCP was negotiated or	     *   if the segment has a CC option equal to CCrecv	     */	    ((tp->t_flags & (TF_REQ_CC|TF_RCVD_CC)) != (TF_REQ_CC|TF_RCVD_CC) ||	     ((to.to_flag & TOF_CC) != 0 && to.to_cc == tp->cc_recv)) &&	    ti->ti_seq == tp->rcv_nxt &&	    tiwin && tiwin == tp->snd_wnd &&	    tp->snd_nxt == tp->snd_max) {		/*		 * If last ACK falls within this segment's sequence numbers,		 * record the timestamp.		 * NOTE that the test is modified according to the latest		 * proposal of the tcplw@cray.com list (Braden 1993/04/26).		 */		if ((to.to_flag & TOF_TS) != 0 &&		   SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) {			tp->ts_recent_age = tcp_now;			tp->ts_recent = to.to_tsval;		}		if (ti->ti_len == 0) {			if (SEQ_GT(ti->ti_ack, tp->snd_una) &&			    SEQ_LEQ(ti->ti_ack, tp->snd_max) &&			    tp->snd_cwnd >= tp->snd_wnd &&			    tp->t_dupacks < tcprexmtthresh) {				/*				 * this is a pure ack for outstanding data.				 */				++tcpstat.tcps_predack;				if ((to.to_flag & TOF_TS) != 0)					tcp_xmit_timer(tp,					    tcp_now - to.to_tsecr + 1);				else if (tp->t_rtt &&					    SEQ_GT(ti->ti_ack, tp->t_rtseq))					tcp_xmit_timer(tp, tp->t_rtt);				acked = ti->ti_ack - tp->snd_una;				tcpstat.tcps_rcvackpack++;				tcpstat.tcps_rcvackbyte += acked;				sbdrop(&so->so_snd, acked);				tp->snd_una = ti->ti_ack;				m_freem(m);				/*				 * If all outstanding data are acked, stop				 * retransmit timer, otherwise restart timer				 * using current (possibly backed-off) value.				 * If process is waiting for space,				 * wakeup/selwakeup/signal.  If data				 * are ready to send, let tcp_output				 * decide between more output or persist.				 */				if (tp->snd_una == tp->snd_max)					tp->t_timer[TCPT_REXMT] = 0;				else if (tp->t_timer[TCPT_PERSIST] == 0)					tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;				if (so->so_snd.sb_flags & SB_NOTIFY)					sowwakeup(so);				if (so->so_snd.sb_cc)					(void) tcp_output(tp);				return;			}		} else if (ti->ti_ack == tp->snd_una &&		    tp->seg_next == (struct tcpiphdr *)tp &&		    ti->ti_len <= sbspace(&so->so_rcv)) {			/*			 * this is a pure, in-sequence data packet			 * with nothing on the reassembly queue and			 * we have enough buffer space to take it.			 */			++tcpstat.tcps_preddat;			tp->rcv_nxt += ti->ti_len;			tcpstat.tcps_rcvpack++;			tcpstat.tcps_rcvbyte += ti->ti_len;			/*			 * Add data to socket buffer.			 */			sbappend(&so->so_rcv, m);			sorwakeup(so);#ifdef TCP_ACK_HACK			/*			 * If this is a short packet, then ACK now - with Nagel			 *	congestion avoidance sender won't send more until			 *	he gets an ACK.			 */			if (tiflags & TH_PUSH) {				tp->t_flags |= TF_ACKNOW;				tcp_output(tp);			} else {				tp->t_flags |= TF_DELACK;			}#else			tp->t_flags |= TF_DELACK;#endif			return;		}	}	/*	 * 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 = imax(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.	 * If it is from this socket, drop it, it must be forged.	 * 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 ((ti->ti_dport == ti->ti_sport) &&		    (ti->ti_dst.s_addr == ti->ti_src.s_addr))			goto drop;		/*		 * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN		 * in_broadcast() should never return true on a received		 * packet with M_BCAST not set.		 */		if (m->m_flags & (M_BCAST|M_MCAST) ||		    IN_MULTICAST(ntohl(ti->ti_dst.s_addr)))			goto drop;		am = m_get(M_DONTWAIT, MT_SONAME);	/* XXX */		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_len = sizeof(*sin);		sin->sin_addr = ti->ti_src;		sin->sin_port = ti->ti_sport;		bzero((caddr_t)sin->sin_zero, sizeof(sin->sin_zero));		laddr = inp->inp_laddr;		if (inp->inp_laddr.s_addr == INADDR_ANY)			inp->inp_laddr = ti->ti_dst;		if (in_pcbconnect(inp, am)) {			inp->inp_laddr = laddr;			(void) m_free(am);			goto drop;		}		(void) m_free(am);		tp->t_template = tcp_template(tp);		if (tp->t_template == 0) {			tp = tcp_drop(tp, ENOBUFS);			dropsocket = 0;		/* socket is already gone */			goto drop;		}		if ((taop = tcp_gettaocache(inp)) == NULL) {			taop = &tao_noncached;			bzero(taop, sizeof(*taop));		}		tcp_dooptions(tp, optp, optlen, ti, &to);		if (iss)			tp->iss = iss;		else			tp->iss = tcp_iss;		tcp_iss += TCP_ISSINCR/4;		tp->irs = ti->ti_seq;		tcp_sendseqinit(tp);		tcp_rcvseqinit(tp);		/*		 * Initialization of the tcpcb for transaction;		 *   set SND.WND = SEG.WND,		 *   initialize CCsend and CCrecv.		 */		tp->snd_wnd = tiwin;	/* initial send-window */		tp->cc_send = CC_INC(tcp_ccgen);		tp->cc_recv = to.to_cc;		/*		 * Perform TAO test on incoming CC (SEG.CC) option, if any.		 * - compare SEG.CC against cached CC from the same host,		 *	if any.		 * - if SEG.CC > chached value, SYN must be new and is accepted		 *	immediately: save new CC in the cache, mark the socket		 *	connected, enter ESTABLISHED state, turn on flag to		 *	send a SYN in the next segment.		 *	A virtual advertised window is set in rcv_adv to		 *	initialize SWS prevention.  Then enter normal segment		 *	processing: drop SYN, process data and FIN.		 * - otherwise do a normal 3-way handshake.		 */		if ((to.to_flag & TOF_CC) != 0) {		    if (taop->tao_cc != 0 && CC_GT(to.to_cc, taop->tao_cc)) {			taop->tao_cc = to.to_cc;			tp->t_state = TCPS_ESTABLISHED;			/*			 * If there is a FIN, or if there is data and the			 * connection is local, then delay SYN,ACK(SYN) in			 * the hope of piggy-backing it on a response			 * segment.  Otherwise must send ACK now in case			 * the other side is slow starting.			 */			if ((tiflags & TH_FIN) || (ti->ti_len != 0 &&			    in_localaddr(inp->inp_faddr)))				tp->t_flags |= (TF_DELACK | TF_NEEDSYN);			else				tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN);			/*			 * Limit the `virtual advertised window' to TCP_MAXWIN			 * here.  Even if we requested window scaling, it will			 * become effective only later when our SYN is acked.			 */			tp->rcv_adv += min(tp->rcv_wnd, TCP_MAXWIN);			tcpstat.tcps_connects++;			soisconnected(so);			tp->t_timer[TCPT_KEEP] = tcp_keepinit;			dropsocket = 0;		/* committed to socket */			tcpstat.tcps_accepts++;			goto trimthenstep6;		    }		/* else do standard 3-way handshake */		} else {		    /*		     * No CC option, but maybe CC.NEW:		     *   invalidate cached value.		     */		     taop->tao_cc = 0;		}		/*		 * TAO test failed or there was no CC option,		 *    do a standard 3-way handshake.		 */		tp->t_flags |= TF_ACKNOW;		tp->t_state = TCPS_SYN_RECEIVED;		tp->t_timer[TCPT_KEEP] = tcp_keepinit;		dropsocket = 0;		/* committed to socket */		tcpstat.tcps_accepts++;		goto trimthenstep6;		}	/*	 * If the state is SYN_RECEIVED:	 *	if seg contains SYN/ACK, send a RST.	 *	if seg contains an ACK, but not for our SYN/ACK, send a RST.	 */	case TCPS_SYN_RECEIVED:		if (tiflags & TH_ACK) {			if (tiflags & TH_SYN) {				tcpstat.tcps_badsyn++;				goto dropwithreset;			}			if (SEQ_LEQ(ti->ti_ack, tp->snd_una) ||			    SEQ_GT(ti->ti_ack, tp->snd_max))				goto dropwithreset;		}		break;	/*	 * 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 ((taop = tcp_gettaocache(inp)) == NULL) {			taop = &tao_noncached;			bzero(taop, sizeof(*taop));		}		if ((tiflags & TH_ACK) &&		    (SEQ_LEQ(ti->ti_ack, tp->iss) ||		     SEQ_GT(ti->ti_ack, tp->snd_max))) {			/*			 * If we have a cached CCsent for the remote host,			 * hence we haven't just crashed and restarted,			 * do not send a RST.  This may be a retransmission			 * from the other side after our earlier ACK was lost.			 * Our new SYN, when it arrives, will serve as the			 * needed ACK.			 */			if (taop->tao_ccsent != 0)				goto drop;			else				goto dropwithreset;		}		if (tiflags & TH_RST) {			if (tiflags & TH_ACK)				tp = tcp_drop(tp, ECONNREFUSED);			goto drop;		}		if ((tiflags & TH_SYN) == 0)			goto drop;		tp->snd_wnd = ti->ti_win;	/* initial send window */		tp->cc_recv = to.to_cc;		/* foreign CC */		tp->irs = ti->ti_seq;		tcp_rcvseqinit(tp);		if (tiflags & TH_ACK) {			/*			 * Our SYN was acked.  If segment contains CC.ECHO			 * option, check it to make sure this segment really			 * matches our SYN.  If not, just drop it as old			 * duplicate, but send an RST if we're still playing			 * by the old rules.  If no CC.ECHO option, make sure			 * we don't get fooled into using T/TCP.			 */			if (to.to_flag & TOF_CCECHO) {				if (tp->cc_send != to.to_ccecho) {					if (taop->tao_ccsent != 0)						goto drop;					else						goto dropwithreset;				}			} else				tp->t_flags &= ~TF_RCVD_CC;			tcpstat.tcps_connects++;			soisconnected(so);			/* Do window scaling on this connection? */			if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==				(TF_RCVD_SCALE|TF_REQ_SCALE)) {				tp->snd_scale = tp->requested_s_scale;				tp->rcv_scale = tp->request_r_scale;			}			/* Segment is acceptable, update cache if undefined. */			if (taop->tao_ccsent == 0)				taop->tao_ccsent = to.to_ccecho;			tp->rcv_adv += tp->rcv_wnd;			tp->snd_una++;		/* SYN is acked */			/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -