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

📄 ip_input.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
📖 第 1 页 / 共 3 页
字号:
		/*		 * Adjust ip_len to not reflect header,		 * set ipqe_mff if more fragments are expected,		 * convert offset of this to bytes.		 */		ip->ip_len -= hlen;		mff = (ip->ip_off & IP_MF) != 0;		if (mff) {			/*			 * Make sure that fragments have a data length			 * that's a non-zero multiple of 8 bytes.			 */			if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {				ipstat.ips_badfrags++;				ipq_unlock();				goto bad;			}		}		ip->ip_off <<= 3;		/*		 * If datagram marked as having more fragments		 * or if this is not the first fragment,		 * attempt reassembly; if it succeeds, proceed.		 */		if (mff || ip->ip_off) {			ipstat.ips_fragments++;			if (ip_frags + 1 > ip_maxqueue) {				ip_flush();				ipstat.ips_rcvmemdrop++;				ipq_unlock();				goto bad;			}			    			MALLOC(ipqe, struct ipqent *, sizeof (struct ipqent),			    M_IPQ, M_NOWAIT);			if (ipqe == NULL) {				ipstat.ips_rcvmemdrop++;				ipq_unlock();				goto bad;			}			ip_frags++;			ipqe->ipqe_mff = mff;			ipqe->ipqe_ip = ip;			ip = ip_reass(ipqe, fp);			if (ip == 0) {				ipq_unlock();				return;			}			ipstat.ips_reassembled++;			m = dtom(ip);			hlen = ip->ip_hl << 2;		} else			if (fp)				ip_freef(fp);		ipq_unlock();	} else		ip->ip_len -= hlen;	/*	 * Switch out to protocol's input routine.	 */	ipstat.ips_delivered++;	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen, NULL, 0);	return;bad:	m_freem(m);}struct in_ifaddr *in_iawithaddr(ina, m)	struct in_addr ina;	register struct mbuf *m;{	register struct in_ifaddr *ia;	for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) {		if ((ina.s_addr == ia->ia_addr.sin_addr.s_addr) ||		    (ia->ia_addr.sin_addr.s_addr == INADDR_ANY) ||		    ((ia->ia_ifp->if_flags & (IFF_LOOPBACK|IFF_LINK1)) ==			(IFF_LOOPBACK|IFF_LINK1) &&		     ia->ia_subnet == (ina.s_addr & ia->ia_subnetmask)))			return ia;		if (m && ((ip_directedbcast == 0) || (ip_directedbcast &&		    ia->ia_ifp == m->m_pkthdr.rcvif)) &&		    (ia->ia_ifp->if_flags & IFF_BROADCAST)) {			if (ina.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||			    ina.s_addr == ia->ia_netbroadcast.s_addr ||			    /*			     * Look for all-0's host part (old broadcast addr),			     * either for subnet or net.			     */			    ina.s_addr == ia->ia_subnet ||			    ina.s_addr == ia->ia_net)				return ia;		}	}	return NULL;}/* * Take incoming datagram fragment and try to * reassemble it into whole datagram.  If a chain for * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */struct ip *ip_reass(ipqe, fp)	register struct ipqent *ipqe;	register struct ipq *fp;{	register struct mbuf *m = dtom(ipqe->ipqe_ip);	register struct ipqent *nq, *p, *q;	struct ip *ip;	struct mbuf *t;	int hlen = ipqe->ipqe_ip->ip_hl << 2;	int i, next;	/*	 * Presence of header sizes in mbufs	 * would confuse code below.	 */	m->m_data += hlen;	m->m_len -= hlen;	/*	 * If first fragment to arrive, create a reassembly queue.	 */	if (fp == 0) {		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)			goto dropfrag;		fp = mtod(t, struct ipq *);		LIST_INSERT_HEAD(&ipq, fp, ipq_q);		fp->ipq_ttl = IPFRAGTTL;		fp->ipq_p = ipqe->ipqe_ip->ip_p;		fp->ipq_id = ipqe->ipqe_ip->ip_id;		LIST_INIT(&fp->ipq_fragq);		fp->ipq_src = ipqe->ipqe_ip->ip_src;		fp->ipq_dst = ipqe->ipqe_ip->ip_dst;		p = NULL;		goto insert;	}	/*	 * Find a segment which begins after this one does.	 */	for (p = NULL, q = fp->ipq_fragq.lh_first; q != NULL;	    p = q, q = q->ipqe_q.le_next)		if (q->ipqe_ip->ip_off > ipqe->ipqe_ip->ip_off)			break;	/*	 * If there is a preceding segment, it may provide some of	 * our data already.  If so, drop the data from the incoming	 * segment.  If it provides all of our data, drop us.	 */	if (p != NULL) {		i = p->ipqe_ip->ip_off + p->ipqe_ip->ip_len -		    ipqe->ipqe_ip->ip_off;		if (i > 0) {			if (i >= ipqe->ipqe_ip->ip_len)				goto dropfrag;			m_adj(dtom(ipqe->ipqe_ip), i);			ipqe->ipqe_ip->ip_off += i;			ipqe->ipqe_ip->ip_len -= i;		}	}	/*	 * While we overlap succeeding segments trim them or,	 * if they are completely covered, dequeue them.	 */	for (; q != NULL && ipqe->ipqe_ip->ip_off + ipqe->ipqe_ip->ip_len >	    q->ipqe_ip->ip_off; q = nq) {		i = (ipqe->ipqe_ip->ip_off + ipqe->ipqe_ip->ip_len) -		    q->ipqe_ip->ip_off;		if (i < q->ipqe_ip->ip_len) {			q->ipqe_ip->ip_len -= i;			q->ipqe_ip->ip_off += i;			m_adj(dtom(q->ipqe_ip), i);			break;		}		nq = q->ipqe_q.le_next;		m_freem(dtom(q->ipqe_ip));		LIST_REMOVE(q, ipqe_q);		FREE(q, M_IPQ);		ip_frags--;	}insert:	/*	 * Stick new segment in its place;	 * check for complete reassembly.	 */	if (p == NULL) {		LIST_INSERT_HEAD(&fp->ipq_fragq, ipqe, ipqe_q);	} else {		LIST_INSERT_AFTER(p, ipqe, ipqe_q);	}	next = 0;	for (p = NULL, q = fp->ipq_fragq.lh_first; q != NULL;	    p = q, q = q->ipqe_q.le_next) {		if (q->ipqe_ip->ip_off != next)			return (0);		next += q->ipqe_ip->ip_len;	}	if (p->ipqe_mff)		return (0);	/*	 * Reassembly is complete.  Check for a bogus message size and	 * concatenate fragments.	 */	q = fp->ipq_fragq.lh_first;	ip = q->ipqe_ip;	if ((next + (ip->ip_hl << 2)) > IP_MAXPACKET) {		ipstat.ips_toolong++;		ip_freef(fp);		return (0);	}	m = dtom(q->ipqe_ip);	t = m->m_next;	m->m_next = 0;	m_cat(m, t);	nq = q->ipqe_q.le_next;	FREE(q, M_IPQ);	ip_frags--;	for (q = nq; q != NULL; q = nq) {		t = dtom(q->ipqe_ip);		nq = q->ipqe_q.le_next;		FREE(q, M_IPQ);		ip_frags--;		m_cat(m, t);	}	/*	 * Create header for new ip packet by	 * modifying header of first packet;	 * dequeue and discard fragment reassembly header.	 * Make header visible.	 */	ip->ip_len = next;	ip->ip_src = fp->ipq_src;	ip->ip_dst = fp->ipq_dst;	LIST_REMOVE(fp, ipq_q);	(void) m_free(dtom(fp));	m->m_len += (ip->ip_hl << 2);	m->m_data -= (ip->ip_hl << 2);	/* some debugging cruft by sklower, below, will go away soon */	if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */		register int plen = 0;		for (t = m; m; m = m->m_next)			plen += m->m_len;		t->m_pkthdr.len = plen;	}	return (ip);dropfrag:	ipstat.ips_fragdropped++;	m_freem(m);	FREE(ipqe, M_IPQ);	ip_frags--;	return (0);}/* * Free a fragment reassembly header and all * associated datagrams. */voidip_freef(fp)	struct ipq *fp;{	register struct ipqent *q, *p;	for (q = fp->ipq_fragq.lh_first; q != NULL; q = p) {		p = q->ipqe_q.le_next;		m_freem(dtom(q->ipqe_ip));		LIST_REMOVE(q, ipqe_q);		FREE(q, M_IPQ);		ip_frags--;	}	LIST_REMOVE(fp, ipq_q);	(void) m_free(dtom(fp));}/* * IP timer processing; * if a timer expires on a reassembly * queue, discard it. */voidip_slowtimo(){	register struct ipq *fp, *nfp;	int s = splsoftnet();	ipq_lock();	for (fp = ipq.lh_first; fp != NULL; fp = nfp) {		nfp = fp->ipq_q.le_next;		if (--fp->ipq_ttl == 0) {			ipstat.ips_fragtimeout++;			ip_freef(fp);		}	}	ipq_unlock();	splx(s);}/* * Drain off all datagram fragments. */voidip_drain(){	if (ipq_lock_try() == 0)		return;	while (ipq.lh_first != NULL) {		ipstat.ips_fragdropped++;		ip_freef(ipq.lh_first);	}	ipq_unlock();}/* * Flush a bunch of datagram fragments, till we are down to 75%. */voidip_flush(){	int max = 50;	/* ipq already locked */	while (ipq.lh_first != NULL && ip_frags > ip_maxqueue * 3 / 4 && --max) {		ipstat.ips_fragdropped++;		ip_freef(ipq.lh_first);	}}/* * Do option processing on a datagram, * possibly discarding it if bad options are encountered, * or forwarding it if source-routed. * Returns 1 if packet has been forwarded/freed, * 0 if the packet should be processed further. */intip_dooptions(m)	struct mbuf *m;{	register struct ip *ip = mtod(m, struct ip *);	register u_char *cp;	register struct ip_timestamp *ipt;	register struct in_ifaddr *ia;	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;	struct in_addr *sin, dst;	n_time ntime;	dst = ip->ip_dst;	cp = (u_char *)(ip + 1);	cnt = (ip->ip_hl << 2) - sizeof (struct ip);	for (; cnt > 0; cnt -= optlen, cp += optlen) {		opt = cp[IPOPT_OPTVAL];		if (opt == IPOPT_EOL)			break;		if (opt == IPOPT_NOP)			optlen = 1;		else {			optlen = cp[IPOPT_OLEN];			if (optlen <= 0 || optlen > cnt) {				code = &cp[IPOPT_OLEN] - (u_char *)ip;				goto bad;			}		}		switch (opt) {		default:			break;		/*		 * Source routing with record.		 * Find interface with current destination address.		 * If none on this machine then drop if strictly routed,		 * or do nothing if loosely routed.		 * Record interface address and bring up next address		 * component.  If strictly routed make sure next		 * address is on directly accessible net.		 */		case IPOPT_LSRR:		case IPOPT_SSRR:			if (!ip_dosourceroute) {				char buf[4*sizeof "123"];				strcpy(buf, inet_ntoa(ip->ip_dst));				log(LOG_WARNING,				    "attempted source route from %s to %s\n",				    inet_ntoa(ip->ip_src), buf);				type = ICMP_UNREACH;				code = ICMP_UNREACH_SRCFAIL;				goto bad;			}			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {				code = &cp[IPOPT_OFFSET] - (u_char *)ip;				goto bad;			}			ipaddr.sin_addr = ip->ip_dst;			ia = ifatoia(ifa_ifwithaddr(sintosa(&ipaddr)));			if (ia == 0) {				if (opt == IPOPT_SSRR) {					type = ICMP_UNREACH;					code = ICMP_UNREACH_SRCFAIL;					goto bad;				}				/*				 * Loose routing, and not at next destination				 * yet; nothing to do except forward.				 */				break;			}			off--;			/* 0 origin */			if (off > optlen - sizeof(struct in_addr)) {				/*				 * End of source route.  Should be for us.				 */				save_rte(cp, ip->ip_src);				break;			}			/*			 * locate outgoing interface			 */			bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,			    sizeof(ipaddr.sin_addr));			if (opt == IPOPT_SSRR) {#define	INA	struct in_ifaddr *#define	SA	struct sockaddr *			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)				ia = (INA)ifa_ifwithnet((SA)&ipaddr);			} else				ia = ip_rtaddr(ipaddr.sin_addr);			if (ia == 0) {				type = ICMP_UNREACH;				code = ICMP_UNREACH_SRCFAIL;				goto bad;			}			ip->ip_dst = ipaddr.sin_addr;			bcopy((caddr_t)&ia->ia_addr.sin_addr,			    (caddr_t)(cp + off), sizeof(struct in_addr));			cp[IPOPT_OFFSET] += sizeof(struct in_addr);			/*			 * Let ip_intr's mcast routing check handle mcast pkts			 */			forward = !IN_MULTICAST(ip->ip_dst.s_addr);			break;		case IPOPT_RR:			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {				code = &cp[IPOPT_OFFSET] - (u_char *)ip;				goto bad;			}			/*			 * If no space remains, ignore.			 */			off--;			/* 0 origin */			if (off > optlen - sizeof(struct in_addr))				break;			bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,			    sizeof(ipaddr.sin_addr));			/*			 * locate outgoing interface; if we're the destination,			 * use the incoming interface (should be same).			 */			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {				type = ICMP_UNREACH;				code = ICMP_UNREACH_HOST;				goto bad;			}			bcopy((caddr_t)&ia->ia_addr.sin_addr,			    (caddr_t)(cp + off), sizeof(struct in_addr));			cp[IPOPT_OFFSET] += sizeof(struct in_addr);			break;

⌨️ 快捷键说明

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