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

📄 icmp6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		}		nd6_ns_input(n, off, icmp6len);		/* m stays. */		break;	case ND_NEIGHBOR_ADVERT:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);		if (code != 0)			goto badcode;		if (icmp6len < sizeof(struct nd_neighbor_advert))			goto badlen;		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {			/* give up local */			nd6_na_input(m, off, icmp6len);			m = NULL;			goto freeit;		}		nd6_na_input(n, off, icmp6len);		/* m stays. */		break;	case ND_REDIRECT:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);		if (code != 0)			goto badcode;		if (icmp6len < sizeof(struct nd_redirect))			goto badlen;		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {			/* give up local */			icmp6_redirect_input(m, off);			m = NULL;			goto freeit;		}		icmp6_redirect_input(n, off);		/* m stays. */		break;	case ICMP6_ROUTER_RENUMBERING:		if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&		    code != ICMP6_ROUTER_RENUMBERING_RESULT)			goto badcode;		if (icmp6len < sizeof(struct icmp6_router_renum))			goto badlen;		break;	default:		nd6log((LOG_DEBUG,		    "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",		    icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),		    ip6_sprintf(&ip6->ip6_dst),		    m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0));		if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {			/* ICMPv6 error: MUST deliver it by spec... */			code = PRC_NCMDS;			/* deliver */		} else {			/* ICMPv6 informational: MUST not deliver */			break;		}	deliver:		if (icmp6_notify_error(m, off, icmp6len, code)) {			/* In this case, m should've been freed. */			return(IPPROTO_DONE);		}		break;	badcode:		icmp6stat.icp6s_badcode++;		break;	badlen:		icmp6stat.icp6s_badlen++;		break;	}	/* deliver the packet to appropriate sockets */	icmp6_rip6_input(&m, *offp);	return IPPROTO_DONE; freeit:	m_freem(m);	return IPPROTO_DONE;}static inticmp6_notify_error(m, off, icmp6len, code)	struct mbuf *m;	int off, icmp6len;{	struct icmp6_hdr *icmp6;	struct ip6_hdr *eip6;	u_int32_t notifymtu;	int64_t zoneid;	struct sockaddr_in6 icmp6src, icmp6dst;	if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {		icmp6stat.icp6s_tooshort++;		goto freeit;	}#ifndef PULLDOWN_TEST	IP6_EXTHDR_CHECK(m, off,			 sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),			 -1);	icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);#else	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,		       sizeof(*icmp6) + sizeof(struct ip6_hdr));	if (icmp6 == NULL) {		icmp6stat.icp6s_tooshort++;		return(-1);	}#endif	eip6 = (struct ip6_hdr *)(icmp6 + 1);	/* Detect the upper level protocol */	{		void (*ctlfunc) __P((int, struct sockaddr *, void *));		u_int8_t nxt = eip6->ip6_nxt;		int eoff = off + sizeof(struct icmp6_hdr) +			sizeof(struct ip6_hdr);		struct ip6ctlparam ip6cp;		struct in6_addr *finaldst = NULL;		int icmp6type = icmp6->icmp6_type;		struct ip6_frag *fh;		struct ip6_rthdr *rth;		struct ip6_rthdr0 *rth0;		int rthlen;		while (1) { /* XXX: should avoid infinite loop explicitly? */			struct ip6_ext *eh;			switch (nxt) {			case IPPROTO_HOPOPTS:			case IPPROTO_DSTOPTS:			case IPPROTO_AH:#ifndef PULLDOWN_TEST				IP6_EXTHDR_CHECK(m, 0, eoff +						 sizeof(struct ip6_ext),						 -1);				eh = (struct ip6_ext *)(mtod(m, caddr_t)							+ eoff);#else				IP6_EXTHDR_GET(eh, struct ip6_ext *, m,					       eoff, sizeof(*eh));				if (eh == NULL) {					icmp6stat.icp6s_tooshort++;					return(-1);				}#endif								if (nxt == IPPROTO_AH)					eoff += (eh->ip6e_len + 2) << 2;				else					eoff += (eh->ip6e_len + 1) << 3;				nxt = eh->ip6e_nxt;				break;			case IPPROTO_ROUTING:				/*				 * When the erroneous packet contains a				 * routing header, we should examine the				 * header to determine the final destination.				 * Otherwise, we can't properly update				 * information that depends on the final				 * destination (e.g. path MTU).				 */#ifndef PULLDOWN_TEST				IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),						 -1);				rth = (struct ip6_rthdr *)(mtod(m, caddr_t)							   + eoff);#else				IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,					       eoff, sizeof(*rth));				if (rth == NULL) {					icmp6stat.icp6s_tooshort++;					return(-1);				}#endif				rthlen = (rth->ip6r_len + 1) << 3;				/*				 * XXX: currently there is no				 * officially defined type other				 * than type-0.				 * Note that if the segment left field				 * is 0, all intermediate hops must				 * have been passed.				 */				if (rth->ip6r_segleft &&				    rth->ip6r_type == IPV6_RTHDR_TYPE_0) {					int hops;#ifndef PULLDOWN_TEST					IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,							 -1);					rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);#else					IP6_EXTHDR_GET(rth0,						       struct ip6_rthdr0 *, m,						       eoff, rthlen);					if (rth0 == NULL) {						icmp6stat.icp6s_tooshort++;						return(-1);					}#endif					/* just ignore a bogus header */					if ((rth0->ip6r0_len % 2) == 0 &&					    (hops = rth0->ip6r0_len/2))						finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);				}				eoff += rthlen;				nxt = rth->ip6r_nxt;				break;			case IPPROTO_FRAGMENT:#ifndef PULLDOWN_TEST				IP6_EXTHDR_CHECK(m, 0, eoff +						 sizeof(struct ip6_frag),						 -1);				fh = (struct ip6_frag *)(mtod(m, caddr_t)							 + eoff);#else				IP6_EXTHDR_GET(fh, struct ip6_frag *, m,					       eoff, sizeof(*fh));				if (fh == NULL) {					icmp6stat.icp6s_tooshort++;					return(-1);				}#endif				/*				 * Data after a fragment header is meaningless				 * unless it is the first fragment, but				 * we'll go to the notify label for path MTU				 * discovery.				 */				if (fh->ip6f_offlg & IP6F_OFF_MASK)					goto notify;				eoff += sizeof(struct ip6_frag);				nxt = fh->ip6f_nxt;				break;			default:				/*				 * This case includes ESP and the No Next				 * Header.  In such cases going to the notify				 * label does not have any meaning				 * (i.e. ctlfunc will be NULL), but we go				 * anyway since we might have to update				 * path MTU information.				 */				goto notify;			}		}	  notify:#ifndef PULLDOWN_TEST		icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);#else		IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,			       sizeof(*icmp6) + sizeof(struct ip6_hdr));		if (icmp6 == NULL) {			icmp6stat.icp6s_tooshort++;			return(-1);		}#endif		eip6 = (struct ip6_hdr *)(icmp6 + 1);		bzero(&icmp6dst, sizeof(icmp6dst));		icmp6dst.sin6_len = sizeof(struct sockaddr_in6);		icmp6dst.sin6_family = AF_INET6;		if (finaldst == NULL)			icmp6dst.sin6_addr = eip6->ip6_dst;		else			icmp6dst.sin6_addr = *finaldst;		if ((zoneid = in6_addr2zoneid(m->m_pkthdr.rcvif,					      &icmp6dst.sin6_addr)) < 0)			goto freeit;		icmp6dst.sin6_scope_id = zoneid;		if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst)) {			/* should be impossbile */			nd6log((LOG_DEBUG,			    "icmp6_notify_error: in6_embedscope failed\n"));			goto freeit;		}		/*		 * retrieve parameters from the inner IPv6 header, and convert		 * them into sockaddr structures.		 */		bzero(&icmp6src, sizeof(icmp6src));		icmp6src.sin6_len = sizeof(struct sockaddr_in6);		icmp6src.sin6_family = AF_INET6;		icmp6src.sin6_addr = eip6->ip6_src;		if ((zoneid = in6_addr2zoneid(m->m_pkthdr.rcvif,					      &icmp6src.sin6_addr)) < 0)			goto freeit;		icmp6src.sin6_scope_id = zoneid;		if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src)) {			/* should be impossbile */			nd6log((LOG_DEBUG,			    "icmp6_notify_error: in6_embedscope failed\n"));			goto freeit;		}		icmp6src.sin6_flowinfo =			(eip6->ip6_flow & IPV6_FLOWLABEL_MASK);		if (finaldst == NULL)			finaldst = &eip6->ip6_dst;		ip6cp.ip6c_m = m;		ip6cp.ip6c_icmp6 = icmp6;		ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);		ip6cp.ip6c_off = eoff;		ip6cp.ip6c_finaldst = finaldst;		ip6cp.ip6c_src = &icmp6src;		ip6cp.ip6c_nxt = nxt;		if (icmp6type == ICMP6_PACKET_TOO_BIG) {			notifymtu = ntohl(icmp6->icmp6_mtu);			ip6cp.ip6c_cmdarg = (void *)&notifymtu;#if !(defined(__NetBSD__) || defined(__OpenBSD__))			icmp6_mtudisc_update(&ip6cp, 1);	/* XXX */#endif		}		ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))			(inet6sw[ip6_protox[nxt]].pr_ctlinput);		if (ctlfunc) {			(void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst,					  &ip6cp);		}	}	return(0);  freeit:	m_freem(m);	return(-1);}voidicmp6_mtudisc_update(ip6cp, validated)	struct ip6ctlparam *ip6cp;	int validated;{#if defined(__NetBSD__) || defined(__OpenBSD__)	unsigned long rtcount;	struct icmp6_mtudisc_callback *mc;#endif	struct in6_addr *dst = ip6cp->ip6c_finaldst;	struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;	struct mbuf *m = ip6cp->ip6c_m;	/* will be necessary for scope issue */	u_int mtu = ntohl(icmp6->icmp6_mtu);	struct rtentry *rt = NULL;	struct sockaddr_in6 sin6;#ifdef __bsdi__#ifdef NEW_STRUCT_ROUTE	struct route ro6;#else	struct route_in6 ro6;#endif#endif#if defined(__NetBSD__) || defined(__OpenBSD__)	/*	 * allow non-validated cases if memory is plenty, to make traffic	 * from non-connected pcb happy.	 */	rtcount = rt_timer_count(icmp6_mtudisc_timeout_q);	if (validated) {		if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat)			return;		else if (0 <= icmp6_mtudisc_lowat &&		    rtcount > icmp6_mtudisc_lowat) {			/*			 * XXX nuke a victim, install the new one.			 */		}	} else {		if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat)			return;	}#else	if (!validated)		return;#endif	bzero(&sin6, sizeof(sin6));	sin6.sin6_family = PF_INET6;	sin6.sin6_len = sizeof(struct sockaddr_in6);	sin6.sin6_addr = *dst;	/* XXX normally, this won't happen */	if (IN6_IS_ADDR_LINKLOCAL(dst)) {		sin6.sin6_addr.s6_addr16[1] =		    htons(m->m_pkthdr.rcvif->if_index);	}	/* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */#if defined(__NetBSD__) || defined(__OpenBSD__)	rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);#else#ifdef __FreeBSD__	rt = rtalloc1((struct sockaddr *)&sin6, 0,		      RTF_CLONING | RTF_PRCLONING);#else#ifdef __bsdi__	bcopy(&sin6, &ro6.ro_dst, sizeof(struct sockaddr_in6));	ro6.ro_rt = 0;	/* rtcalloc((struct route *)&ro6); */	rtalloc((struct route *)&ro6);	rt = ro6.ro_rt;#else#error no case for this particular operating system#endif#endif#endif	if (rt && (rt->rt_flags & RTF_HOST)	    && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {		if (mtu < IPV6_MMTU) {				/* xxx */			rt->rt_rmx.rmx_locks |= RTV_MTU;		} else if (mtu < rt->rt_ifp->if_mtu &&			   rt->rt_rmx.rmx_mtu > mtu) {			icmp6stat.icp6s_pmtuchg++;			rt->rt_rmx.rmx_mtu = mtu;		}	}	if (rt) { /* XXX: need braces to avoid conflict with else in RTFREE. */		RTFREE(rt);	}#if defined(__NetBSD__) || defined(__OpenBSD__)	/*	 * Notify protocols that the MTU for this destination	 * has changed.	 */	for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;	     mc = LIST_NEXT(mc, mc_list))		(*mc->mc_func)(&sin6.sin6_addr);#endif}/* * Process a Node Information Query packet, based on * draft-ietf-ipngwg-icmp-name-lookups-07. *  * Spec incompatibilities: * - IPv6 Subject address handling * - IPv4 Subject address handling support missing * - Proxy reply (answer even if it's not for me) * - joins NI group address at in6_ifattach() time only, does not cope *   with hostname changes by sethostname(3) */#ifdef __FreeBSD__#define hostnamelen	strlen(hostname)#endif#ifndef offsetof		/* XXX */#define	offsetof(type, member)	((size_t)(&((type *)0)->member))#endifstatic struct mbuf *ni6_input(m, off)	struct mbuf *m;	int off;{	struct icmp6_nodeinfo *ni6, *nni6;	struct mbuf *n = NULL;	u_int16_t qtype;	int subjlen;	int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);	struct ni_reply_fqdn *fqdn;	int addrs;		/* for NI_QTYPE_NODEADDR */	struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */	struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */	struct sockaddr_in6 sin6_d; /* XXX: we should retrieve this from m_aux */	struct ip6_hdr *ip6;	int oldfqdn = 0;	/* if 1, return pascal string (03 draft) */	char *subj = NULL;	struct in6_ifaddr *ia6 = NULL;	int64_t zoneid;	ip6 = mtod(m, struct ip6_hdr *);#ifndef PULLDOWN_TEST	ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off);#else	IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));	if (ni6 == NULL) {		/* m is already reclaimed */		return NULL;	}#endif	/*	 * Validate IPv6 destination address.	 *	 * The Responder must discard the Query without further processing	 * unless it is one of the Responder's unicast or anycast addresses, or	 * a link-local scope multicast address which the Responder has joined.	 * [icmp-name-lookups-07, Section 4.]

⌨️ 快捷键说明

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