Home | History | Annotate | Line # | Download | only in netinet
ip_icmp.c revision 1.1.1.2
      1      1.1      cgd /*
      2  1.1.1.2  thorpej  * Copyright (c) 1982, 1986, 1988, 1993
      3  1.1.1.2  thorpej  *	The Regents of the University of California.  All rights reserved.
      4      1.1      cgd  *
      5      1.1      cgd  * Redistribution and use in source and binary forms, with or without
      6      1.1      cgd  * modification, are permitted provided that the following conditions
      7      1.1      cgd  * are met:
      8      1.1      cgd  * 1. Redistributions of source code must retain the above copyright
      9      1.1      cgd  *    notice, this list of conditions and the following disclaimer.
     10      1.1      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11      1.1      cgd  *    notice, this list of conditions and the following disclaimer in the
     12      1.1      cgd  *    documentation and/or other materials provided with the distribution.
     13      1.1      cgd  * 3. All advertising materials mentioning features or use of this software
     14      1.1      cgd  *    must display the following acknowledgement:
     15      1.1      cgd  *	This product includes software developed by the University of
     16      1.1      cgd  *	California, Berkeley and its contributors.
     17      1.1      cgd  * 4. Neither the name of the University nor the names of its contributors
     18      1.1      cgd  *    may be used to endorse or promote products derived from this software
     19      1.1      cgd  *    without specific prior written permission.
     20      1.1      cgd  *
     21      1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22      1.1      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23      1.1      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24      1.1      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25      1.1      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26      1.1      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27      1.1      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28      1.1      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29      1.1      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30      1.1      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31      1.1      cgd  * SUCH DAMAGE.
     32      1.1      cgd  *
     33  1.1.1.2  thorpej  *	@(#)ip_icmp.c	8.2 (Berkeley) 1/4/94
     34      1.1      cgd  */
     35      1.1      cgd 
     36  1.1.1.2  thorpej #include <sys/param.h>
     37  1.1.1.2  thorpej #include <sys/systm.h>
     38  1.1.1.2  thorpej #include <sys/malloc.h>
     39  1.1.1.2  thorpej #include <sys/mbuf.h>
     40  1.1.1.2  thorpej #include <sys/protosw.h>
     41  1.1.1.2  thorpej #include <sys/socket.h>
     42  1.1.1.2  thorpej #include <sys/time.h>
     43  1.1.1.2  thorpej #include <sys/kernel.h>
     44  1.1.1.2  thorpej 
     45  1.1.1.2  thorpej #include <net/if.h>
     46  1.1.1.2  thorpej #include <net/route.h>
     47  1.1.1.2  thorpej 
     48  1.1.1.2  thorpej #include <netinet/in.h>
     49  1.1.1.2  thorpej #include <netinet/in_systm.h>
     50  1.1.1.2  thorpej #include <netinet/in_var.h>
     51  1.1.1.2  thorpej #include <netinet/ip.h>
     52  1.1.1.2  thorpej #include <netinet/ip_icmp.h>
     53  1.1.1.2  thorpej #include <netinet/icmp_var.h>
     54      1.1      cgd 
     55      1.1      cgd /*
     56      1.1      cgd  * ICMP routines: error generation, receive packet processing, and
     57      1.1      cgd  * routines to turnaround packets back to the originator, and
     58      1.1      cgd  * host table maintenance routines.
     59      1.1      cgd  */
     60  1.1.1.2  thorpej 
     61  1.1.1.2  thorpej int	icmpmaskrepl = 0;
     62      1.1      cgd #ifdef ICMPPRINTFS
     63      1.1      cgd int	icmpprintfs = 0;
     64      1.1      cgd #endif
     65      1.1      cgd 
     66      1.1      cgd extern	struct protosw inetsw[];
     67      1.1      cgd 
     68      1.1      cgd /*
     69      1.1      cgd  * Generate an error packet of type error
     70      1.1      cgd  * in response to bad packet ip.
     71      1.1      cgd  */
     72  1.1.1.2  thorpej void
     73  1.1.1.2  thorpej icmp_error(n, type, code, dest, destifp)
     74      1.1      cgd 	struct mbuf *n;
     75      1.1      cgd 	int type, code;
     76  1.1.1.2  thorpej 	n_long dest;
     77  1.1.1.2  thorpej 	struct ifnet *destifp;
     78      1.1      cgd {
     79      1.1      cgd 	register struct ip *oip = mtod(n, struct ip *), *nip;
     80      1.1      cgd 	register unsigned oiplen = oip->ip_hl << 2;
     81      1.1      cgd 	register struct icmp *icp;
     82      1.1      cgd 	register struct mbuf *m;
     83      1.1      cgd 	unsigned icmplen;
     84      1.1      cgd 
     85      1.1      cgd #ifdef ICMPPRINTFS
     86      1.1      cgd 	if (icmpprintfs)
     87      1.1      cgd 		printf("icmp_error(%x, %d, %d)\n", oip, type, code);
     88      1.1      cgd #endif
     89      1.1      cgd 	if (type != ICMP_REDIRECT)
     90      1.1      cgd 		icmpstat.icps_error++;
     91      1.1      cgd 	/*
     92      1.1      cgd 	 * Don't send error if not the first fragment of message.
     93      1.1      cgd 	 * Don't error if the old packet protocol was ICMP
     94      1.1      cgd 	 * error message, only known informational types.
     95      1.1      cgd 	 */
     96      1.1      cgd 	if (oip->ip_off &~ (IP_MF|IP_DF))
     97      1.1      cgd 		goto freeit;
     98      1.1      cgd 	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
     99      1.1      cgd 	  n->m_len >= oiplen + ICMP_MINLEN &&
    100      1.1      cgd 	  !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
    101      1.1      cgd 		icmpstat.icps_oldicmp++;
    102      1.1      cgd 		goto freeit;
    103      1.1      cgd 	}
    104  1.1.1.2  thorpej 	/* Don't send error in response to a multicast or broadcast packet */
    105  1.1.1.2  thorpej 	if (n->m_flags & (M_BCAST|M_MCAST))
    106  1.1.1.2  thorpej 		goto freeit;
    107      1.1      cgd 	/*
    108      1.1      cgd 	 * First, formulate icmp message
    109      1.1      cgd 	 */
    110      1.1      cgd 	m = m_gethdr(M_DONTWAIT, MT_HEADER);
    111      1.1      cgd 	if (m == NULL)
    112      1.1      cgd 		goto freeit;
    113      1.1      cgd 	icmplen = oiplen + min(8, oip->ip_len);
    114      1.1      cgd 	m->m_len = icmplen + ICMP_MINLEN;
    115      1.1      cgd 	MH_ALIGN(m, m->m_len);
    116      1.1      cgd 	icp = mtod(m, struct icmp *);
    117      1.1      cgd 	if ((u_int)type > ICMP_MAXTYPE)
    118      1.1      cgd 		panic("icmp_error");
    119      1.1      cgd 	icmpstat.icps_outhist[type]++;
    120      1.1      cgd 	icp->icmp_type = type;
    121      1.1      cgd 	if (type == ICMP_REDIRECT)
    122  1.1.1.2  thorpej 		icp->icmp_gwaddr.s_addr = dest;
    123  1.1.1.2  thorpej 	else {
    124      1.1      cgd 		icp->icmp_void = 0;
    125  1.1.1.2  thorpej 		/*
    126  1.1.1.2  thorpej 		 * The following assignments assume an overlay with the
    127  1.1.1.2  thorpej 		 * zeroed icmp_void field.
    128  1.1.1.2  thorpej 		 */
    129  1.1.1.2  thorpej 		if (type == ICMP_PARAMPROB) {
    130  1.1.1.2  thorpej 			icp->icmp_pptr = code;
    131  1.1.1.2  thorpej 			code = 0;
    132  1.1.1.2  thorpej 		} else if (type == ICMP_UNREACH &&
    133  1.1.1.2  thorpej 			code == ICMP_UNREACH_NEEDFRAG && destifp) {
    134  1.1.1.2  thorpej 			icp->icmp_nextmtu = htons(destifp->if_mtu);
    135  1.1.1.2  thorpej 		}
    136      1.1      cgd 	}
    137  1.1.1.2  thorpej 
    138      1.1      cgd 	icp->icmp_code = code;
    139      1.1      cgd 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
    140      1.1      cgd 	nip = &icp->icmp_ip;
    141      1.1      cgd 	nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
    142      1.1      cgd 
    143      1.1      cgd 	/*
    144      1.1      cgd 	 * Now, copy old ip header (without options)
    145      1.1      cgd 	 * in front of icmp message.
    146      1.1      cgd 	 */
    147      1.1      cgd 	if (m->m_data - sizeof(struct ip) < m->m_pktdat)
    148      1.1      cgd 		panic("icmp len");
    149      1.1      cgd 	m->m_data -= sizeof(struct ip);
    150      1.1      cgd 	m->m_len += sizeof(struct ip);
    151      1.1      cgd 	m->m_pkthdr.len = m->m_len;
    152      1.1      cgd 	m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
    153      1.1      cgd 	nip = mtod(m, struct ip *);
    154  1.1.1.2  thorpej 	bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
    155      1.1      cgd 	nip->ip_len = m->m_len;
    156      1.1      cgd 	nip->ip_hl = sizeof(struct ip) >> 2;
    157      1.1      cgd 	nip->ip_p = IPPROTO_ICMP;
    158  1.1.1.2  thorpej 	nip->ip_tos = 0;
    159      1.1      cgd 	icmp_reflect(m);
    160      1.1      cgd 
    161      1.1      cgd freeit:
    162      1.1      cgd 	m_freem(n);
    163      1.1      cgd }
    164      1.1      cgd 
    165      1.1      cgd static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
    166      1.1      cgd static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
    167      1.1      cgd static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
    168      1.1      cgd struct sockaddr_in icmpmask = { 8, 0 };
    169      1.1      cgd 
    170      1.1      cgd /*
    171      1.1      cgd  * Process a received ICMP message.
    172      1.1      cgd  */
    173  1.1.1.2  thorpej void
    174      1.1      cgd icmp_input(m, hlen)
    175      1.1      cgd 	register struct mbuf *m;
    176      1.1      cgd 	int hlen;
    177      1.1      cgd {
    178      1.1      cgd 	register struct icmp *icp;
    179      1.1      cgd 	register struct ip *ip = mtod(m, struct ip *);
    180      1.1      cgd 	int icmplen = ip->ip_len;
    181      1.1      cgd 	register int i;
    182      1.1      cgd 	struct in_ifaddr *ia;
    183  1.1.1.2  thorpej 	void (*ctlfunc) __P((int, struct sockaddr *, struct ip *));
    184  1.1.1.2  thorpej 	int code;
    185      1.1      cgd 	extern u_char ip_protox[];
    186      1.1      cgd 
    187      1.1      cgd 	/*
    188      1.1      cgd 	 * Locate icmp structure in mbuf, and check
    189      1.1      cgd 	 * that not corrupted and of at least minimum length.
    190      1.1      cgd 	 */
    191      1.1      cgd #ifdef ICMPPRINTFS
    192      1.1      cgd 	if (icmpprintfs)
    193  1.1.1.2  thorpej 		printf("icmp_input from %x to %x, len %d\n",
    194  1.1.1.2  thorpej 			ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr),
    195  1.1.1.2  thorpej 			icmplen);
    196      1.1      cgd #endif
    197      1.1      cgd 	if (icmplen < ICMP_MINLEN) {
    198      1.1      cgd 		icmpstat.icps_tooshort++;
    199      1.1      cgd 		goto freeit;
    200      1.1      cgd 	}
    201  1.1.1.2  thorpej 	i = hlen + min(icmplen, ICMP_ADVLENMIN);
    202  1.1.1.2  thorpej 	if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
    203      1.1      cgd 		icmpstat.icps_tooshort++;
    204      1.1      cgd 		return;
    205      1.1      cgd 	}
    206  1.1.1.2  thorpej 	ip = mtod(m, struct ip *);
    207      1.1      cgd 	m->m_len -= hlen;
    208      1.1      cgd 	m->m_data += hlen;
    209      1.1      cgd 	icp = mtod(m, struct icmp *);
    210      1.1      cgd 	if (in_cksum(m, icmplen)) {
    211      1.1      cgd 		icmpstat.icps_checksum++;
    212      1.1      cgd 		goto freeit;
    213      1.1      cgd 	}
    214      1.1      cgd 	m->m_len += hlen;
    215      1.1      cgd 	m->m_data -= hlen;
    216      1.1      cgd 
    217      1.1      cgd #ifdef ICMPPRINTFS
    218      1.1      cgd 	/*
    219      1.1      cgd 	 * Message type specific processing.
    220      1.1      cgd 	 */
    221      1.1      cgd 	if (icmpprintfs)
    222      1.1      cgd 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
    223      1.1      cgd 		    icp->icmp_code);
    224      1.1      cgd #endif
    225      1.1      cgd 	if (icp->icmp_type > ICMP_MAXTYPE)
    226      1.1      cgd 		goto raw;
    227      1.1      cgd 	icmpstat.icps_inhist[icp->icmp_type]++;
    228      1.1      cgd 	code = icp->icmp_code;
    229      1.1      cgd 	switch (icp->icmp_type) {
    230      1.1      cgd 
    231      1.1      cgd 	case ICMP_UNREACH:
    232  1.1.1.2  thorpej 		switch (code) {
    233  1.1.1.2  thorpej 			case ICMP_UNREACH_NET:
    234  1.1.1.2  thorpej 			case ICMP_UNREACH_HOST:
    235  1.1.1.2  thorpej 			case ICMP_UNREACH_PROTOCOL:
    236  1.1.1.2  thorpej 			case ICMP_UNREACH_PORT:
    237  1.1.1.2  thorpej 			case ICMP_UNREACH_SRCFAIL:
    238  1.1.1.2  thorpej 				code += PRC_UNREACH_NET;
    239  1.1.1.2  thorpej 				break;
    240  1.1.1.2  thorpej 
    241  1.1.1.2  thorpej 			case ICMP_UNREACH_NEEDFRAG:
    242  1.1.1.2  thorpej 				code = PRC_MSGSIZE;
    243  1.1.1.2  thorpej 				break;
    244  1.1.1.2  thorpej 
    245  1.1.1.2  thorpej 			case ICMP_UNREACH_NET_UNKNOWN:
    246  1.1.1.2  thorpej 			case ICMP_UNREACH_NET_PROHIB:
    247  1.1.1.2  thorpej 			case ICMP_UNREACH_TOSNET:
    248  1.1.1.2  thorpej 				code = PRC_UNREACH_NET;
    249  1.1.1.2  thorpej 				break;
    250  1.1.1.2  thorpej 
    251  1.1.1.2  thorpej 			case ICMP_UNREACH_HOST_UNKNOWN:
    252  1.1.1.2  thorpej 			case ICMP_UNREACH_ISOLATED:
    253  1.1.1.2  thorpej 			case ICMP_UNREACH_HOST_PROHIB:
    254  1.1.1.2  thorpej 			case ICMP_UNREACH_TOSHOST:
    255  1.1.1.2  thorpej 				code = PRC_UNREACH_HOST;
    256  1.1.1.2  thorpej 				break;
    257  1.1.1.2  thorpej 
    258  1.1.1.2  thorpej 			default:
    259  1.1.1.2  thorpej 				goto badcode;
    260  1.1.1.2  thorpej 		}
    261      1.1      cgd 		goto deliver;
    262      1.1      cgd 
    263      1.1      cgd 	case ICMP_TIMXCEED:
    264      1.1      cgd 		if (code > 1)
    265      1.1      cgd 			goto badcode;
    266      1.1      cgd 		code += PRC_TIMXCEED_INTRANS;
    267      1.1      cgd 		goto deliver;
    268      1.1      cgd 
    269      1.1      cgd 	case ICMP_PARAMPROB:
    270  1.1.1.2  thorpej 		if (code > 1)
    271      1.1      cgd 			goto badcode;
    272      1.1      cgd 		code = PRC_PARAMPROB;
    273      1.1      cgd 		goto deliver;
    274      1.1      cgd 
    275      1.1      cgd 	case ICMP_SOURCEQUENCH:
    276      1.1      cgd 		if (code)
    277      1.1      cgd 			goto badcode;
    278      1.1      cgd 		code = PRC_QUENCH;
    279      1.1      cgd 	deliver:
    280      1.1      cgd 		/*
    281      1.1      cgd 		 * Problem with datagram; advise higher level routines.
    282      1.1      cgd 		 */
    283      1.1      cgd 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
    284      1.1      cgd 		    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
    285      1.1      cgd 			icmpstat.icps_badlen++;
    286      1.1      cgd 			goto freeit;
    287      1.1      cgd 		}
    288      1.1      cgd 		NTOHS(icp->icmp_ip.ip_len);
    289      1.1      cgd #ifdef ICMPPRINTFS
    290      1.1      cgd 		if (icmpprintfs)
    291      1.1      cgd 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
    292      1.1      cgd #endif
    293      1.1      cgd 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
    294      1.1      cgd 		if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
    295      1.1      cgd 			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
    296  1.1.1.2  thorpej 			    &icp->icmp_ip);
    297      1.1      cgd 		break;
    298      1.1      cgd 
    299      1.1      cgd 	badcode:
    300      1.1      cgd 		icmpstat.icps_badcode++;
    301      1.1      cgd 		break;
    302      1.1      cgd 
    303      1.1      cgd 	case ICMP_ECHO:
    304      1.1      cgd 		icp->icmp_type = ICMP_ECHOREPLY;
    305      1.1      cgd 		goto reflect;
    306      1.1      cgd 
    307      1.1      cgd 	case ICMP_TSTAMP:
    308      1.1      cgd 		if (icmplen < ICMP_TSLEN) {
    309      1.1      cgd 			icmpstat.icps_badlen++;
    310      1.1      cgd 			break;
    311      1.1      cgd 		}
    312      1.1      cgd 		icp->icmp_type = ICMP_TSTAMPREPLY;
    313      1.1      cgd 		icp->icmp_rtime = iptime();
    314      1.1      cgd 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
    315      1.1      cgd 		goto reflect;
    316      1.1      cgd 
    317  1.1.1.2  thorpej 	case ICMP_MASKREQ:
    318      1.1      cgd #define	satosin(sa)	((struct sockaddr_in *)(sa))
    319  1.1.1.2  thorpej 		if (icmpmaskrepl == 0)
    320  1.1.1.2  thorpej 			break;
    321  1.1.1.2  thorpej 		/*
    322  1.1.1.2  thorpej 		 * We are not able to respond with all ones broadcast
    323  1.1.1.2  thorpej 		 * unless we receive it over a point-to-point interface.
    324  1.1.1.2  thorpej 		 */
    325  1.1.1.2  thorpej 		if (icmplen < ICMP_MASKLEN)
    326  1.1.1.2  thorpej 			break;
    327  1.1.1.2  thorpej 		switch (ip->ip_dst.s_addr) {
    328      1.1      cgd 
    329  1.1.1.2  thorpej 		case INADDR_BROADCAST:
    330  1.1.1.2  thorpej 		case INADDR_ANY:
    331  1.1.1.2  thorpej 			icmpdst.sin_addr = ip->ip_src;
    332  1.1.1.2  thorpej 			break;
    333  1.1.1.2  thorpej 
    334  1.1.1.2  thorpej 		default:
    335  1.1.1.2  thorpej 			icmpdst.sin_addr = ip->ip_dst;
    336  1.1.1.2  thorpej 		}
    337  1.1.1.2  thorpej 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
    338  1.1.1.2  thorpej 			    (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
    339  1.1.1.2  thorpej 		if (ia == 0)
    340      1.1      cgd 			break;
    341      1.1      cgd 		icp->icmp_type = ICMP_MASKREPLY;
    342      1.1      cgd 		icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
    343      1.1      cgd 		if (ip->ip_src.s_addr == 0) {
    344      1.1      cgd 			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
    345      1.1      cgd 			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
    346      1.1      cgd 			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
    347      1.1      cgd 			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
    348      1.1      cgd 		}
    349      1.1      cgd reflect:
    350      1.1      cgd 		ip->ip_len += hlen;	/* since ip_input deducts this */
    351      1.1      cgd 		icmpstat.icps_reflect++;
    352      1.1      cgd 		icmpstat.icps_outhist[icp->icmp_type]++;
    353      1.1      cgd 		icmp_reflect(m);
    354      1.1      cgd 		return;
    355      1.1      cgd 
    356      1.1      cgd 	case ICMP_REDIRECT:
    357  1.1.1.2  thorpej 		if (code > 3)
    358  1.1.1.2  thorpej 			goto badcode;
    359  1.1.1.2  thorpej 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
    360  1.1.1.2  thorpej 		    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
    361      1.1      cgd 			icmpstat.icps_badlen++;
    362      1.1      cgd 			break;
    363      1.1      cgd 		}
    364      1.1      cgd 		/*
    365      1.1      cgd 		 * Short circuit routing redirects to force
    366      1.1      cgd 		 * immediate change in the kernel's routing
    367      1.1      cgd 		 * tables.  The message is also handed to anyone
    368      1.1      cgd 		 * listening on a raw socket (e.g. the routing
    369      1.1      cgd 		 * daemon for use in updating its tables).
    370      1.1      cgd 		 */
    371      1.1      cgd 		icmpgw.sin_addr = ip->ip_src;
    372      1.1      cgd 		icmpdst.sin_addr = icp->icmp_gwaddr;
    373      1.1      cgd #ifdef	ICMPPRINTFS
    374      1.1      cgd 		if (icmpprintfs)
    375      1.1      cgd 			printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
    376      1.1      cgd 				icp->icmp_gwaddr);
    377      1.1      cgd #endif
    378  1.1.1.2  thorpej 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
    379  1.1.1.2  thorpej 		rtredirect((struct sockaddr *)&icmpsrc,
    380  1.1.1.2  thorpej 		  (struct sockaddr *)&icmpdst,
    381  1.1.1.2  thorpej 		  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
    382  1.1.1.2  thorpej 		  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
    383  1.1.1.2  thorpej 		pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
    384      1.1      cgd 		break;
    385      1.1      cgd 
    386      1.1      cgd 	/*
    387      1.1      cgd 	 * No kernel processing for the following;
    388      1.1      cgd 	 * just fall through to send to raw listener.
    389      1.1      cgd 	 */
    390      1.1      cgd 	case ICMP_ECHOREPLY:
    391  1.1.1.2  thorpej 	case ICMP_ROUTERADVERT:
    392  1.1.1.2  thorpej 	case ICMP_ROUTERSOLICIT:
    393      1.1      cgd 	case ICMP_TSTAMPREPLY:
    394      1.1      cgd 	case ICMP_IREQREPLY:
    395      1.1      cgd 	case ICMP_MASKREPLY:
    396      1.1      cgd 	default:
    397      1.1      cgd 		break;
    398      1.1      cgd 	}
    399      1.1      cgd 
    400      1.1      cgd raw:
    401  1.1.1.2  thorpej 	rip_input(m);
    402      1.1      cgd 	return;
    403      1.1      cgd 
    404      1.1      cgd freeit:
    405      1.1      cgd 	m_freem(m);
    406      1.1      cgd }
    407      1.1      cgd 
    408      1.1      cgd /*
    409      1.1      cgd  * Reflect the ip packet back to the source
    410      1.1      cgd  */
    411  1.1.1.2  thorpej void
    412      1.1      cgd icmp_reflect(m)
    413      1.1      cgd 	struct mbuf *m;
    414      1.1      cgd {
    415      1.1      cgd 	register struct ip *ip = mtod(m, struct ip *);
    416      1.1      cgd 	register struct in_ifaddr *ia;
    417      1.1      cgd 	struct in_addr t;
    418      1.1      cgd 	struct mbuf *opts = 0, *ip_srcroute();
    419      1.1      cgd 	int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
    420      1.1      cgd 
    421  1.1.1.2  thorpej 	if (!in_canforward(ip->ip_src) &&
    422  1.1.1.2  thorpej 	    ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
    423  1.1.1.2  thorpej 	     (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
    424  1.1.1.2  thorpej 		m_freem(m);	/* Bad return address */
    425  1.1.1.2  thorpej 		goto done;	/* Ip_output() will check for broadcast */
    426  1.1.1.2  thorpej 	}
    427      1.1      cgd 	t = ip->ip_dst;
    428      1.1      cgd 	ip->ip_dst = ip->ip_src;
    429      1.1      cgd 	/*
    430      1.1      cgd 	 * If the incoming packet was addressed directly to us,
    431      1.1      cgd 	 * use dst as the src for the reply.  Otherwise (broadcast
    432      1.1      cgd 	 * or anonymous), use the address which corresponds
    433      1.1      cgd 	 * to the incoming interface.
    434      1.1      cgd 	 */
    435      1.1      cgd 	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
    436      1.1      cgd 		if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
    437      1.1      cgd 			break;
    438      1.1      cgd 		if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
    439      1.1      cgd 		    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
    440      1.1      cgd 			break;
    441      1.1      cgd 	}
    442  1.1.1.2  thorpej 	icmpdst.sin_addr = t;
    443      1.1      cgd 	if (ia == (struct in_ifaddr *)0)
    444  1.1.1.2  thorpej 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
    445  1.1.1.2  thorpej 			(struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
    446  1.1.1.2  thorpej 	/*
    447  1.1.1.2  thorpej 	 * The following happens if the packet was not addressed to us,
    448  1.1.1.2  thorpej 	 * and was received on an interface with no IP address.
    449  1.1.1.2  thorpej 	 */
    450      1.1      cgd 	if (ia == (struct in_ifaddr *)0)
    451      1.1      cgd 		ia = in_ifaddr;
    452      1.1      cgd 	t = IA_SIN(ia)->sin_addr;
    453      1.1      cgd 	ip->ip_src = t;
    454      1.1      cgd 	ip->ip_ttl = MAXTTL;
    455      1.1      cgd 
    456      1.1      cgd 	if (optlen > 0) {
    457      1.1      cgd 		register u_char *cp;
    458      1.1      cgd 		int opt, cnt;
    459      1.1      cgd 		u_int len;
    460      1.1      cgd 
    461      1.1      cgd 		/*
    462      1.1      cgd 		 * Retrieve any source routing from the incoming packet;
    463      1.1      cgd 		 * add on any record-route or timestamp options.
    464      1.1      cgd 		 */
    465      1.1      cgd 		cp = (u_char *) (ip + 1);
    466      1.1      cgd 		if ((opts = ip_srcroute()) == 0 &&
    467      1.1      cgd 		    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
    468      1.1      cgd 			opts->m_len = sizeof(struct in_addr);
    469      1.1      cgd 			mtod(opts, struct in_addr *)->s_addr = 0;
    470      1.1      cgd 		}
    471      1.1      cgd 		if (opts) {
    472      1.1      cgd #ifdef ICMPPRINTFS
    473      1.1      cgd 		    if (icmpprintfs)
    474      1.1      cgd 			    printf("icmp_reflect optlen %d rt %d => ",
    475      1.1      cgd 				optlen, opts->m_len);
    476      1.1      cgd #endif
    477      1.1      cgd 		    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
    478      1.1      cgd 			    opt = cp[IPOPT_OPTVAL];
    479      1.1      cgd 			    if (opt == IPOPT_EOL)
    480      1.1      cgd 				    break;
    481      1.1      cgd 			    if (opt == IPOPT_NOP)
    482      1.1      cgd 				    len = 1;
    483      1.1      cgd 			    else {
    484      1.1      cgd 				    len = cp[IPOPT_OLEN];
    485      1.1      cgd 				    if (len <= 0 || len > cnt)
    486      1.1      cgd 					    break;
    487      1.1      cgd 			    }
    488      1.1      cgd 			    /*
    489  1.1.1.2  thorpej 			     * Should check for overflow, but it "can't happen"
    490      1.1      cgd 			     */
    491  1.1.1.2  thorpej 			    if (opt == IPOPT_RR || opt == IPOPT_TS ||
    492  1.1.1.2  thorpej 				opt == IPOPT_SECURITY) {
    493      1.1      cgd 				    bcopy((caddr_t)cp,
    494      1.1      cgd 					mtod(opts, caddr_t) + opts->m_len, len);
    495      1.1      cgd 				    opts->m_len += len;
    496      1.1      cgd 			    }
    497      1.1      cgd 		    }
    498  1.1.1.2  thorpej 		    /* Terminate & pad, if necessary */
    499  1.1.1.2  thorpej 		    if (cnt = opts->m_len % 4) {
    500  1.1.1.2  thorpej 			    for (; cnt < 4; cnt++) {
    501  1.1.1.2  thorpej 				    *(mtod(opts, caddr_t) + opts->m_len) =
    502  1.1.1.2  thorpej 					IPOPT_EOL;
    503  1.1.1.2  thorpej 				    opts->m_len++;
    504  1.1.1.2  thorpej 			    }
    505      1.1      cgd 		    }
    506      1.1      cgd #ifdef ICMPPRINTFS
    507      1.1      cgd 		    if (icmpprintfs)
    508      1.1      cgd 			    printf("%d\n", opts->m_len);
    509      1.1      cgd #endif
    510      1.1      cgd 		}
    511      1.1      cgd 		/*
    512      1.1      cgd 		 * Now strip out original options by copying rest of first
    513      1.1      cgd 		 * mbuf's data back, and adjust the IP length.
    514      1.1      cgd 		 */
    515      1.1      cgd 		ip->ip_len -= optlen;
    516      1.1      cgd 		ip->ip_hl = sizeof(struct ip) >> 2;
    517      1.1      cgd 		m->m_len -= optlen;
    518      1.1      cgd 		if (m->m_flags & M_PKTHDR)
    519      1.1      cgd 			m->m_pkthdr.len -= optlen;
    520      1.1      cgd 		optlen += sizeof(struct ip);
    521      1.1      cgd 		bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
    522      1.1      cgd 			 (unsigned)(m->m_len - sizeof(struct ip)));
    523      1.1      cgd 	}
    524  1.1.1.2  thorpej 	m->m_flags &= ~(M_BCAST|M_MCAST);
    525      1.1      cgd 	icmp_send(m, opts);
    526  1.1.1.2  thorpej done:
    527      1.1      cgd 	if (opts)
    528      1.1      cgd 		(void)m_free(opts);
    529      1.1      cgd }
    530      1.1      cgd 
    531      1.1      cgd /*
    532      1.1      cgd  * Send an icmp packet back to the ip level,
    533      1.1      cgd  * after supplying a checksum.
    534      1.1      cgd  */
    535  1.1.1.2  thorpej void
    536      1.1      cgd icmp_send(m, opts)
    537      1.1      cgd 	register struct mbuf *m;
    538      1.1      cgd 	struct mbuf *opts;
    539      1.1      cgd {
    540      1.1      cgd 	register struct ip *ip = mtod(m, struct ip *);
    541      1.1      cgd 	register int hlen;
    542      1.1      cgd 	register struct icmp *icp;
    543      1.1      cgd 
    544      1.1      cgd 	hlen = ip->ip_hl << 2;
    545      1.1      cgd 	m->m_data += hlen;
    546      1.1      cgd 	m->m_len -= hlen;
    547      1.1      cgd 	icp = mtod(m, struct icmp *);
    548      1.1      cgd 	icp->icmp_cksum = 0;
    549      1.1      cgd 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
    550      1.1      cgd 	m->m_data -= hlen;
    551      1.1      cgd 	m->m_len += hlen;
    552      1.1      cgd #ifdef ICMPPRINTFS
    553      1.1      cgd 	if (icmpprintfs)
    554      1.1      cgd 		printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
    555      1.1      cgd #endif
    556  1.1.1.2  thorpej 	(void) ip_output(m, opts, NULL, 0, NULL);
    557      1.1      cgd }
    558      1.1      cgd 
    559      1.1      cgd n_time
    560      1.1      cgd iptime()
    561      1.1      cgd {
    562      1.1      cgd 	struct timeval atv;
    563      1.1      cgd 	u_long t;
    564      1.1      cgd 
    565      1.1      cgd 	microtime(&atv);
    566      1.1      cgd 	t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
    567      1.1      cgd 	return (htonl(t));
    568  1.1.1.2  thorpej }
    569  1.1.1.2  thorpej 
    570  1.1.1.2  thorpej int
    571  1.1.1.2  thorpej icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
    572  1.1.1.2  thorpej 	int *name;
    573  1.1.1.2  thorpej 	u_int namelen;
    574  1.1.1.2  thorpej 	void *oldp;
    575  1.1.1.2  thorpej 	size_t *oldlenp;
    576  1.1.1.2  thorpej 	void *newp;
    577  1.1.1.2  thorpej 	size_t newlen;
    578  1.1.1.2  thorpej {
    579  1.1.1.2  thorpej 
    580  1.1.1.2  thorpej 	/* All sysctl names at this level are terminal. */
    581  1.1.1.2  thorpej 	if (namelen != 1)
    582  1.1.1.2  thorpej 		return (ENOTDIR);
    583  1.1.1.2  thorpej 
    584  1.1.1.2  thorpej 	switch (name[0]) {
    585  1.1.1.2  thorpej 	case ICMPCTL_MASKREPL:
    586  1.1.1.2  thorpej 		return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl));
    587  1.1.1.2  thorpej 	default:
    588  1.1.1.2  thorpej 		return (ENOPROTOOPT);
    589  1.1.1.2  thorpej 	}
    590  1.1.1.2  thorpej 	/* NOTREACHED */
    591      1.1      cgd }
    592