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

📄 ip6_input.c

📁 嵌入式操作系统ECOS的网络开发包
💻 C
📖 第 1 页 / 共 5 页
字号:
				 */
				if (ctl->rthdr == NULL && prevrth &&
				    prevrhlen == elen &&
				    bcmp(ip6e, prevrth, elen) == 0)
					break;

				*mp = sbcreatecontrol((caddr_t)ip6e, elen,
						      IS2292(IPV6_2292RTHDR,
							     IPV6_RTHDR),
						      IPPROTO_IPV6);
				if (ctl->rthdr == NULL)
					ctl->rthdr = *mp;
				if (*mp)
					mp = &(*mp)->m_next;
				break;
			}
			case IPPROTO_HOPOPTS:
			case IPPROTO_AH: /* is it possible? */
				break;

			default:
				/*
			 	 * other cases have been filtered in the above.
				 * none will visit this case.  here we supply
				 * the code just in case (nxt overwritten or
				 * other cases).
				 */
#ifdef PULLDOWN_TEST
				m_freem(ext);
#endif
				goto loopend;

			}

			/* proceed with the next header. */
			off += elen;
			nxt = ip6e->ip6e_nxt;
			ip6e = NULL;
#ifdef PULLDOWN_TEST
			m_freem(ext);
			ext = NULL;
#endif
		}
	  loopend:
		;
	}

#ifdef __bsdi__
# undef sbcreatecontrol
#endif
#ifdef __OpenBSD__
# undef in6p_flags
#endif
#undef IS2292
}

void
ip6_notify_pmtu(in6p, dst, mtu)
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(HAVE_NRL_INPCB)
	struct inpcb *in6p;
#else
	struct in6pcb *in6p;
#endif
	struct sockaddr_in6 *dst;
	u_int32_t *mtu;
{
	struct socket *so;
	struct mbuf *m_mtu;
	struct ip6_mtuinfo mtuctl;
#ifdef __bsdi__
# define sbcreatecontrol	so_cmsg
#endif

#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(HAVE_NRL_INPCB)
	so =  in6p->inp_socket;
#else
	so = in6p->in6p_socket;
#endif

	if (mtu == NULL)
		return;

#ifdef DIAGNOSTIC
	if (so == NULL)		/* I believe this is impossible */
		panic("ip6_notify_pmtu: socket is NULL");
#endif

	bzero(&mtuctl, sizeof(mtuctl));	/* zero-clear for safety */
	mtuctl.ip6m_mtu = *mtu;
	mtuctl.ip6m_addr = *dst;
#ifndef SCOPEDROUTING
	in6_recoverscope(&mtuctl.ip6m_addr, &mtuctl.ip6m_addr.sin6_addr, NULL);
#endif

	if ((m_mtu = sbcreatecontrol((caddr_t)&mtuctl, sizeof(mtuctl),
				     IPV6_PATHMTU, IPPROTO_IPV6)) == NULL)
		return;

	if (sbappendaddr(&so->so_rcv, (struct sockaddr *)dst, NULL, m_mtu)
	    == 0) {
		m_freem(m_mtu);
		/* XXX: should count statistics */
	} else
		sorwakeup(so);

	return;

#ifdef __bsdi__
# undef sbcreatecontrol
#endif
}

#ifdef PULLDOWN_TEST
/*
 * pull single extension header from mbuf chain.  returns single mbuf that
 * contains the result, or NULL on error.
 */
static struct mbuf *
ip6_pullexthdr(m, off, nxt)
	struct mbuf *m;
	size_t off;
	int nxt;
{
	struct ip6_ext ip6e;
	size_t elen;
	struct mbuf *n;

#ifdef DIAGNOSTIC
	switch (nxt) {
	case IPPROTO_DSTOPTS:
	case IPPROTO_ROUTING:
	case IPPROTO_HOPOPTS:
	case IPPROTO_AH: /* is it possible? */
		break;
	default:
		printf("ip6_pullexthdr: invalid nxt=%d\n", nxt);
	}
#endif

	m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
	if (nxt == IPPROTO_AH)
		elen = (ip6e.ip6e_len + 2) << 2;
	else
		elen = (ip6e.ip6e_len + 1) << 3;

	MGET(n, M_DONTWAIT, MT_DATA);
	if (n && elen >= MLEN) {
		MCLGET(n, M_DONTWAIT);
		if ((n->m_flags & M_EXT) == 0) {
			m_free(n);
			n = NULL;
		}
	}
	if (!n)
		return NULL;

	n->m_len = 0;
	if (elen >= M_TRAILINGSPACE(n)) {
		m_free(n);
		return NULL;
	}

	m_copydata(m, off, elen, mtod(n, caddr_t));
	n->m_len = elen;
	return n;
}
#endif

