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