proto = va_arg(ap, int);
icmp_input(struct mbuf *m, ...)#elseicmp_input(m, va_alist)	struct mbuf *m;	va_dcl#endif{	int proto;	register struct icmp *icp;	register struct ip *ip = mtod(m, struct ip *);	int icmplen = ip->ip_len;	register int i;	struct in_ifaddr *ia;	void *(*ctlfunc) __P((int, struct sockaddr *, void *));	int code;	extern u_char ip_protox[];	int hlen;	va_list ap;	va_start(ap, m);	hlen = va_arg(ap, int);	proto = va_arg(ap, int);	va_end(ap);	/*	 * Locate icmp structure in mbuf, and check	 * that not corrupted and of at least minimum length.	 */#ifdef ICMPPRINTFS	if (icmpprintfs) {		char buf[4*sizeof "123"];		strcpy(buf, inet_ntoa(ip->ip_dst));		printf("icmp_input from %s to %s, len %d\n",			inet_ntoa(ip->ip_src), buf, icmplen);	}#endif	if (icmplen < ICMP_MINLEN) {		icmpstat.icps_tooshort++;		goto freeit;	}	i = hlen + min(icmplen, ICMP_ADVLENMIN);	if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {		icmpstat.icps_tooshort++;		return;	}	ip = mtod(m, struct ip *);	m->m_len -= hlen;	m->m_data += hlen;	icp = mtod(m, struct icmp *);	if (in_cksum(m, icmplen)) {		icmpstat.icps_checksum++;		goto freeit;	}	m->m_len += hlen;	m->m_data -= hlen;#ifdef ICMPPRINTFS	/*	 * Message type specific processing.	 */	if (icmpprintfs)		printf("icmp_input, type %d code %d\n", icp->icmp_type,		    icp->icmp_code);#endif#if 0 /*KAME IPSEC*/	/* drop it if it does not match the policy */	if (ipsec4_in_reject(m, NULL)) {		ipsecstat.in_polvio++;		goto freeit;	}#endif	if (icp->icmp_type > ICMP_MAXTYPE)		goto raw;	icmpstat.icps_inhist[icp->icmp_type]++;	code = icp->icmp_code;	switch (icp->icmp_type) {	case ICMP_UNREACH:		switch (code) {		case ICMP_UNREACH_NET:		case ICMP_UNREACH_HOST:		case ICMP_UNREACH_PROTOCOL:		case ICMP_UNREACH_PORT:		case ICMP_UNREACH_SRCFAIL:			code += PRC_UNREACH_NET;			break;		case ICMP_UNREACH_NEEDFRAG:#if 0 /*NRL INET6*/			if (icp->icmp_nextmtu) {				extern int ipv6_trans_mtu				    __P((struct mbuf **, int, int));				struct mbuf *m0 = m;				/*				 * Do cool v4-related path MTU, for now,				 * only v6-in-v4 can handle it.				 */				if (icmplen >= ICMP_V6ADVLENMIN &&				    icmplen >= ICMP_V6ADVLEN(icp) &&				    icp->icmp_ip.ip_p == IPPROTO_IPV6) {					/*					 * ipv6_trans_mtu returns 1 if					 * the mbuf is still intact.					 */					if (ipv6_trans_mtu(&m0,icp->icmp_nextmtu,					    hlen + ICMP_V6ADVLEN(icp))) {						m = m0;						goto raw;					} else						return;				}			}#endif /* INET6 */			code = PRC_MSGSIZE;			break;						case ICMP_UNREACH_NET_UNKNOWN:		case ICMP_UNREACH_NET_PROHIB:		case ICMP_UNREACH_TOSNET:			code = PRC_UNREACH_NET;			break;		case ICMP_UNREACH_HOST_UNKNOWN:		case ICMP_UNREACH_ISOLATED:		case ICMP_UNREACH_HOST_PROHIB:		case ICMP_UNREACH_TOSHOST:		case ICMP_UNREACH_FILTER_PROHIB:		case ICMP_UNREACH_HOST_PRECEDENCE:		case ICMP_UNREACH_PRECEDENCE_CUTOFF:			code = PRC_UNREACH_HOST;			break;		default:			goto badcode;		}		goto deliver;	case ICMP_TIMXCEED:		if (code > 1)			goto badcode;		code += PRC_TIMXCEED_INTRANS;		goto deliver;	case ICMP_PARAMPROB:		if (code > 1)			goto badcode;		code = PRC_PARAMPROB;		goto deliver;	case ICMP_SOURCEQUENCH:		if (code)			goto badcode;		code = PRC_QUENCH;	deliver:		/*		 * Problem with datagram; advise higher level routines.		 */		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||		    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {			icmpstat.icps_badlen++;			goto freeit;		}		if (IN_MULTICAST(icp->icmp_ip.ip_dst.s_addr))			goto badcode;		NTOHS(icp->icmp_ip.ip_len);#ifdef INET6		/* Get more contiguous data for a v6 in v4 ICMP message. */		if (icp->icmp_ip.ip_p == IPPROTO_IPV6) {			if (icmplen < ICMP_V6ADVLENMIN || 			    icmplen < ICMP_V6ADVLEN(icp)) {				icmpstat.icps_badlen++;				goto freeit;			} else {				if (!(m = m_pullup(m, (ip->ip_hl << 2) +				    ICMP_V6ADVLEN(icp)))) {					icmpstat.icps_tooshort++;					return;				}				ip = mtod(m, struct ip *);				icp = (struct icmp *)(m->m_data + (ip->ip_hl << 2));			}		}#endif /* INET6 */#ifdef ICMPPRINTFS		if (icmpprintfs)			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);#endif		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;		/*		 * XXX if the packet contains [IPv4 AH TCP], we can't make a		 * notification to TCP layer.		 */		ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;		if (ctlfunc)			(*ctlfunc)(code, sintosa(&icmpsrc), &icp->icmp_ip);		break;	badcode:		icmpstat.icps_badcode++;		break;	case ICMP_ECHO:		if (!icmpbmcastecho &&		    (m->m_flags & (M_MCAST | M_BCAST)) != 0) {			icmpstat.icps_bmcastecho++;			break;		}		icp->icmp_type = ICMP_ECHOREPLY;		goto reflect;	case ICMP_TSTAMP:		if (!icmpbmcastecho &&		    (m->m_flags & (M_MCAST | M_BCAST)) != 0) {			icmpstat.icps_bmcastecho++;			break;		}		if (icmplen < ICMP_TSLEN) {			icmpstat.icps_badlen++;			break;		}		icp->icmp_type = ICMP_TSTAMPREPLY;		icp->icmp_rtime = iptime();		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */		goto reflect;			case ICMP_MASKREQ:		if (icmpmaskrepl == 0)			break;		/*		 * We are not able to respond with all ones broadcast		 * unless we receive it over a point-to-point interface.		 */		if (icmplen < ICMP_MASKLEN) {			icmpstat.icps_badlen++;			break;		}		if (ip->ip_dst.s_addr == INADDR_BROADCAST ||		    ip->ip_dst.s_addr == INADDR_ANY)			icmpdst.sin_addr = ip->ip_src;		else			icmpdst.sin_addr = ip->ip_dst;		ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst),		    m->m_pkthdr.rcvif));		if (ia == 0)			break;		icp->icmp_type = ICMP_MASKREPLY;		icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;		if (ip->ip_src.s_addr == 0) {			if (ia->ia_ifp->if_flags & IFF_BROADCAST)				ip->ip_src = ia->ia_broadaddr.sin_addr;			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)				ip->ip_src = ia->ia_dstaddr.sin_addr;		}reflect:		ip->ip_len += hlen;	/* since ip_input deducts this */		icmpstat.icps_reflect++;		icmpstat.icps_outhist[icp->icmp_type]++;		icmp_reflect(m);		return;	case ICMP_REDIRECT:		if (code > 3)			goto badcode;		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||		    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {			icmpstat.icps_badlen++;			break;		}		/*		 * Short circuit routing redirects to force		 * immediate change in the kernel's routing		 * tables.  The message is also handed to anyone		 * listening on a raw socket (e.g. the routing		 * daemon for use in updating its tables).		 */		icmpgw.sin_addr = ip->ip_src;		icmpdst.sin_addr = icp->icmp_gwaddr;#ifdef	ICMPPRINTFS		if (icmpprintfs) {			char buf[4 * sizeof "123"];			strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));			printf("redirect dst %s to %s\n",			    buf, inet_ntoa(icp->icmp_gwaddr));		}#endif		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;		rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst),		    (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,		    sintosa(&icmpgw), (struct rtentry **)0);		pfctlinput(PRC_REDIRECT_HOST, sintosa(&icmpsrc));#if 0 /*KAME IPSEC*/		key_sa_routechange((struct sockaddr *)&icmpsrc);#endif		break;	/*	 * No kernel processing for the following;	 * just fall through to send to raw listener.	 */	case ICMP_ECHOREPLY:	case ICMP_ROUTERADVERT:	case ICMP_ROUTERSOLICIT:	case ICMP_TSTAMPREPLY:	case ICMP_IREQREPLY:	case ICMP_MASKREPLY:	default:		break;	}raw:	rip_input(m, hlen, proto);	return;freeit:	m_freem(m);}