/*
 * Merge new IPv6 received options to previous ones.
 * If a new option is not given, just re-link the option chain.
 * If an old option exists but a corresponding new one doesn't, just
 * keep the ole option.
 * If a new option exists but a corresponding old one doesn't, just
 * copy the new option.
 * If both new and old options exist, free old one and overwrite the option
 * with the new option.
 * Otherwise, do nothing for the option.
 * XXX: in any case, options that don't follow the recommend order and
 *      number of extension headers (RFC 2460 Section 4.1) are simply ignored.
 * XXX: We assume that each option is stored in a single mbuf.
 */
#define CLEAN_RECVOPT(old, type) \
do {								\
	if ((old)->type && (old)->type->m_next) {		\
		(old)->type->m_next = NULL;			\
	}							\
} while (0)
#define MERGE_RECVOPT(new, old, type) if ((new)->type) {\
		if ((old)->type)\
			m_free((old)->type);\
		(old)->type = m_copy((new)->type, 0, (new)->type->m_len);\
		if (((old)->type) && ((old)->type->m_next)) {\
			m_freem((old)->type);\
			old->type = NULL;\
		}\
	}
#define LINK_RECVOPTS(opt, type, p) if ((opt)->type) {\
		*(p) = (opt)->type;\
		(p) = &(opt)->type->m_next;\
	}

static void dump_inputopts __P((char *, struct ip6_recvpktopts *));
static void
dump_inputopts(str, p)
	char *str;
	struct ip6_recvpktopts *p;
{
#if 1
	return;
#else
#define PRINT1(p, name) \
do { \
	if (p->name) { \
		printf(" %s: %p", #name, (p)->name); \
		if (p->name->m_next) \
			printf("[%p]", (p)->name->m_next); \
	} \
} while (0)

	printf("%s p=%p head=%p", str, p, p->head);
	PRINT1(p, hlim);
	PRINT1(p, pktinfo);
	PRINT1(p, hbh);
	PRINT1(p, dest);
	PRINT1(p, rthdr);
	printf("\n");
#undef PRINT1
#endif
}

void
ip6_update_recvpcbopt(old, new)
	struct ip6_recvpktopts *new, *old;
{
	struct mbuf **mp;

	if (old == NULL) {
		printf("ip6_update_recvpcbopt: invalid arguments\n");
		return;
	}

	dump_inputopts("old before", old);
	if (new)
		dump_inputopts("new before", new);

#if 0
	/*
	 * cleanup m->m_next linkage. note that we do it in reverse order
	 * to prevent possible memory leakage.
	 */
	old->head = NULL;
	CLEAN_RECVOPT(old, rthdr);
	CLEAN_RECVOPT(old, dest);
	CLEAN_RECVOPT(old, hbh);
	CLEAN_RECVOPT(old, pktinfo);
	CLEAN_RECVOPT(old, hlim);
#endif

	if (new) {
		MERGE_RECVOPT(new, old, hlim);
		MERGE_RECVOPT(new, old, pktinfo);
		MERGE_RECVOPT(new, old, hbh);
		MERGE_RECVOPT(new, old, dest);
		MERGE_RECVOPT(new, old, rthdr);
	}

	dump_inputopts("old middle", old);
	if (new)
		dump_inputopts("new middle", new);

	/* link options */
	mp = &old->head;
	LINK_RECVOPTS(old, hlim, mp);
	LINK_RECVOPTS(old, pktinfo, mp);
	LINK_RECVOPTS(old, hbh, mp);
	LINK_RECVOPTS(old, dest, mp);
	LINK_RECVOPTS(old, rthdr, mp);
	*mp = NULL;

