ip6_input.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,515 行 · 第 1/5 页

C
2,515
字号
		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 voiddump_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}voidip6_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_RECVOPTSvoidip6_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. */intip6_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. */intip6_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_nexthdr(m, off, proto, nxtp);		if (newoff < 0)			return off;		else if (newoff < off)			return -1;	/* invalid */		else if (newoff == off)			return newoff;		off = newoff;		proto = *nxtp;	}}#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)voidpfctlinput2(cmd, sa, ctlparam)	int cmd;	struct sockaddr *sa;	void *ctlparam;{	struct domain *dp;	struct protosw *pr;	if (!sa)		return;	for (dp = domains; dp; dp = dp->dom_next) {		/*		 * the check must be made by xx_ctlinput() anyways, to		 * make sure we use data item pointed to by ctlparam in		 * correct way.  the following check is made just for safety.		 */		if (dp->dom_family != sa->sa_family)			continue;		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)			if (pr->pr_ctlinput)				(*pr->pr_ctlinput)(cmd, sa, ctlparam);	}}#endifstruct mbuf *ip6_addaux(m)	struct mbuf *m;{	struct mbuf *n;#ifdef DIAGNOSTIC	if (sizeof(struct ip6aux) > MHLEN)		panic("assumption failed on sizeof(ip6aux)");#endif	n = m_aux_find(m, AF_INET6, -1);	if (n) {		if (n->m_len < sizeof(struct ip6aux)) {			printf("conflicting use of ip6aux");			return NULL;		}	} else {		n = m_aux_add(m, AF_INET6, -1);		n->m_len = sizeof(struct ip6aux);		bzero(mtod(n, caddr_t), n->m_len);	}	return n;}struct mbuf *ip6_findaux(m)	struct mbuf *m;{	struct mbuf *n;	n = m_aux_find(m, AF_INET6, -1);	if (n && n->m_len < sizeof(struct ip6aux)) {		printf("conflicting use of ip6aux");		n = NULL;	}	return n;}voidip6_delaux(m)	struct mbuf *m;{	struct mbuf *n;	n = m_aux_find(m, AF_INET6, -1);	if (n)		m_aux_delete(m, n);}/* * System control for IP6 */int inet6ctlerrmap[PRC_NCMDS] = {	0,		0,		0,		0,	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,	EMSGSIZE,	EHOSTUNREACH,	0,		0,	0,		0,		0,		0,	ENOPROTOOPT};

⌨️ 快捷键说明

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