ip6_input.c

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

C
2,515
字号
#endif			/*			 * jumbo payload length must be larger than 65535.			 */			if (jumboplen <= IPV6_MAXPACKET) {				ip6stat.ip6s_badoptions++;				icmp6_error(m, ICMP6_PARAM_PROB,					    ICMP6_PARAMPROB_HEADER,					    erroff + opt + 2 - opthead);				return(-1);			}			*plenp = jumboplen;			break;		default:		/* unknown option */			if (hbhlen < IP6OPT_MINLEN) {				ip6stat.ip6s_toosmall++;				goto bad;			}			optlen = ip6_unknown_opt(opt, m,			    erroff + opt - opthead);			if (optlen == -1)				return(-1);			optlen += 2;			break;		}	}	return(0);  bad:	m_freem(m);	return(-1);}/* * Unknown option processing. * The third argument `off' is the offset from the IPv6 header to the option, * which is necessary if the IPv6 header the and option header and IPv6 header * is not continuous in order to return an ICMPv6 error. */intip6_unknown_opt(optp, m, off)	u_int8_t *optp;	struct mbuf *m;	int off;{	struct ip6_hdr *ip6;	switch (IP6OPT_TYPE(*optp)) {	case IP6OPT_TYPE_SKIP: /* ignore the option */		return((int)*(optp + 1));	case IP6OPT_TYPE_DISCARD:	/* silently discard */		m_freem(m);		return(-1);	case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */		ip6stat.ip6s_badoptions++;		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off);		return(-1);	case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */		ip6stat.ip6s_badoptions++;		ip6 = mtod(m, struct ip6_hdr *);		if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||		    (m->m_flags & (M_BCAST|M_MCAST)))			m_freem(m);		else			icmp6_error(m, ICMP6_PARAM_PROB,				    ICMP6_PARAMPROB_OPTION, off);		return(-1);	}	m_freem(m);		/* XXX: NOTREACHED */	return(-1);}/* * Create the "control" list for this pcb. * The function will not modify mbuf chain at all. * * with KAME mbuf chain restriction: * The routine will be called from upper layer handlers like tcp6_input(). * Thus the routine assumes that the caller (tcp6_input) have already * called IP6_EXTHDR_CHECK() and all the extension headers are located in the * very first mbuf on the mbuf chain. */voidip6_savecontrol(in6p, ip6, m, ctl, prevctlp)#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(HAVE_NRL_INPCB)	struct inpcb *in6p;#else	struct in6pcb *in6p;#endif	struct ip6_hdr *ip6;	struct mbuf *m;	struct ip6_recvpktopts *ctl, **prevctlp;{#define IS2292(x, y)	((in6p->in6p_flags & IN6P_RFC2292) ? (x) : (y))	struct mbuf **mp;	struct cmsghdr *cm = NULL;	struct ip6_recvpktopts *prevctl = NULL;#ifdef HAVE_NRL_INPCB# define in6p_flags	inp_flags#endif#ifdef __bsdi__# define sbcreatecontrol	so_cmsg#endif	int privileged = 1;	if (ctl == NULL)	/* validity check */		return;	bzero(ctl, sizeof(*ctl)); /* XXX is it really OK? */	mp = &ctl->head;	/*	 * If caller wanted to keep history, allocate space to store the	 * history at the first time.	 */	if (prevctlp) {		if (*prevctlp == NULL) {			MALLOC(prevctl, struct ip6_recvpktopts *,			       sizeof(*prevctl), M_IP6OPT, M_NOWAIT);			if (prevctl == NULL) {				printf("ip6_savecontrol: can't allocate "				       " enough space for history\n");				return;			}			bzero(prevctl, sizeof(*prevctl));			*prevctlp = prevctl;		}		else			prevctl = *prevctlp;	}#ifdef SO_TIMESTAMP	if ((in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0) {		struct timeval tv;		microtime(&tv);		*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),				      SCM_TIMESTAMP, SOL_SOCKET);		if (*mp) {			/* always set regradless of the previous value */			ctl->timestamp = *mp;			mp = &(*mp)->m_next;		}	}#endif	/* RFC 2292 sec. 5 */	if ((in6p->in6p_flags & IN6P_PKTINFO) != 0) {		struct in6_pktinfo pi6, *prevpi = NULL;		bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr));		if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr) ||		    IN6_IS_ADDR_MC_INTFACELOCAL(&pi6.ipi6_addr))			pi6.ipi6_addr.s6_addr16[1] = 0;		pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif)					? m->m_pkthdr.rcvif->if_index					: 0;		if (prevctl && prevctl->pktinfo) {			cm = mtod(prevctl->pktinfo, struct cmsghdr *);			prevpi = (struct in6_pktinfo *)CMSG_DATA(cm);		}		/*		 * Make a new option only if this is the first time or if the		 * option value is chaned from last time.		 */		if (prevpi == NULL || bcmp(prevpi, &pi6, sizeof(pi6))) {			*mp = sbcreatecontrol((caddr_t) &pi6,			     sizeof(struct in6_pktinfo),			     IS2292(IPV6_2292PKTINFO, IPV6_PKTINFO),			     IPPROTO_IPV6);			if (*mp) {				ctl->pktinfo = *mp;				mp = &(*mp)->m_next;			}		}	}	if ((in6p->in6p_flags & IN6P_HOPLIMIT) != 0) {		int hlim = ip6->ip6_hlim & 0xff, oldhlim = -1;		if (prevctl && prevctl->hlim) {			cm = mtod(prevctl->hlim, struct cmsghdr *);			bcopy(CMSG_DATA(cm), &oldhlim, sizeof(oldhlim));			oldhlim &= 0xff;		}		if (oldhlim < 0 || hlim != oldhlim) {			*mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int),			    IS2292(IPV6_2292HOPLIMIT, IPV6_HOPLIMIT),			    IPPROTO_IPV6);			if (*mp) {				ctl->hlim = *mp;				mp = &(*mp)->m_next;			}		}	}	if ((in6p->in6p_flags & IN6P_TCLASS) != 0) {		u_int32_t flowinfo;		int oflowinfo = -1;		int v;		flowinfo = (u_int32_t)ntohl(ip6->ip6_flow & IPV6_FLOWINFO_MASK);		flowinfo >>= 20;		if (prevctl && prevctl->hlim) {			cm = mtod(prevctl->hlim, struct cmsghdr *);			bcopy(CMSG_DATA(cm), &v, sizeof(v));			oflowinfo = v & 0xff;		}		if (oflowinfo < 0 || flowinfo != oflowinfo) {			v = flowinfo & 0xff;			*mp = sbcreatecontrol((caddr_t) &v, sizeof(v),			    IPV6_TCLASS, IPPROTO_IPV6);			if (*mp) {				ctl->hlim = *mp;				mp = &(*mp)->m_next;			}		}	}	/*	 * IPV6_HOPOPTS socket option. We require super-user privilege	 * for the option, but it might be too strict, since there might	 * be some hop-by-hop options which can be returned to normal user.	 * See RFC 2292 section 6.	 */	if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0 && privileged) {		/*		 * Check if a hop-by-hop options header is contatined in the		 * received packet, and if so, store the options as ancillary		 * data. Note that a hop-by-hop options header must be		 * just after the IPv6 header, which fact is assured through		 * the IPv6 input processing.		 */		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);		if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {			struct ip6_hbh *hbh, *prevhbh = NULL;			int hbhlen = 0, prevhbhlen = 0;#ifdef PULLDOWN_TEST			struct mbuf *ext;#endif#ifndef PULLDOWN_TEST			hbh = (struct ip6_hbh *)(ip6 + 1);			hbhlen = (hbh->ip6h_len + 1) << 3;#else			ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr),			    ip6->ip6_nxt);			if (ext == NULL) {				ip6stat.ip6s_tooshort++;				return;			}			hbh = mtod(ext, struct ip6_hbh *);			hbhlen = (hbh->ip6h_len + 1) << 3;			if (hbhlen != ext->m_len) {				m_freem(ext);				ip6stat.ip6s_tooshort++;				return;			}#endif			if (prevctl && prevctl->hbh) {				cm = mtod(prevctl->hbh, struct cmsghdr *);				prevhbh = (struct ip6_hbh *)CMSG_DATA(cm);				prevhbhlen = (prevhbh->ip6h_len + 1) << 3;			}			/*			 * Check if there's difference between the current			 * and previous HbH headers.			 * XXX: should the next header field be ignored?			 */			if (prevhbh == NULL || hbhlen != prevhbhlen ||			    bcmp(prevhbh, hbh, hbhlen)) {				/*				 * XXX: We copy whole the header even if a				 * jumbo payload option is included, which				 * option is to be removed before returning				 * in the RFC 2292.				 * Note: this constraint is removed in				 * 2292bis.				 */				*mp = sbcreatecontrol((caddr_t)hbh, hbhlen,				    IS2292(IPV6_2292HOPOPTS, IPV6_HOPOPTS),				    IPPROTO_IPV6);				if (*mp) {					ctl->hbh = *mp;					mp = &(*mp)->m_next;				}			}#ifdef PULLDOWN_TEST			m_freem(ext);#endif		}	}	if ((in6p->in6p_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) {		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);		int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);		/*		 * Search for destination options headers or routing		 * header(s) through the header chain, and stores each		 * header as ancillary data.		 * Note that the order of the headers remains in		 * the chain of ancillary data.		 */		while (1) {	/* is explicit loop prevention necessary? */			struct ip6_ext *ip6e = NULL;			int elen;#ifdef PULLDOWN_TEST			struct mbuf *ext = NULL;#endif			/*			 * if it is not an extension header, don't try to			 * pull it from the chain.			 */			switch (nxt) {			case IPPROTO_DSTOPTS:			case IPPROTO_ROUTING:			case IPPROTO_HOPOPTS:			case IPPROTO_AH: /* is it possible? */				break;			default:				goto loopend;			}#ifndef PULLDOWN_TEST			if (off + sizeof(*ip6e) > m->m_len)				goto loopend;			ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off);			if (nxt == IPPROTO_AH)				elen = (ip6e->ip6e_len + 2) << 2;			else				elen = (ip6e->ip6e_len + 1) << 3;			if (off + elen > m->m_len)				goto loopend;#else			ext = ip6_pullexthdr(m, off, nxt);			if (ext == NULL) {				ip6stat.ip6s_tooshort++;				return;			}			ip6e = mtod(ext, struct ip6_ext *);			if (nxt == IPPROTO_AH)				elen = (ip6e->ip6e_len + 2) << 2;			else				elen = (ip6e->ip6e_len + 1) << 3;			if (elen != ext->m_len) {				m_freem(ext);				ip6stat.ip6s_tooshort++;				return;			}#endif			switch (nxt) {			case IPPROTO_DSTOPTS:			{				struct ip6_dest *prevdest = NULL;				int prevdestlen = 0;				if (!(in6p->in6p_flags & IN6P_DSTOPTS))					break;				/*				 * We also require super-user privilege for				 * the option.  See comments on IN6_HOPOPTS.				 */				if (prevctl && prevctl->dest) {					cm = mtod(prevctl->dest,						  struct cmsghdr *);					prevdest = (struct ip6_dest *)CMSG_DATA(cm);					prevdestlen =						(prevdest->ip6d_len + 1) << 3;				}				/*				 * If this is the 1st dst opt header				 * we enconter and this header is				 * not different from the previous one,				 * simply ignore the header.				 */				if (ctl->dest == NULL && prevdest &&				    prevdestlen == elen &&				    bcmp(ip6e, prevdest, elen) == 0)					break;				*mp = sbcreatecontrol((caddr_t)ip6e, elen,						      IS2292(IPV6_2292DSTOPTS,							     IPV6_DSTOPTS),						      IPPROTO_IPV6);				if (ctl->dest == NULL)					ctl->dest = *mp;				if (*mp)					mp = &(*mp)->m_next;				break;			}			case IPPROTO_ROUTING:			{				struct ip6_rthdr *prevrth = NULL;				int prevrhlen = 0;				if (!in6p->in6p_flags & IN6P_RTHDR)					break;				if (prevctl && prevctl->rthdr) {					cm = mtod(prevctl->rthdr,						  struct cmsghdr *);					prevrth = (struct ip6_rthdr *)CMSG_DATA(cm);					prevrhlen =						(prevrth->ip6r_len + 1) << 3;				}				/*				 * Check if the rthdr should be passed to				 * a user. See the comments for dstopt hdr.				 */				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}voidip6_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)

⌨️ 快捷键说明

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