save data in static area because dbmclose does a free().
[unix-history] / usr / src / sys / netinet / ip_icmp.c
CommitLineData
373c0574 1/* ip_icmp.c 6.3 84/01/11 */
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;
7b66c1fd 115 int (*ctlfunc)(), code, i;
b454c3ea 116 extern u_char ip_protox[];
81a36a8d
BJ
117
118 /*
119 * Locate icmp structure in mbuf, and check
120 * that not corrupted and of at least minimum length.
121 */
a60889ab 122#ifdef ICMPPRINTFS
39674d5f
SL
123 if (icmpprintfs)
124 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
a60889ab 125#endif
167351c2 126 if (icmplen < sizeof(struct ip) + ICMP_MINLEN) {
7b66c1fd 127 icmpstat.icps_tooshort++;
72e4f44e 128 goto free;
7b66c1fd 129 }
167351c2
MK
130 if ((m->m_off > MMAXOFF || m->m_len < icmplen)
131 && (m = m_pullup(m, icmplen)) == 0) {
132 icmpstat.icps_tooshort++;
133 return;
134 }
81a36a8d
BJ
135 m->m_len -= hlen;
136 m->m_off += hlen;
72e4f44e 137 icp = mtod(m, struct icmp *);
81a36a8d
BJ
138 i = icp->icmp_cksum;
139 icp->icmp_cksum = 0;
72e4f44e 140 if (i != in_cksum(m, icmplen)) {
7b66c1fd 141 icmpstat.icps_checksum++;
d52566dd 142 goto free;
72e4f44e 143 }
81a36a8d 144
a60889ab 145#ifdef ICMPPRINTFS
81a36a8d
BJ
146 /*
147 * Message type specific processing.
148 */
39674d5f
SL
149 if (icmpprintfs)
150 printf("icmp_input, type %d code %d\n", icp->icmp_type,
a60889ab
KM
151 icp->icmp_code);
152#endif
7b66c1fd
SL
153 if (icp->icmp_type > ICMP_IREQREPLY)
154 goto free;
155 icmpstat.icps_inhist[icp->icmp_type]++;
a60889ab 156 code = icp->icmp_code;
7b66c1fd 157 switch (icp->icmp_type) {
81a36a8d
BJ
158
159 case ICMP_UNREACH:
a60889ab
KM
160 if (code > 5)
161 goto badcode;
162 code += PRC_UNREACH_NET;
163 goto deliver;
164
81a36a8d 165 case ICMP_TIMXCEED:
a60889ab
KM
166 if (code > 1)
167 goto badcode;
168 code += PRC_TIMXCEED_INTRANS;
169 goto deliver;
170
81a36a8d 171 case ICMP_PARAMPROB:
a60889ab
KM
172 if (code)
173 goto badcode;
174 code = PRC_PARAMPROB;
175 goto deliver;
176
72e4f44e 177 case ICMP_SOURCEQUENCH:
a60889ab
KM
178 if (code)
179 goto badcode;
180 code = PRC_QUENCH;
181 deliver:
81a36a8d 182 /*
a60889ab 183 * Problem with datagram; advise higher level routines.
81a36a8d 184 */
a1edc12b 185 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
7b66c1fd
SL
186 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
187 icmpstat.icps_badlen++;
d52566dd 188 goto free;
7b66c1fd 189 }
a60889ab 190#ifdef ICMPPRINTFS
39674d5f
SL
191 if (icmpprintfs)
192 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
a60889ab 193#endif
59965020 194 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
a60889ab
KM
195 (*ctlfunc)(code, (caddr_t)icp);
196 goto free;
197
198 badcode:
199 icmpstat.icps_badcode++;
81a36a8d
BJ
200 goto free;
201
202 case ICMP_ECHO:
203 icp->icmp_type = ICMP_ECHOREPLY;
204 goto reflect;
205
206 case ICMP_TSTAMP:
7b66c1fd
SL
207 if (icmplen < ICMP_TSLEN) {
208 icmpstat.icps_badlen++;
d52566dd 209 goto free;
7b66c1fd 210 }
81a36a8d 211 icp->icmp_type = ICMP_TSTAMPREPLY;
2b4b57cd 212 icp->icmp_rtime = iptime();
81a36a8d
BJ
213 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
214 goto reflect;
215
216 case ICMP_IREQ:
a60889ab 217#ifdef notdef
81a36a8d
BJ
218 /* fill in source address zero fields! */
219 goto reflect;
a60889ab
KM
220#else
221 goto free; /* not yet implemented: ignore */
222#endif
81a36a8d 223
a469458a 224 case ICMP_REDIRECT:
7b66c1fd
SL
225 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
226 icmpstat.icps_badlen++;
d52566dd 227 goto free;
7b66c1fd 228 }
a469458a
SL
229 /*
230 * Short circuit routing redirects to force
231 * immediate change in the kernel's routing
232 * tables. The message is also handed to anyone
233 * listening on a raw socket (e.g. the routing
234 * daemon for use in updating it's tables).
235 */
167351c2
MK
236 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
237 icmpdst.sin_addr = icp->icmp_gwaddr;
238 rtredirect((struct sockaddr *)&icmpsrc,
239 (struct sockaddr *)&icmpdst,
240 (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) ?
241 RTF_GATEWAY : (RTF_GATEWAY | RTF_HOST));
242 /* FALL THROUGH */
243
244 case ICMP_ECHOREPLY:
245 case ICMP_TSTAMPREPLY:
246 case ICMP_IREQREPLY:
72e4f44e
SL
247 icmpsrc.sin_addr = ip->ip_src;
248 icmpdst.sin_addr = ip->ip_dst;
249 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
250 (struct sockaddr *)&icmpdst);
fd15a680 251 return;
81a36a8d
BJ
252
253 default:
254 goto free;
255 }
256reflect:
b012ee63 257 ip->ip_len += hlen; /* since ip_input deducts this */
7b66c1fd 258 icmpstat.icps_reflect++;
81a36a8d 259 icmp_reflect(ip);
af8f6a21 260 return;
81a36a8d
BJ
261free:
262 m_freem(dtom(ip));
263}
264
265/*
266 * Reflect the ip packet back to the source
72e4f44e 267 * TODO: rearrange ip source routing options.
81a36a8d
BJ
268 */
269icmp_reflect(ip)
270 struct ip *ip;
271{
2b4b57cd 272 struct in_addr t;
81a36a8d 273
72e4f44e
SL
274 t = ip->ip_dst;
275 ip->ip_dst = ip->ip_src;
276 ip->ip_src = t;
81a36a8d
BJ
277 icmp_send(ip);
278}
279
280/*
72e4f44e
SL
281 * Send an icmp packet back to the ip level,
282 * after supplying a checksum.
81a36a8d 283 */
cdad2eb1 284icmp_send(ip)
81a36a8d 285 struct ip *ip;
81a36a8d 286{
af8f6a21 287 register int hlen;
72e4f44e 288 register struct icmp *icp;
af8f6a21 289 register struct mbuf *m;
d52566dd 290
af8f6a21
SL
291 m = dtom(ip);
292 hlen = ip->ip_hl << 2;
72e4f44e
SL
293 icp = mtod(m, struct icmp *);
294 icp->icmp_cksum = 0;
295 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
296 m->m_off -= hlen;
297 m->m_len += hlen;
a60889ab 298#ifdef ICMPPRINTFS
39674d5f
SL
299 if (icmpprintfs)
300 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
a60889ab 301#endif
a1edc12b 302 (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0);
d52566dd
BJ
303}
304
cdad2eb1 305n_time
2b4b57cd 306iptime()
d52566dd 307{
cdad2eb1 308 int s = spl6();
2752c877 309 u_long t;
d52566dd 310
b2ac7f3b 311 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
cdad2eb1
BJ
312 splx(s);
313 return (htonl(t));
d52566dd 314}