xref: /csrg-svn/sys/netinet/ip_icmp.c (revision 6583)
1 /*	ip_icmp.c	4.14	82/04/24	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/protosw.h"
7 #include "../h/socket.h"
8 #include "../h/clock.h"
9 #include "../net/in.h"
10 #include "../net/in_systm.h"
11 #include "../net/ip.h"
12 #include "../net/ip_icmp.h"
13 
14 /*
15  * ICMP routines: error generation, receive packet processing, and
16  * routines to turnaround packets back to the originator, and
17  * host table maintenance routines.
18  */
19 
20 /*
21  * Generate an error packet of type error
22  * in response to bad packet ip.
23  */
24 icmp_error(oip, type, code)
25 	struct ip *oip;
26 	int type, code;
27 {
28 	register unsigned oiplen = oip->ip_hl << 2;
29 	register struct icmp *icp;
30 	struct mbuf *m;
31 	struct ip *nip;
32 COUNT(ICMP_ERROR);
33 
34 	/*
35 	 * Make sure that the old IP packet had 8 bytes of data to return;
36 	 * if not, don't bother.  Also don't EVER error if the old
37 	 * packet protocol was ICMP.
38 	 */
39 	if (oip->ip_len - oiplen < 8 || oip->ip_p == IPPROTO_ICMP)
40 		goto free;
41 
42 	/*
43 	 * First, formulate icmp message
44 	 */
45 	m = m_get(M_DONTWAIT);
46 	if (m == 0)
47 		goto free;
48 	m->m_len = oiplen + 8 + ICMP_MINLEN;
49 	m->m_off = MMAXOFF - m->m_len;
50 	icp = mtod(m, struct icmp *);
51 	icp->icmp_type = type;
52 	icp->icmp_void = 0;
53 	if (type == ICMP_PARAMPROB) {
54 		icp->icmp_pptr = code;
55 		code = 0;
56 	}
57 	icp->icmp_code = code;
58 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
59 
60 	/*
61 	 * Now, copy old ip header in front of icmp
62 	 * message.  This allows us to reuse any source
63 	 * routing info present.
64 	 */
65 	m->m_off -= oiplen;
66 	nip = mtod(m, struct ip *);
67 	bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
68 	nip->ip_len = m->m_len + oiplen;
69 	nip->ip_p = IPPROTO_ICMP;
70 	/* icmp_send adds ip header to m_off and m_len, so we deduct here */
71 	m->m_off += oiplen;
72 	icmp_reflect(nip);
73 
74 free:
75 	m_freem(dtom(oip));
76 }
77 
78 static char icmpmap[] = {
79 	-1,		 -1,		-1,
80 	PRC_UNREACH_NET, PRC_QUENCH, 	PRC_REDIRECT_NET,
81 	-1,		 -1,		-1,
82 	-1,		 -1,		PRC_TIMXCEED_INTRANS,
83 	PRC_PARAMPROB,	 -1,		-1,
84 	-1,		 -1
85 };
86 
87 static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
88 static struct sockaddr_in icmpsrc = { AF_INET };
89 static struct sockaddr_in icmpdst = { AF_INET };
90 
91 /*
92  * Process a received ICMP message.
93  */
94 icmp_input(m)
95 	struct mbuf *m;
96 {
97 	register struct icmp *icp;
98 	register struct ip *ip = mtod(m, struct ip *);
99 	int icmplen = ip->ip_len, hlen = ip->ip_hl << 2, i;
100 	extern u_char ip_protox[];
101 COUNT(ICMP_INPUT);
102 
103 	/*
104 	 * Locate icmp structure in mbuf, and check
105 	 * that not corrupted and of at least minimum length.
106 	 */
107 	if (icmplen < ICMP_MINLEN)
108 		goto free;
109 	m->m_len -= hlen;
110 	m->m_off += hlen;
111 	/* need routine to make sure header is in this mbuf here */
112 	icp = mtod(m, struct icmp *);
113 	i = icp->icmp_cksum;
114 	icp->icmp_cksum = 0;
115 	if (i != in_cksum(m, icmplen)) {
116 		printf("icmp: cksum %x\n", i);
117 		goto free;
118 	}
119 
120 	/*
121 	 * Message type specific processing.
122 	 */
123 	switch (i = icp->icmp_type) {
124 
125 	case ICMP_UNREACH:
126 	case ICMP_TIMXCEED:
127 	case ICMP_PARAMPROB:
128 	case ICMP_REDIRECT:
129 	case ICMP_SOURCEQUENCH:
130 		/*
131 		 * Problem with previous datagram; advise
132 		 * higher level routines.
133 		 */
134 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
135 			goto free;
136 		(*protosw[ip_protox[ip->ip_p]].pr_ctlinput)
137 			(icmpmap[i] + icp->icmp_code, (caddr_t)icp);
138 		goto free;
139 
140 	case ICMP_ECHO:
141 		icp->icmp_type = ICMP_ECHOREPLY;
142 		goto reflect;
143 
144 	case ICMP_TSTAMP:
145 		if (icmplen < ICMP_TSLEN)
146 			goto free;
147 		icp->icmp_type = ICMP_TSTAMPREPLY;
148 		icp->icmp_rtime = iptime();
149 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
150 		goto reflect;
151 
152 	case ICMP_IREQ:
153 		/* fill in source address zero fields! */
154 		goto reflect;
155 
156 	case ICMP_ECHOREPLY:
157 	case ICMP_TSTAMPREPLY:
158 	case ICMP_IREQREPLY:
159 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
160 			goto free;
161 		icmpsrc.sin_addr = ip->ip_src;
162 		icmpdst.sin_addr = ip->ip_dst;
163 		raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
164 		  (struct sockaddr *)&icmpdst);
165 		goto free;
166 
167 	default:
168 		goto free;
169 	}
170 reflect:
171 	icmp_reflect(ip);
172 free:
173 	m_freem(dtom(ip));
174 }
175 
176 /*
177  * Reflect the ip packet back to the source
178  * TODO: rearrange ip source routing options.
179  */
180 icmp_reflect(ip)
181 	struct ip *ip;
182 {
183 	struct in_addr t;
184 COUNT(ICMP_REFLECT);
185 
186 	t = ip->ip_dst;
187 	ip->ip_dst = ip->ip_src;
188 	ip->ip_src = t;
189 	icmp_send(ip);
190 }
191 
192 int	generateicmpmsgs = 0;
193 
194 /*
195  * Send an icmp packet back to the ip level,
196  * after supplying a checksum.
197  */
198 icmp_send(ip)
199 	struct ip *ip;
200 {
201 	register int hlen = ip->ip_hl << 2;
202 	register struct icmp *icp;
203 	register struct mbuf *m = dtom(ip);
204 
205 COUNT(ICMP_SEND);
206 	if (!generateicmpmsgs)
207 		return;
208 	icp = mtod(m, struct icmp *);
209 	icp->icmp_cksum = 0;
210 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
211 	m->m_off -= hlen;
212 	m->m_len += hlen;
213 	(void) ip_output(m, 0, 0, 0);
214 }
215 
216 n_time
217 iptime()
218 {
219 	int s = spl6();
220 	u_long t;
221 
222 COUNT(IPTIME);
223 	t = (time % SECDAY) * 1000 + lbolt * hz;
224 	splx(s);
225 	return (htonl(t));
226 }
227