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

📄 ip_input.c

📁 嵌入式操作系统ECOS的网络开发包
💻 C
📖 第 1 页 / 共 3 页
字号:
				ipstat.ips_toosmall++;
				return;
			}
			ip = mtod(m, struct ip *);
		}

		/*
		 * Look for queue of fragments
		 * of this datagram.
		 */
		ipq_lock();
		for (fp = ipq.lh_first; fp != NULL; fp = fp->ipq_q.le_next)
			if (ip->ip_id == fp->ipq_id &&
			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
			    ip->ip_p == fp->ipq_p)
				goto found;
		fp = 0;
found:

		/*
		 * 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_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) {
				/* Make sure M_BCAST is set */
				m->m_flags |= M_BCAST;
				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_ttl = 0;	/* xxx */
	ip->ip_sum = 0;
	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.
 */
void
ip_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.
 */
void
ip_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.
 */
void
ip_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%.
 */
void
ip_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.
 */
int
ip_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) {
#ifndef __ECOS
				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);
#endif
				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;

		case IPOPT_TS:
			code = cp - (u_char *)ip;
			ipt = (struct ip_timestamp *)cp;
			if (ipt->ipt_ptr < 5 || ipt->ipt_len < 5)
				goto bad;
			if (ipt->ipt_ptr - 1 + sizeof(n_time) > ipt->ipt_len) {
				if (++ipt->ipt_oflw == 0)
					goto bad;
				break;
			}

⌨️ 快捷键说明

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