in6_gif.c

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

C
662
字号
	if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))		ip6->ip6_dst = sin6_dst->sin6_addr;	else  {		m_freem(m);		return ENETUNREACH;	}	if (ifp->if_flags & IFF_LINK1)		ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);	else		ip_ecn_ingress(ECN_NOCARE, &otos, &itos);	ip6->ip6_flow &= ~ntohl(0xff00000);	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)	time_second = time.tv_sec;#endif	/*	 * compare address family just for safety.  other validity checks	 * are made in in6_selectsrc() called from ip6_output().	 */	if (sc->gif_ro6.ro_rt && (dst->sin6_family != sin6_dst->sin6_family ||				  sc->rtcache_expire == 0 ||				  time_second >= sc->rtcache_expire)) {		/*		 * If the cached route is not valid or has expired,		 * clear the stale cache and let ip6_output make a new cached		 * route.		 */		RTFREE(sc->gif_ro6.ro_rt);		sc->gif_ro6.ro_rt = NULL;	}#ifdef IPV6_MINMTU	/*	 * force fragmentation to minimum MTU, to avoid path MTU discovery.	 * it is too painful to ask for resend of inner packet, to achieve	 * path MTU discovery for encapsulated packets.	 */	error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL);#else	error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL);#endif	/*	 * if a (new) cached route has been created in ip6_output(), extend	 * the expiration time.	 */	if (sc->gif_ro6.ro_rt && time_second >= sc->rtcache_expire)		sc->rtcache_expire = time_second + in6_gif_rtcachettl;	return(error);#endif	/* __OpenBSD__ */}int in6_gif_input(mp, offp, proto)	struct mbuf **mp;	int *offp, proto;{	struct mbuf *m = *mp;	struct ifnet *gifp = NULL;	struct ip6_hdr *ip6;#ifndef __OpenBSD__	int af = 0;	u_int32_t otos;#endif	ip6 = mtod(m, struct ip6_hdr *);	gifp = (struct ifnet *)encap_getarg(m);	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {		m_freem(m);		ip6stat.ip6s_nogif++;		return IPPROTO_DONE;	}#ifndef USE_ENCAPCHECK	if (!gif_validate6(ip6, (struct gif_softc *)gifp, m->m_pkthdr.rcvif)) {		m_freem(m);		ip6stat.ip6s_nogif++;		return IPPROTO_DONE;	}#endif#ifdef __OpenBSD__	m->m_pkthdr.rcvif = gifp;	gifp->if_ipackets++;	gifp->if_ibytes += m->m_pkthdr.len;	ipip_input(m, *offp, gifp);	return IPPROTO_DONE;#else	otos = ip6->ip6_flow;	m_adj(m, *offp);	switch (proto) {#ifdef INET	case IPPROTO_IPV4:	    {		struct ip *ip;		u_int8_t otos8;		af = AF_INET;		otos8 = (ntohl(otos) >> 20) & 0xff;		if (m->m_len < sizeof(*ip)) {			m = m_pullup(m, sizeof(*ip));			if (!m)				return IPPROTO_DONE;		}		ip = mtod(m, struct ip *);		if (gifp->if_flags & IFF_LINK1)			ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);		else			ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);		break;	    }#endif /* INET */#ifdef INET6	case IPPROTO_IPV6:	    {		struct ip6_hdr *ip6;		af = AF_INET6;		if (m->m_len < sizeof(*ip6)) {			m = m_pullup(m, sizeof(*ip6));			if (!m)				return IPPROTO_DONE;		}		ip6 = mtod(m, struct ip6_hdr *);		if (gifp->if_flags & IFF_LINK1)			ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);		else			ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);		break;	    }#endif#if defined(__NetBSD__) && defined(ISO)	case IPPROTO_EON:		af = AF_ISO;		break;#endif	default:		ip6stat.ip6s_nogif++;		m_freem(m);		return IPPROTO_DONE;	}			gif_input(m, af, gifp);	return IPPROTO_DONE;#endif}/* * validate outer address. */static intgif_validate6(ip6, sc, ifp)	const struct ip6_hdr *ip6;	struct gif_softc *sc;	struct ifnet *ifp;{	struct sockaddr_in6 *src, *dst;	src = (struct sockaddr_in6 *)sc->gif_psrc;	dst = (struct sockaddr_in6 *)sc->gif_pdst;	/* check for address match */	if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))		return 0;	/* martian filters on outer source - done in ip6_input */	/* ingress filters on outer source */	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {		struct sockaddr_in6 sin6;		struct rtentry *rt;		bzero(&sin6, sizeof(sin6));		sin6.sin6_family = AF_INET6;		sin6.sin6_len = sizeof(struct sockaddr_in6);		sin6.sin6_addr = ip6->ip6_src;		/* XXX scopeid */#ifdef __FreeBSD__		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);#else		rt = rtalloc1((struct sockaddr *)&sin6, 0);#endif		if (!rt || rt->rt_ifp != ifp) {#if 0			log(LOG_WARNING, "%s: packet from %s dropped "			    "due to ingress filter\n", if_name(&sc->gif_if),			    ip6_sprintf(&sin6.sin6_addr));#endif			if (rt)				rtfree(rt);			return 0;		}		rtfree(rt);	}	return 128 * 2;}/* * we know that we are in IFF_UP, outer address available, and outer family * matched the physical addr family.  see gif_encapcheck(). */intgif_encapcheck6(m, off, proto, arg)	const struct mbuf *m;	int off;	int proto;	void *arg;{	struct ip6_hdr ip6;	struct gif_softc *sc;	struct ifnet *ifp;	/* sanity check done in caller */	sc = (struct gif_softc *)arg;	/* LINTED const cast */	m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6);	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;	return gif_validate6(&ip6, sc, ifp);}intin6_gif_attach(sc)	struct gif_softc *sc;{#ifndef USE_ENCAPCHECK	struct sockaddr_in6 mask6;	bzero(&mask6, sizeof(mask6));	mask6.sin6_len = sizeof(struct sockaddr_in6);	mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] = 	    mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;	if (!sc->gif_psrc || !sc->gif_pdst)		return EINVAL;	sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc,	    (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6,	    (struct protosw *)&in6_gif_protosw, sc);#else	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,	    (struct protosw *)&in6_gif_protosw, sc);#endif	if (sc->encap_cookie6 == NULL)		return EEXIST;	return 0;}intin6_gif_detach(sc)	struct gif_softc *sc;{	int error;	error = encap_detach(sc->encap_cookie6);	if (error == 0)		sc->encap_cookie6 = NULL;	return error;}voidin6_gif_ctlinput(cmd, sa, d)	int cmd;	struct sockaddr *sa;	void *d;{	struct gif_softc *sc;	struct ip6ctlparam *ip6cp = NULL;	struct mbuf *m;	struct ip6_hdr *ip6;	int off;	void *cmdarg;	const struct sockaddr_in6 *sa6_src = NULL;	struct sockaddr_in6 *dst6;	if (sa->sa_family != AF_INET6 ||	    sa->sa_len != sizeof(struct sockaddr_in6))		return;	if ((unsigned)cmd >= PRC_NCMDS)		return;	if (cmd == PRC_HOSTDEAD)		d = NULL;	else if (inet6ctlerrmap[cmd] == 0)		return;	/* if the parameter is from icmp6, decode it. */	if (d != NULL) {		ip6cp = (struct ip6ctlparam *)d;		m = ip6cp->ip6c_m;		ip6 = ip6cp->ip6c_ip6;		off = ip6cp->ip6c_off;		cmdarg = ip6cp->ip6c_cmdarg;		sa6_src = ip6cp->ip6c_src;	} else {		m = NULL;		ip6 = NULL;		cmdarg = NULL;		sa6_src = &sa6_any;	}	if (!ip6)		return;	/*	 * for now we don't care which type it was, just flush the route cache.	 * XXX slow.  sc (or sc->encap_cookie6) should be passed from	 * ip_encap.c.	 */	for (sc = LIST_FIRST(&gif_softc_list); sc;	     sc = LIST_NEXT(sc, gif_list)) {		if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)			continue;		if (sc->gif_psrc->sa_family != AF_INET6)			continue;		if (!sc->gif_ro6.ro_rt)			continue;		dst6 = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;		/* XXX scope */		if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr)) {			/* flush route cache */			RTFREE(sc->gif_ro6.ro_rt);			sc->gif_ro6.ro_rt = NULL;		}	}}

⌨️ 快捷键说明

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