Add copyright
[unix-history] / usr / src / sys / netinet / ip_icmp.c
CommitLineData
8ae0e4b4
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)ip_icmp.c 6.12 (Berkeley) %G%
7 */
81a36a8d 8
20666ad3
JB
9#include "param.h"
10#include "systm.h"
11#include "mbuf.h"
12#include "protosw.h"
13#include "socket.h"
14#include "time.h"
15#include "kernel.h"
6e7edb25
BJ
16
17#include "../net/route.h"
c175a1bd 18#include "../net/if.h"
f4d55810 19
20666ad3
JB
20#include "in.h"
21#include "in_systm.h"
c175a1bd 22#include "in_var.h"
20666ad3
JB
23#include "ip.h"
24#include "ip_icmp.h"
25#include "icmp_var.h"
81a36a8d 26
a60889ab 27#ifdef ICMPPRINTFS
81a36a8d
BJ
28/*
29 * ICMP routines: error generation, receive packet processing, and
30 * routines to turnaround packets back to the originator, and
31 * host table maintenance routines.
32 */
67387c9c 33int icmpprintfs = 0;
a60889ab 34#endif
81a36a8d
BJ
35
36/*
72e4f44e
SL
37 * Generate an error packet of type error
38 * in response to bad packet ip.
81a36a8d
BJ
39 */
40icmp_error(oip, type, code)
41 struct ip *oip;
755d8841 42 int type, code;
81a36a8d 43{
72e4f44e
SL
44 register unsigned oiplen = oip->ip_hl << 2;
45 register struct icmp *icp;
81a36a8d
BJ
46 struct mbuf *m;
47 struct ip *nip;
48
a60889ab 49#ifdef ICMPPRINTFS
39674d5f
SL
50 if (icmpprintfs)
51 printf("icmp_error(%x, %d, %d)\n", oip, type, code);
a60889ab 52#endif
7b66c1fd 53 icmpstat.icps_error++;
81a36a8d
BJ
54 /*
55 * Make sure that the old IP packet had 8 bytes of data to return;
56 * if not, don't bother. Also don't EVER error if the old
57 * packet protocol was ICMP.
58 */
7b66c1fd
SL
59 if (oip->ip_len < 8) {
60 icmpstat.icps_oldshort++;
81a36a8d 61 goto free;
7b66c1fd
SL
62 }
63 if (oip->ip_p == IPPROTO_ICMP) {
64 icmpstat.icps_oldicmp++;
65 goto free;
66 }
81a36a8d
BJ
67
68 /*
72e4f44e 69 * First, formulate icmp message
81a36a8d 70 */
cce93e4b 71 m = m_get(M_DONTWAIT, MT_HEADER);
7b66c1fd 72 if (m == NULL)
81a36a8d 73 goto free;
72e4f44e
SL
74 m->m_len = oiplen + 8 + ICMP_MINLEN;
75 m->m_off = MMAXOFF - m->m_len;
76 icp = mtod(m, struct icmp *);
755d8841 77 if ((u_int)type > ICMP_IREQREPLY)
7b66c1fd
SL
78 panic("icmp_error");
79 icmpstat.icps_outhist[type]++;
81a36a8d 80 icp->icmp_type = type;
72e4f44e 81 icp->icmp_void = 0;
81a36a8d 82 if (type == ICMP_PARAMPROB) {
81a36a8d 83 icp->icmp_pptr = code;
72e4f44e
SL
84 code = 0;
85 }
86 icp->icmp_code = code;
d52566dd 87 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
39674d5f
SL
88 nip = &icp->icmp_ip;
89 nip->ip_len += oiplen;
39674d5f 90 nip->ip_len = htons((u_short)nip->ip_len);
81a36a8d
BJ
91
92 /*
72e4f44e
SL
93 * Now, copy old ip header in front of icmp
94 * message. This allows us to reuse any source
95 * routing info present.
81a36a8d 96 */
72e4f44e
SL
97 m->m_off -= oiplen;
98 nip = mtod(m, struct ip *);
99 bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
100 nip->ip_len = m->m_len + oiplen;
101 nip->ip_p = IPPROTO_ICMP;
102 /* icmp_send adds ip header to m_off and m_len, so we deduct here */
103 m->m_off += oiplen;
d52566dd 104 icmp_reflect(nip);
81a36a8d 105
def04636 106free:
81a36a8d
BJ
107 m_freem(dtom(oip));
108}
109
72e4f44e
SL
110static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
111static struct sockaddr_in icmpsrc = { AF_INET };
112static struct sockaddr_in icmpdst = { AF_INET };
113
81a36a8d 114/*
d52566dd 115 * Process a received ICMP message.
81a36a8d
BJ
116 */
117icmp_input(m)
118 struct mbuf *m;
119{
81a36a8d 120 register struct icmp *icp;
d52566dd 121 register struct ip *ip = mtod(m, struct ip *);
af8f6a21 122 int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
8046f415
MK
123 register int i;
124 int (*ctlfunc)(), code;
b454c3ea 125 extern u_char ip_protox[];
c175a1bd 126 extern struct in_addr in_makeaddr();
81a36a8d
BJ
127
128 /*
129 * Locate icmp structure in mbuf, and check
130 * that not corrupted and of at least minimum length.
131 */
a60889ab 132#ifdef ICMPPRINTFS
39674d5f
SL
133 if (icmpprintfs)
134 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
a60889ab 135#endif
4d75f980 136 if (icmplen < ICMP_MINLEN) {
7b66c1fd 137 icmpstat.icps_tooshort++;
72e4f44e 138 goto free;
7b66c1fd 139 }
8046f415
MK
140 /* THIS LENGTH CHECK STILL MISSES ANY IP OPTIONS IN ICMP_IP */
141 i = MIN(icmplen, ICMP_ADVLENMIN + hlen);
142 if ((m->m_off > MMAXOFF || m->m_len < i) &&
143 (m = m_pullup(m, i)) == 0) {
167351c2
MK
144 icmpstat.icps_tooshort++;
145 return;
146 }
8046f415 147 ip = mtod(m, struct ip *);
81a36a8d
BJ
148 m->m_len -= hlen;
149 m->m_off += hlen;
72e4f44e 150 icp = mtod(m, struct icmp *);
8046f415 151 if (in_cksum(m, icmplen)) {
7b66c1fd 152 icmpstat.icps_checksum++;
d52566dd 153 goto free;
72e4f44e 154 }
81a36a8d 155
a60889ab 156#ifdef ICMPPRINTFS
81a36a8d
BJ
157 /*
158 * Message type specific processing.
159 */
39674d5f
SL
160 if (icmpprintfs)
161 printf("icmp_input, type %d code %d\n", icp->icmp_type,
a60889ab
KM
162 icp->icmp_code);
163#endif
7b66c1fd
SL
164 if (icp->icmp_type > ICMP_IREQREPLY)
165 goto free;
166 icmpstat.icps_inhist[icp->icmp_type]++;
a60889ab 167 code = icp->icmp_code;
7b66c1fd 168 switch (icp->icmp_type) {
81a36a8d
BJ
169
170 case ICMP_UNREACH:
a60889ab
KM
171 if (code > 5)
172 goto badcode;
173 code += PRC_UNREACH_NET;
174 goto deliver;
175
81a36a8d 176 case ICMP_TIMXCEED:
a60889ab
KM
177 if (code > 1)
178 goto badcode;
179 code += PRC_TIMXCEED_INTRANS;
180 goto deliver;
181
81a36a8d 182 case ICMP_PARAMPROB:
a60889ab
KM
183 if (code)
184 goto badcode;
185 code = PRC_PARAMPROB;
186 goto deliver;
187
72e4f44e 188 case ICMP_SOURCEQUENCH:
a60889ab
KM
189 if (code)
190 goto badcode;
191 code = PRC_QUENCH;
192 deliver:
81a36a8d 193 /*
a60889ab 194 * Problem with datagram; advise higher level routines.
81a36a8d 195 */
a1edc12b 196 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
7b66c1fd
SL
197 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
198 icmpstat.icps_badlen++;
d52566dd 199 goto free;
7b66c1fd 200 }
a60889ab 201#ifdef ICMPPRINTFS
39674d5f
SL
202 if (icmpprintfs)
203 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
a60889ab 204#endif
59965020 205 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
a60889ab
KM
206 (*ctlfunc)(code, (caddr_t)icp);
207 goto free;
208
209 badcode:
210 icmpstat.icps_badcode++;
81a36a8d
BJ
211 goto free;
212
213 case ICMP_ECHO:
214 icp->icmp_type = ICMP_ECHOREPLY;
215 goto reflect;
216
217 case ICMP_TSTAMP:
7b66c1fd
SL
218 if (icmplen < ICMP_TSLEN) {
219 icmpstat.icps_badlen++;
d52566dd 220 goto free;
7b66c1fd 221 }
81a36a8d 222 icp->icmp_type = ICMP_TSTAMPREPLY;
2b4b57cd 223 icp->icmp_rtime = iptime();
81a36a8d
BJ
224 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
225 goto reflect;
226
227 case ICMP_IREQ:
c175a1bd
MK
228#define satosin(sa) ((struct sockaddr_in *)(sa))
229 if (in_netof(ip->ip_src) == 0)
230 ip->ip_src = in_makeaddr(
231 in_netof(satosin(&in_ifaddr->ia_addr)->sin_addr),
232 in_lnaof(ip->ip_src));
233 icp->icmp_type = ICMP_IREQREPLY;
81a36a8d
BJ
234 goto reflect;
235
a469458a 236 case ICMP_REDIRECT:
7b66c1fd
SL
237 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
238 icmpstat.icps_badlen++;
d52566dd 239 goto free;
7b66c1fd 240 }
a469458a
SL
241 /*
242 * Short circuit routing redirects to force
243 * immediate change in the kernel's routing
244 * tables. The message is also handed to anyone
245 * listening on a raw socket (e.g. the routing
fbc81152 246 * daemon for use in updating its tables).
a469458a 247 */
167351c2 248 icmpdst.sin_addr = icp->icmp_gwaddr;
fbc81152
MK
249 if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
250 icmpsrc.sin_addr =
c175a1bd 251 in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
fbc81152
MK
252 rtredirect((struct sockaddr *)&icmpsrc,
253 (struct sockaddr *)&icmpdst, RTF_GATEWAY);
0270e817 254 pfctlinput(PRC_REDIRECT_NET, (caddr_t)icp);
fbc81152
MK
255 } else {
256 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
257 rtredirect((struct sockaddr *)&icmpsrc,
258 (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST);
0270e817 259 pfctlinput(PRC_REDIRECT_HOST, (caddr_t)icp);
fbc81152 260 }
167351c2
MK
261 /* FALL THROUGH */
262
263 case ICMP_ECHOREPLY:
264 case ICMP_TSTAMPREPLY:
265 case ICMP_IREQREPLY:
72e4f44e
SL
266 icmpsrc.sin_addr = ip->ip_src;
267 icmpdst.sin_addr = ip->ip_dst;
268 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
269 (struct sockaddr *)&icmpdst);
fd15a680 270 return;
81a36a8d
BJ
271
272 default:
273 goto free;
274 }
275reflect:
b012ee63 276 ip->ip_len += hlen; /* since ip_input deducts this */
7b66c1fd 277 icmpstat.icps_reflect++;
06730e5a 278 icmpstat.icps_outhist[icp->icmp_type]++;
81a36a8d 279 icmp_reflect(ip);
af8f6a21 280 return;
81a36a8d
BJ
281free:
282 m_freem(dtom(ip));
283}
284
285/*
286 * Reflect the ip packet back to the source
72e4f44e 287 * TODO: rearrange ip source routing options.
81a36a8d
BJ
288 */
289icmp_reflect(ip)
290 struct ip *ip;
291{
c175a1bd
MK
292 register struct in_addr t;
293 register struct in_ifaddr *ia;
81a36a8d 294
72e4f44e 295 t = ip->ip_dst;
c175a1bd
MK
296 if (t.s_addr == INADDR_ANY)
297 t = IA_SIN(in_ifaddr)->sin_addr;
298 else for (ia = in_ifaddr; ia; ia = ia->ia_next)
299 if (t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr &&
300 (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
301 t = IA_SIN(ia)->sin_addr;
302 break;
303 }
72e4f44e
SL
304 ip->ip_dst = ip->ip_src;
305 ip->ip_src = t;
81a36a8d
BJ
306 icmp_send(ip);
307}
308
309/*
72e4f44e
SL
310 * Send an icmp packet back to the ip level,
311 * after supplying a checksum.
81a36a8d 312 */
cdad2eb1 313icmp_send(ip)
81a36a8d 314 struct ip *ip;
81a36a8d 315{
af8f6a21 316 register int hlen;
72e4f44e 317 register struct icmp *icp;
af8f6a21 318 register struct mbuf *m;
d52566dd 319
af8f6a21
SL
320 m = dtom(ip);
321 hlen = ip->ip_hl << 2;
72e4f44e
SL
322 icp = mtod(m, struct icmp *);
323 icp->icmp_cksum = 0;
324 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
325 m->m_off -= hlen;
326 m->m_len += hlen;
a60889ab 327#ifdef ICMPPRINTFS
39674d5f
SL
328 if (icmpprintfs)
329 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
a60889ab 330#endif
a1edc12b 331 (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0);
d52566dd
BJ
332}
333
cdad2eb1 334n_time
2b4b57cd 335iptime()
d52566dd 336{
cdad2eb1 337 int s = spl6();
2752c877 338 u_long t;
d52566dd 339
b2ac7f3b 340 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
cdad2eb1
BJ
341 splx(s);
342 return (htonl(t));
d52566dd 343}