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

📄 icmp6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	icmp6->icmp6_type = type;	icmp6->icmp6_code = code;	icmp6->icmp6_pptr = htonl((u_int32_t)param);	/*	 * icmp6_reflect() is designed to be in the input path.	 * icmp6_error() can be called from both input and outut path,	 * and if we are in output path rcvif could contain bogus value.	 * clear m->m_pkthdr.rcvif for safety, we should have enough scope	 * information in ip header (nip6).	 */	m->m_pkthdr.rcvif = NULL;	icmp6stat.icp6s_outhist[type]++;	icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */	return;  freeit:	/*	 * If we can't tell wheter or not we can generate ICMP6, free it.	 */	m_freem(m);}/* * Process a received ICMP6 message. */inticmp6_input(mp, offp, proto)	struct mbuf **mp;	int *offp, proto;{	struct mbuf *m = *mp, *n;	struct ip6_hdr *ip6, *nip6;	struct icmp6_hdr *icmp6, *nicmp6;	int off = *offp;	int icmp6len = m->m_pkthdr.len - *offp;	int code, sum, noff;	icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);#ifndef PULLDOWN_TEST	IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);	/* m might change if M_LOOP.  So, call mtod after this */#endif	/*	 * Locate icmp6 structure in mbuf, and check	 * that not corrupted and of at least minimum length	 */	ip6 = mtod(m, struct ip6_hdr *);	if (icmp6len < sizeof(struct icmp6_hdr)) {		icmp6stat.icp6s_tooshort++;		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);		goto freeit;	}	/*	 * calculate the checksum	 */#ifndef PULLDOWN_TEST	icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);#else	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));	if (icmp6 == NULL) {		icmp6stat.icp6s_tooshort++;		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);		return IPPROTO_DONE;	}#endif	code = icmp6->icmp6_code;	if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {		nd6log((LOG_ERR,		    "ICMP6 checksum error(%d|%x) %s\n",		    icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src)));		icmp6stat.icp6s_checksum++;		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);		goto freeit;	}#if defined(NFAITH) && 0 < NFAITH	if (faithprefix(&ip6->ip6_dst)) {		/*		 * Deliver very specific ICMP6 type only.		 * This is important to deilver TOOBIG.  Otherwise PMTUD		 * will not work.		 */		switch (icmp6->icmp6_type) {		case ICMP6_DST_UNREACH:		case ICMP6_PACKET_TOO_BIG:		case ICMP6_TIME_EXCEEDED:			break;		default:			goto freeit;		}	}#endif	icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;#ifdef MIP6	if (mip6_icmp6_tunnel_input(m, off, icmp6len)) {		goto freeit;	}#endif /* MIP6 */	switch (icmp6->icmp6_type) {	case ICMP6_DST_UNREACH:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);#ifdef MIP6		if (mip6_icmp6_input(m, off, icmp6len))			goto freeit;#endif /* MIP6 */		switch (code) {		case ICMP6_DST_UNREACH_NOROUTE:			code = PRC_UNREACH_NET;			break;		case ICMP6_DST_UNREACH_ADMIN:			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);			code = PRC_UNREACH_PROTOCOL; /* is this a good code? */			break;		case ICMP6_DST_UNREACH_ADDR:			code = PRC_HOSTDEAD;			break;#ifdef COMPAT_RFC1885		case ICMP6_DST_UNREACH_NOTNEIGHBOR:			code = PRC_UNREACH_SRCFAIL;			break;#else		case ICMP6_DST_UNREACH_BEYONDSCOPE:			/* I mean "source address was incorrect." */			code = PRC_UNREACH_NET;			break;#endif		case ICMP6_DST_UNREACH_NOPORT:			code = PRC_UNREACH_PORT;			break;		default:			goto badcode;		}		goto deliver;		break;	case ICMP6_PACKET_TOO_BIG:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);		if (code != 0)			goto badcode;		code = PRC_MSGSIZE;		/*		 * Updating the path MTU will be done after examining		 * intermediate extension headers.		 */		goto deliver;		break;	case ICMP6_TIME_EXCEEDED:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);		switch (code) {		case ICMP6_TIME_EXCEED_TRANSIT:			code = PRC_TIMXCEED_INTRANS;			break;		case ICMP6_TIME_EXCEED_REASSEMBLY:			code = PRC_TIMXCEED_REASS;			break;		default:			goto badcode;		}		goto deliver;		break;	case ICMP6_PARAM_PROB:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);		switch (code) {		case ICMP6_PARAMPROB_NEXTHEADER:			code = PRC_UNREACH_PROTOCOL;			break;		case ICMP6_PARAMPROB_HEADER:		case ICMP6_PARAMPROB_OPTION:#ifdef MIP6			if (mip6_icmp6_input(m, off, icmp6len))				goto freeit;#endif /* MIP6 */			code = PRC_PARAMPROB;			break;		default:			goto badcode;		}		goto deliver;		break;	case ICMP6_ECHO_REQUEST:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);		if (code != 0)			goto badcode;		/*		 * Copy mbuf to send to two data paths: userland socket(s),		 * and to the querier (echo reply).		 * m: a copy for socket, n: a copy for querier		 */		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {			/* Give up local */			n = m;			m = NULL;			goto deliverecho;		}		/*		 * If the first mbuf is shared, or the first mbuf is too short,		 * copy the first part of the data into a fresh mbuf.		 * Otherwise, we will wrongly overwrite both copies.		 */		if ((n->m_flags & M_EXT) != 0 ||		    n->m_len < off + sizeof(struct icmp6_hdr)) {			struct mbuf *n0 = n;			const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);			/*			 * Prepare an internal mbuf.  m_pullup() doesn't			 * always copy the length we specified.			 */			if (maxlen >= MCLBYTES) {				/* Give up remote */				m_freem(n0);				break;			}			MGETHDR(n, M_DONTWAIT, n0->m_type);			if (n && maxlen >= MHLEN) {				MCLGET(n, M_DONTWAIT);				if ((n->m_flags & M_EXT) == 0) {					m_free(n);					n = NULL;				}			}			if (n == NULL) {				/* Give up local */				m_freem(n0);				n = m;				m = NULL;				goto deliverecho;			}#ifdef __OpenBSD__			M_MOVE_PKTHDR(n, n0);#else			M_COPY_PKTHDR(n, n0);#endif			/*			 * Copy IPv6 and ICMPv6 only.			 */			nip6 = mtod(n, struct ip6_hdr *);			bcopy(ip6, nip6, sizeof(struct ip6_hdr));			nicmp6 = (struct icmp6_hdr *)(nip6 + 1);			bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));			noff = sizeof(struct ip6_hdr);			n->m_len = noff + sizeof(struct icmp6_hdr);			/*			 * Adjust mbuf.  ip6_plen will be adjusted in			 * ip6_output().			 * n->m_pkthdr.len == n0->m_pkthdr.len at this point.			 */			n->m_pkthdr.len += noff + sizeof(struct icmp6_hdr);			n->m_pkthdr.len -= (off + sizeof(struct icmp6_hdr));			m_adj(n0, off + sizeof(struct icmp6_hdr));			n->m_next = n0;			n0->m_flags &= ~M_PKTHDR;		} else {	 deliverecho:			nip6 = mtod(n, struct ip6_hdr *);			nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off);			noff = off;		}		nicmp6->icmp6_type = ICMP6_ECHO_REPLY;		nicmp6->icmp6_code = 0;		if (n) {			icmp6stat.icp6s_reflect++;			icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;			icmp6_reflect(n, noff);		}		if (!m)			goto freeit;		break;	case ICMP6_ECHO_REPLY:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);		if (code != 0)			goto badcode;		break;#ifdef MIP6	case ICMP6_HADISCOV_REQUEST:		if (icmp6len < sizeof(struct ha_discov_req))			goto badlen;		if (code != 0)			goto badcode;		if (mip6_icmp6_input(m, off, icmp6len))			goto freeit;		break;	case ICMP6_HADISCOV_REPLY:		if (icmp6len < sizeof(struct ha_discov_rep))			goto badlen;		if (code != 0)			goto badcode;		if (mip6_icmp6_input(m, off, icmp6len))			goto freeit;		break;#ifndef MIP6_DRAFT13	case ICMP6_MOBILEPREFIX_SOLICIT:		if (icmp6len < sizeof(struct mobile_prefix_solicit))			goto badlen;		if (code != 0)			goto badcode;		if (mip6_icmp6_input(m, off, icmp6len))			goto freeit;		break;	case ICMP6_MOBILEPREFIX_ADVERT:		if (icmp6len < sizeof (struct mobile_prefix_advert))			goto badlen;		if (code != 0)			goto badcode;		if (mip6_icmp6_input(m, off, icmp6len))			goto freeit;		break;#endif /* !MIP6_DRAFT13 */#endif /* MIP6 */	case MLD_LISTENER_QUERY:	case MLD_LISTENER_REPORT:		if (icmp6len < sizeof(struct mld_hdr))			goto badlen;		if (icmp6->icmp6_type == MLD_LISTENER_QUERY) /* XXX: ugly... */			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);		else			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {			/* give up local */			mld6_input(m, off);			m = NULL;			goto freeit;		}		mld6_input(n, off);		/* m stays. */		break;	case MLD_LISTENER_DONE:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);		if (icmp6len < sizeof(struct mld_hdr))	/* necessary? */			goto badlen;		break;		/* nothing to be done in kernel */	case MLD_MTRACE_RESP:	case MLD_MTRACE:		/* XXX: these two are experimental.  not officially defined. */		/* XXX: per-interface statistics? */		break;		/* just pass it to applications */	case ICMP6_WRUREQUEST:	/* ICMP6_FQDN_QUERY */	    {		enum { WRU, FQDN } mode;		if (!icmp6_nodeinfo)			break;		if (icmp6len == sizeof(struct icmp6_hdr) + 4)			mode = WRU;		else if (icmp6len >= sizeof(struct icmp6_nodeinfo))			mode = FQDN;		else			goto badlen;#ifdef __FreeBSD__#define hostnamelen	strlen(hostname)#endif		if (mode == FQDN) {#ifndef PULLDOWN_TEST			IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),					 IPPROTO_DONE);#endif			n = m_copym(m, 0, M_COPYALL, M_DONTWAIT);			if (n)				n = ni6_input(n, off);			/* XXX meaningless if n == NULL */			noff = sizeof(struct ip6_hdr);		} else {			u_char *p;			int maxlen, maxhlen;			if ((icmp6_nodeinfo & 5) != 5) 				break;			if (code != 0)				goto badcode;			maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;			if (maxlen >= MCLBYTES) {				/* Give up remote */				break;			}			MGETHDR(n, M_DONTWAIT, m->m_type);			if (n && maxlen > MHLEN) {				MCLGET(n, M_DONTWAIT);				if ((n->m_flags & M_EXT) == 0) {					m_free(n);					n = NULL;				}			}			if (n == NULL) {				/* Give up remote */				break;			}			n->m_pkthdr.rcvif = NULL;			n->m_len = 0;			maxhlen = M_TRAILINGSPACE(n) - maxlen;			if (maxhlen > hostnamelen)				maxhlen = hostnamelen;			/*			 * Copy IPv6 and ICMPv6 only.			 */			nip6 = mtod(n, struct ip6_hdr *);			bcopy(ip6, nip6, sizeof(struct ip6_hdr));			nicmp6 = (struct icmp6_hdr *)(nip6 + 1);			bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));			p = (u_char *)(nicmp6 + 1);			bzero(p, 4);			bcopy(hostname, p + 4, maxhlen); /* meaningless TTL */			noff = sizeof(struct ip6_hdr);#ifdef __OpenBSD__			M_DUP_PKTHDR(n, m); /* just for rcvif */#else			M_COPY_PKTHDR(n, m); /* just for rcvif */#endif			n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +				sizeof(struct icmp6_hdr) + 4 + maxhlen;			nicmp6->icmp6_type = ICMP6_WRUREPLY;			nicmp6->icmp6_code = 0;		}#undef hostnamelen		if (n) {			icmp6stat.icp6s_reflect++;			icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;			icmp6_reflect(n, noff);		}		break;	    }	case ICMP6_WRUREPLY:		if (code != 0)			goto badcode;		break;	case ND_ROUTER_SOLICIT:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);		if (code != 0)			goto badcode;		if (icmp6len < sizeof(struct nd_router_solicit))			goto badlen;		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {			/* give up local */			nd6_rs_input(m, off, icmp6len);			m = NULL;			goto freeit;		}		nd6_rs_input(n, off, icmp6len);		/* m stays. */		break;	case ND_ROUTER_ADVERT:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);		if (code != 0)			goto badcode;		if (icmp6len < sizeof(struct nd_router_advert))			goto badlen;		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {			/* give up local */			nd6_ra_input(m, off, icmp6len);			m = NULL;			goto freeit;		}		nd6_ra_input(n, off, icmp6len);		/* m stays. */		break;	case ND_NEIGHBOR_SOLICIT:		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);		if (code != 0)			goto badcode;		if (icmp6len < sizeof(struct nd_neighbor_solicit))			goto badlen;		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {			/* give up local */			nd6_ns_input(m, off, icmp6len);			m = NULL;			goto freeit;

⌨️ 快捷键说明

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