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

📄 tcp_input.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* XXX Should never fail */	if (tp == 0)		goto dropwithreset;	if (tp->t_state == TCPS_CLOSED)		goto drop;		/* Unscale the window into a 32-bit value. *//*	if ((tiflags & TH_SYN) == 0) *		tiwin = ti->ti_win << tp->snd_scale; *	else */		tiwin = ti->ti_win;	/*	 * Segment received on connection.	 * Reset idle time and keep-alive timer.	 */	tp->t_idle = 0;	if (so_options)	   tp->t_timer[TCPT_KEEP] = tcp_keepintvl;	else	   tp->t_timer[TCPT_KEEP] = tcp_keepidle;	/*	 * Process options if not in LISTEN state,	 * else do it below (after getting remote address).	 */	if (optp && tp->t_state != TCPS_LISTEN)		tcp_dooptions(tp, (u_char *)optp, optlen, ti); /* , *//*			&ts_present, &ts_val, &ts_ecr); */	/* 	 * 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.	 *	 * XXX Some of these tests are not needed	 * eg: the tiwin == tp->snd_wnd prevents many more	 * predictions.. with no *real* advantage..	 */	if (tp->t_state == TCPS_ESTABLISHED &&	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&/*	    (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && */	    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.		 *//*		if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && *		   SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { *			tp->ts_recent_age = tcp_now; *			tp->ts_recent = ts_val; *		} */		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) {				/*				 * this is a pure ack for outstanding data.				 */				++tcpstat.tcps_predack;/*				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);				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;				/* 				 * There's room in so_snd, sowwakup will read()				 * from the socket if we can				 *//*				if (so->so_snd.sb_flags & SB_NOTIFY) *					sowwakeup(so); */				/* 				 * This is called because sowwakeup might have				 * put data into so_snd.  Since we don't so sowwakeup,				 * we don't need this.. XXX???				 */				if (so->so_snd.sb_cc)					(void) tcp_output(tp);				return;			}		} else if (ti->ti_ack == tp->snd_una &&		    tp->seg_next == (tcpiphdrp_32)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.			 */			if (so->so_emu) {				if (tcp_emu(so,m)) sbappend(so, m);			} else				sbappend(so, m);						/* 			 * XXX This is called when data arrives.  Later, check			 * if we can actually write() to the socket			 * XXX Need to check? It's be NON_BLOCKING			 *//*			sorwakeup(so); */						/*			 * If this is a short packet, then ACK now - with Nagel			 *	congestion avoidance sender won't send more until			 *	he gets an ACK.			 * 			 * It is better to not delay acks at all to maximize			 * TCP throughput.  See RFC 2581.			 */ 			tp->t_flags |= TF_ACKNOW;			tcp_output(tp);			return;		}	} /* header prediction */	/*	 * 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: {	  if (tiflags & TH_RST)	    goto drop;	  if (tiflags & TH_ACK)	    goto dropwithreset;	  if ((tiflags & TH_SYN) == 0)	    goto drop;			  /*	   * This has way too many gotos...	   * But a bit of spaghetti code never hurt anybody :)	   */	  	  /*	   * If this is destined for the control address, then flag to	   * tcp_ctl once connected, otherwise connect	   */	  if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) {	    int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff;	    if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) {#if 0	      if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) {		/* Command or exec adress */		so->so_state |= SS_CTL;	      } else #endif              {		/* May be an add exec */		struct ex_list *ex_ptr;		for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {		  if(ex_ptr->ex_fport == so->so_fport && 		     lastbyte == ex_ptr->ex_addr) {		    so->so_state |= SS_CTL;		    break;		  }		}	      }	      if(so->so_state & SS_CTL) goto cont_input;	    }	    /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */	  }	  	  if (so->so_emu & EMU_NOCONNECT) {	    so->so_emu &= ~EMU_NOCONNECT;	    goto cont_input;	  }	  	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {	    u_char code=ICMP_UNREACH_NET;	    DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",			errno,strerror(errno)));	    if(errno == ECONNREFUSED) {	      /* ACK the SYN, send RST to refuse the connection */	      tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,			  TH_RST|TH_ACK); 	    } else {	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;	      HTONL(ti->ti_seq);             /* restore tcp header */	      HTONL(ti->ti_ack);	      HTONS(ti->ti_win);	      HTONS(ti->ti_urp);	      m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);	      *ip=save_ip;	      icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));	    }	    tp = tcp_close(tp);	    m_free(m);	  } else {	    /*	     * Haven't connected yet, save the current mbuf	     * and ti, and return	     * XXX Some OS's don't tell us whether the connect()	     * succeeded or not.  So we must time it out.	     */	    so->so_m = m;	    so->so_ti = ti;	    tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;	    tp->t_state = TCPS_SYN_RECEIVED;	  }	  return;	cont_conn:     	  /* m==NULL 	   * Check if the connect succeeded	   */	  if (so->so_state & SS_NOFDREF) {	    tp = tcp_close(tp);	    goto dropwithreset;	  }	cont_input:			  tcp_template(tp);	  	  if (optp)	    tcp_dooptions(tp, (u_char *)optp, optlen, ti);	  /* , */	  /*				&ts_present, &ts_val, &ts_ecr); */	  	  if (iss)	    tp->iss = iss;	  else 	    tp->iss = tcp_iss;	  tcp_iss += TCP_ISSINCR/2;	  tp->irs = ti->ti_seq;	  tcp_sendseqinit(tp);	  tcp_rcvseqinit(tp);	  tp->t_flags |= TF_ACKNOW;	  tp->t_state = TCPS_SYN_RECEIVED;	  tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;	  tcpstat.tcps_accepts++;	  goto trimthenstep6;	} /* case TCPS_LISTEN */		/*	 * 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)				tp = tcp_drop(tp,0); /* XXX Check t_softerror! */			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++;			soisfconnected(so);			tp->t_state = TCPS_ESTABLISHED;						/* 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; *			} */			(void) tcp_reass(tp, (struct tcpiphdr *)0,				(struct mbuf *)0);			/*			 * if we didn't have to retransmit the SYN,			 * use its rtt as our initial srtt & rtt var.			 */			if (tp->t_rtt)				tcp_xmit_timer(tp, tp->t_rtt);		} else			tp->t_state = TCPS_SYN_RECEIVED;trimthenstep6:		/*		 * 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;	} /* switch tp->t_state */	/*	 * States other than LISTEN or SYN_SENT.	 * First check timestamp, if present.	 * Then 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.	 * 	 * RFC 1323 PAWS: If we have a timestamp reply on this segment	 * and it's less than ts_recent, drop it.	 *//*	if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && *	    TSTMP_LT(ts_val, tp->ts_recent)) { * */		/* Check to see if ts_recent is over 24 days old.  *//*		if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { */			/* *			 * Invalidate ts_recent.  If this segment updates *			 * ts_recent, the age will be reset later and ts_recent *			 * will get a valid value.  If it does not, setting *			 * ts_recent to zero will at least satisfy the *			 * requirement that zero be placed in the timestamp *			 * echo reply when ts_recent isn't valid.  The *			 * age isn't reset until we get a valid ts_recent *			 * because we don't want out-of-order segments to be *			 * dropped when ts_recent is old. *			 *//*			tp->ts_recent = 0; *		} else { *			tcpstat.tcps_rcvduppack++; *			tcpstat.tcps_rcvdupbyte += ti->ti_len; *			tcpstat.tcps_pawsdrop++; *			goto dropafterack; *		} *	} */	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--;		}		/*		 * Following if statement from Stevens, vol. 2, p. 960.		 */		if (todrop > ti->ti_len		    || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {			/*			 * Any valid FIN must be to the left of the window.

⌨️ 快捷键说明

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