	dump_inputopts("old after", old);
	if (new)
		dump_inputopts("new after", new);
}

#undef MERGE_RECVOPT
#undef LINK_RECVOPTS

void
ip6_reset_rcvopt(opts, optname)
	struct ip6_recvpktopts *opts;
	int optname;
{
	if (opts == NULL)
		return;

	switch (optname) {
	case IPV6_RECVPKTINFO:
		if (opts->pktinfo) m_free(opts->pktinfo);
		opts->pktinfo = NULL;
		break;
	case IPV6_RECVHOPLIMIT:
		if (opts->hlim) m_free(opts->hlim);
		opts->hlim = NULL;
		break;
	case IPV6_RECVHOPOPTS:
		if (opts->hbh) m_free(opts->hbh);
		opts->hbh = NULL;
		break;
	case IPV6_RECVDSTOPTS:
		if (opts->dest) m_free(opts->dest);
		opts->dest = NULL;
		break;
	case IPV6_RECVRTHDR:
		if (opts->rthdr) m_free(opts->rthdr);
		opts->rthdr = NULL;
		break;
	default:
		printf("ip6_reset_rcvopt: invalid option name (%d)\n",
		       optname);
		return;
	}

	ip6_update_recvpcbopt(opts, NULL); /* re-link the option chain */
}

/*
 * Get pointer to the previous header followed by the header
 * currently processed.
 * XXX: This function supposes that
 *	M includes all headers,
 *	the next header field and the header length field of each header
 *	are valid, and
 *	the sum of each header length equals to OFF.
 * Because of these assumptions, this function must be called very
 * carefully. Moreover, it will not be used in the near future when
 * we develop `neater' mechanism to process extension headers.
 */
char *
ip6_get_prevhdr(m, off)
	struct mbuf *m;
	int off;
{
	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);

	if (off == sizeof(struct ip6_hdr))
		return(&ip6->ip6_nxt);
	else {
		int len, nxt;
		struct ip6_ext *ip6e = NULL;

		nxt = ip6->ip6_nxt;
		len = sizeof(struct ip6_hdr);
		while (len < off) {
			ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);

			switch (nxt) {
			case IPPROTO_FRAGMENT:
				len += sizeof(struct ip6_frag);
				break;
			case IPPROTO_AH:
				len += (ip6e->ip6e_len + 2) << 2;
				break;
			default:
				len += (ip6e->ip6e_len + 1) << 3;
				break;
			}
			nxt = ip6e->ip6e_nxt;
		}
		if (ip6e)
			return(&ip6e->ip6e_nxt);
		else
			return NULL;
	}
}

/*
 * get next header offset.  m will be retained.
 */
int
ip6_nexthdr(m, off, proto, nxtp)
	struct mbuf *m;
	int off;
	int proto;
	int *nxtp;
{
	struct ip6_hdr ip6;
	struct ip6_ext ip6e;
	struct ip6_frag fh;

	/* just in case */
	if (m == NULL)
		panic("ip6_nexthdr: m == NULL");
	if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off)
		return -1;

	switch (proto) {
	case IPPROTO_IPV6:
		/* do not chase beyond intermediate IPv6 headers */
		if (off != 0)
			return -1;
		if (m->m_pkthdr.len < off + sizeof(ip6))
			return -1;
		m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6);
		if (nxtp)
			*nxtp = ip6.ip6_nxt;
		off += sizeof(ip6);
		return off;

	case IPPROTO_FRAGMENT:
		/*
		 * terminate parsing if it is not the first fragment,
		 * it does not make sense to parse through it.
		 */
		if (m->m_pkthdr.len < off + sizeof(fh))
			return -1;
		m_copydata(m, off, sizeof(fh), (caddr_t)&fh);
		if ((ntohs(fh.ip6f_offlg) & IP6F_OFF_MASK) != 0)
			return -1;
		if (nxtp)
			*nxtp = fh.ip6f_nxt;
		off += sizeof(struct ip6_frag);
		return off;

	case IPPROTO_AH:
		if (m->m_pkthdr.len < off + sizeof(ip6e))
			return -1;
		m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
		if (nxtp)
			*nxtp = ip6e.ip6e_nxt;
		off += (ip6e.ip6e_len + 2) << 2;
		if (m->m_pkthdr.len < off)
			return -1;
		return off;

	case IPPROTO_HOPOPTS:
	case IPPROTO_ROUTING:
	case IPPROTO_DSTOPTS:
		if (m->m_pkthdr.len < off + sizeof(ip6e))
			return -1;
		m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
		if (nxtp)
			*nxtp = ip6e.ip6e_nxt;
		off += (ip6e.ip6e_len + 1) << 3;
		if (m->m_pkthdr.len < off)
			return -1;
		return off;

	case IPPROTO_NONE:
	case IPPROTO_ESP:
	case IPPROTO_IPCOMP:
		/* give up */
		return -1;

	default:
		return -1;
	}

	return -1;
}

/*
 * get offset for the last header in the chain.  m will be kept untainted.
 */
int
ip6_lasthdr(m, off, proto, nxtp)
	struct mbuf *m;
	int off;
	int proto;
	int *nxtp;
{
	int newoff;
	int nxt;

	if (!nxtp) {
		nxt = -1;
		nxtp = &nxt;
	}
	while (1) {
		newoff = ip6_

⌨️ 快捷键说明

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