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

📄 tcp_input.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	if (is_ipv6) {#ifdef DIAGNOSTIC	  if (iphlen < sizeof(struct ip6_hdr)) {	    m_freem(m);	    return;	  }#endif /* DIAGNOSTIC */	  /* strip off any options */	  if (iphlen > sizeof(struct ip6_hdr)) {#if 0 /*XXX*/	    ipv6_stripoptions(m, iphlen);#else		printf("extension headers are not allowed\n");		m_freem(m);		return;#endif	    iphlen = sizeof(struct ip6_hdr);	  }	  ti = NULL;	  ipv6 = mtod(m, struct ip6_hdr *);		/* Be proactive about malicious use of IPv4 mapped address */		if (IN6_IS_ADDR_V4MAPPED(&ipv6->ip6_src) ||		    IN6_IS_ADDR_V4MAPPED(&ipv6->ip6_dst)) {			/* XXX stat */			goto drop;		}	  if (in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), tlen)) {	    tcpstat.tcps_rcvbadsum++;	    goto drop;	  } /* endif in6_cksum */	} else {	  ti = mtod(m, struct tcpiphdr *);#endif /* INET6 */	/*	 * Checksum extended TCP header and data.	 */#ifndef INET6	tlen = ((struct ip *)ti)->ip_len;#endif /* INET6 */	len = sizeof (struct ip) + tlen;	bzero(ti->ti_x1, sizeof ti->ti_x1);	ti->ti_len = (u_int16_t)tlen;	HTONS(ti->ti_len);	if ((ti->ti_sum = in_cksum(m, len)) != 0) {		tcpstat.tcps_rcvbadsum++;		goto drop;	}#ifdef INET6	}#endif /* INET6 */#endif /* TUBA_INCLUDE */	th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen);	/*	 * Check that TCP offset makes sense,	 * pull out TCP options and adjust length.		XXX	 */	off = th->th_off << 2;	if (off < sizeof (struct tcphdr) || off > tlen) {		tcpstat.tcps_rcvbadoff++;		goto drop;	}	tlen -= off;	if (off > sizeof (struct tcphdr)) {		if (m->m_len < iphlen + off) {			if ((m = m_pullup2(m, iphlen + off)) == 0) {				tcpstat.tcps_rcvshort++;				return;			}#ifdef INET6			if (is_ipv6)			  ipv6 = mtod(m, struct ip6_hdr *);			else#endif /* INET6 */			ti = mtod(m, struct tcpiphdr *);			th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen);		}		optlen = off - sizeof (struct tcphdr);		optp = mtod(m, caddr_t) + iphlen + sizeof(struct tcphdr);		/* 		 * Do quick retrieval of timestamp options ("options		 * prediction?").  If timestamp is the only option and it's		 * formatted as recommended in RFC 1323 appendix A, we		 * quickly get the values now and not bother calling		 * tcp_dooptions(), etc.		 */		if ((optlen == TCPOLEN_TSTAMP_APPA ||		     (optlen > TCPOLEN_TSTAMP_APPA &&			optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) &&		     *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) &&		     (th->th_flags & TH_SYN) == 0) {			ts_present = 1;			ts_val = ntohl(*(u_int32_t *)(optp + 4));			ts_ecr = ntohl(*(u_int32_t *)(optp + 8));			optp = NULL;	/* we've parsed the options */		}	}	tiflags = th->th_flags;	/*	 * Convert TCP protocol specific fields to host format.	 */	NTOHL(th->th_seq);	NTOHL(th->th_ack);	NTOHS(th->th_win);	NTOHS(th->th_urp);	/*	 * Locate pcb for segment.	 */findpcb:#ifdef INET6	if (is_ipv6) {	  inp = in6_pcbhashlookup(&tcbtable, &ipv6->ip6_src, th->th_sport,				 &ipv6->ip6_dst, th->th_dport);	} else#endif /* INET6 */	inp = in_pcbhashlookup(&tcbtable, ti->ti_src, ti->ti_sport,	    ti->ti_dst, ti->ti_dport);	if (inp == 0) {		++tcpstat.tcps_pcbhashmiss;#ifdef INET6		if (is_ipv6)			inp = in_pcblookup(&tcbtable, &ipv6->ip6_src,			    th->th_sport, &ipv6->ip6_dst, th->th_dport,			    INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);		else#endif /* INET6 */		inp = in_pcblookup(&tcbtable, &ti->ti_src, ti->ti_sport,		    &ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD);		/*		 * 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.		 */		if (inp == 0) {			++tcpstat.tcps_noport;			goto dropwithreset;		}	}	tp = intotcpcb(inp);	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 = th->th_win << tp->snd_scale;	else		tiwin = th->th_win;	so = inp->inp_socket;	if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {		if (so->so_options & SO_DEBUG) {			ostate = tp->t_state;#ifdef INET6			if (is_ipv6)			  tcp_saveti6 = *(mtod(m, struct tcpipv6hdr *));			else#endif /* INET6 */			tcp_saveti = *ti;		}		if (so->so_options & SO_ACCEPTCONN) {			struct socket *so1;			so1 = sonewconn(so, 0);			if (so1 == NULL) {				tcpdropoldhalfopen(tp, th->th_dport);				so1 = sonewconn(so, 0);				if (so1 == NULL)					goto drop;			}			so = so1;			/*			 * 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++;#ifdef IPSEC			/* 			 * We need to copy the required security levels			 * from the old pcb.			 */			{			  struct inpcb *newinp = (struct inpcb *)so->so_pcb;			  bcopy(inp->inp_seclevel, newinp->inp_seclevel,				sizeof(inp->inp_seclevel));			  newinp->inp_secrequire = inp->inp_secrequire;			}#endif /* IPSEC */#ifdef INET6			/*			 * inp still has the OLD in_pcb stuff, set the			 * v6-related flags on the new guy, too.   This is			 * done particularly for the case where an AF_INET6			 * socket is bound only to a port, and a v4 connection			 * comes in on that port.			 * we also copy the flowinfo from the original pcb 			 * to the new one.			 */			{			  int flags = inp->inp_flags;			  struct inpcb *oldinpcb = inp;			  			  inp = (struct inpcb *)so->so_pcb;			  inp->inp_flags |= (flags & (INP_IPV6 | INP_IPV6_UNDEC						      | INP_IPV6_MAPPED));			  if ((inp->inp_flags & INP_IPV6) &&			      !(inp->inp_flags & INP_IPV6_MAPPED)) {			    inp->inp_ipv6.ip6_hlim = 			      oldinpcb->inp_ipv6.ip6_hlim;			    inp->inp_ipv6.ip6_flow = 			      oldinpcb->inp_ipv6.ip6_flow;			  }			}#else /* INET6 */			inp = (struct inpcb *)so->so_pcb;#endif /* INET6 */			inp->inp_lport = th->th_dport;#ifdef INET6			if (is_ipv6) {			  inp->inp_laddr6 = ipv6->ip6_dst;			  inp->inp_fflowinfo = htonl(0x0fffffff) & 			    ipv6->ip6_flow;			  			  /*inp->inp_options = ip6_srcroute();*/ /* soon. */			  /* still need to tweak outbound options			     processing to include this mbuf in			     the right place and put the correct			     NextHdr values in the right places.			     XXX  rja */			} else {			  if (inp->inp_flags & INP_IPV6) {/* v4 to v6 socket */			    CREATE_IPV6_MAPPED(inp->inp_laddr6,			      ti->ti_dst.s_addr);			  } else {#endif /* INET6 */			    inp->inp_laddr = ti->ti_dst;			    inp->inp_options = ip_srcroute();#if INET6			  }			}#endif /* INET6 */			in_pcbrehash(inp);			tp = intotcpcb(inp);			tp->t_state = TCPS_LISTEN;			/* 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++;		}	}#ifdef IPSEC	/* Check if this socket requires security for incoming packets */	if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE &&	     !(m->m_flags & M_AUTH)) ||	    (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&	     !(m->m_flags & M_CONF))) {#ifdef notyet#ifdef INET6		if (is_ipv6)			icmp6_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);		else#endif /* INET6 */		icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);#endif /* notyet */		tcpstat.tcps_rcvnosec++;		goto drop;	}	/* Use tdb_bind_out for this inp's outbound communication */	if (tdb)		tdb_add_inp(tdb, inp);#endif /*IPSEC */	/*	 * Segment received on connection.	 * Reset idle time and keep-alive timer.	 */	tp->t_idle = 0;	if (tp->t_state != TCPS_SYN_RECEIVED)		tp->t_timer[TCPT_KEEP] = tcp_keepidle;#ifdef TCP_SACK	if (!tp->sack_disable)		tcp_del_sackholes(tp, th); /* Delete stale SACK holes */#endif /* TCP_SACK */	/*	 * 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, optp, optlen, th,			&ts_present, &ts_val, &ts_ecr);#ifdef TCP_SACK	if (!tp->sack_disable) {		tp->rcv_laststart = th->th_seq; /* last rec'vd segment*/		tp->rcv_lastend = th->th_seq + tlen;	}#endif /* TCP_SACK */	/* 	 * 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.	 */	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)) &&	    th->th_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.		 * Fix from Braden, see Stevens p. 870		 */		if (ts_present && SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {			tp->ts_recent_age = tcp_now;			tp->ts_recent = ts_val;		}		if (tlen == 0) {			if (SEQ_GT(th->th_ack, tp->snd_una) &&			    SEQ_LEQ(th->th_ack, tp->snd_max) &&			    tp->snd_cwnd >= tp->snd_wnd &&			    tp->t_dupacks == 0) {				/*				 * 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(th->th_ack, tp->t_rtseq))					tcp_xmit_timer(tp, tp->t_rtt);				acked = th->th_ack - tp->snd_una;				tcpstat.tcps_rcvackpack++;				tcpstat.tcps_rcvackbyte += acked;				ND6_HINT(tp);				sbdrop(&so->so_snd, acked);				tp->snd_una = th->th_ack;#if defined(TCP_SACK)				/* 				 * We want snd_last to track snd_una so				 * as to avoid sequence wraparound problems				 * for very large transfers.				 */				tp->snd_last = tp->snd_una;#endif /* TCP_SACK */#if defined(TCP_SACK) && defined(TCP_FACK)				tp->snd_fack = tp->snd_una;				tp->retran_data = 0;#endif /* TCP_FACK */				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 (sb_notify(&so->so_snd))					sowwakeup(so);				if (so->so_snd.sb_cc)					(void) tcp_output(tp);				return;			}		} else if (th->th_ack == tp->snd_una &&		    tp->segq.lh_first == NULL &&		    tlen <= 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.			 */#ifdef TCP_SACK			/* Clean receiver SACK report if present */			if (!tp->sack_disable && tp->rcv_numsacks)				tcp_clean_sackreport(tp);#endif /* TCP_SACK */			++tcpstat.tcps_preddat;			tp->rcv_nxt += tlen;			tcpstat.tcps_rcvpack++;			tcpstat.tcps_rcvbyte += tlen;			ND6_HINT(tp);			/*			 * Drop TCP, IP headers and TCP options then add data			 * to socket buffer.			 */			if (th->th_flags & TH_PUSH)				tp->t_flags |= TF_ACKNOW;			else				tp->t_flags |= TF_DELACK;			m_adj(m, iphlen + off);			sbappend(&so->so_rcv, m);			sorwakeup(so);			return;		}	}	/*	 * Compute mbuf offset to TCP data segment.	 */	hdroptlen = iphlen + off;	/*	 * 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.

⌨️ 快捷键说明

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