collect more statistics; add sanity check to avoid bad icmp packets
[unix-history] / usr / src / sys / netinet / ip_input.c
CommitLineData
9dc8d46a 1/* ip_input.c 1.65 83/02/23 */
6e8b2eca 2
e1d82856 3#include "../h/param.h"
d10bd5b7 4#include "../h/systm.h"
e6dd2097 5#include "../h/mbuf.h"
59965020 6#include "../h/domain.h"
eb44bfb2 7#include "../h/protosw.h"
2b4b57cd 8#include "../h/socket.h"
f4d55810
SL
9#include "../h/errno.h"
10#include "../h/time.h"
15aae2a0 11#include "../h/kernel.h"
6e7edb25
BJ
12
13#include "../net/if.h"
14#include "../net/route.h"
f4d55810 15
fcfe450e 16#include "../netinet/in.h"
a8d3bf7f 17#include "../netinet/in_pcb.h"
fcfe450e 18#include "../netinet/in_systm.h"
6e7edb25 19#include "../netinet/ip.h"
fcfe450e
BJ
20#include "../netinet/ip_var.h"
21#include "../netinet/ip_icmp.h"
22#include "../netinet/tcp.h"
e6dd2097 23
eb44bfb2 24u_char ip_protox[IPPROTO_MAX];
1e977657 25int ipqmaxlen = IFQ_MAXLEN;
ee787340 26struct ifnet *ifinet; /* first inet interface */
eb44bfb2 27
d52566dd 28/*
b454c3ea 29 * IP initialization: fill in IP protocol switch table.
405c9168 30 * All protocols not implemented in kernel go to raw IP protocol handler.
d52566dd
BJ
31 */
32ip_init()
33{
eb44bfb2
BJ
34 register struct protosw *pr;
35 register int i;
eb44bfb2
BJ
36
37 pr = pffindproto(PF_INET, IPPROTO_RAW);
38 if (pr == 0)
39 panic("ip_init");
40 for (i = 0; i < IPPROTO_MAX; i++)
59965020
BJ
41 ip_protox[i] = pr - inetsw;
42 for (pr = inetdomain.dom_protosw;
43 pr <= inetdomain.dom_protoswNPROTOSW; pr++)
eb44bfb2
BJ
44 if (pr->pr_family == PF_INET &&
45 pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
59965020 46 ip_protox[pr->pr_protocol] = pr - inetsw;
d52566dd 47 ipq.next = ipq.prev = &ipq;
b2ac7f3b 48 ip_id = time.tv_sec & 0xffff;
1e977657 49 ipintrq.ifq_maxlen = ipqmaxlen;
ee787340 50 ifinet = if_ifwithaf(AF_INET);
d52566dd
BJ
51}
52
eb44bfb2 53u_char ipcksum = 1;
e6dd2097 54struct ip *ip_reass();
ee787340 55struct sockaddr_in ipaddr = { AF_INET };
e6dd2097 56
e6dd2097
BJ
57/*
58 * Ip input routine. Checksum and byte swap header. If fragmented
59 * try to reassamble. If complete and fragment queue exists, discard.
60 * Process options. Pass to next level.
61 */
8a13b737 62ipintr()
e1d82856 63{
2b4b57cd 64 register struct ip *ip;
8a13b737 65 register struct mbuf *m;
a8d3bf7f 66 struct mbuf *m0;
e6dd2097 67 register int i;
e1d82856 68 register struct ipq *fp;
8a13b737 69 int hlen, s;
e1d82856 70
8a13b737 71next:
e6dd2097 72 /*
8a13b737
BJ
73 * Get next datagram off input queue and get IP header
74 * in first mbuf.
e6dd2097 75 */
8a13b737
BJ
76 s = splimp();
77 IF_DEQUEUE(&ipintrq, m);
78 splx(s);
7ac98d3c 79 if (m == 0)
8a13b737 80 return;
9411b6be 81 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) &&
9dc8d46a
SL
82 (m = m_pullup(m, sizeof (struct ip))) == 0) {
83 ipstat.ips_toosmall++;
84 goto next;
85 }
e6dd2097 86 ip = mtod(m, struct ip *);
405c9168 87 if ((hlen = ip->ip_hl << 2) > m->m_len) {
9dc8d46a
SL
88 if ((m = m_pullup(m, hlen)) == 0) {
89 ipstat.ips_badhlen++;
90 goto next;
91 }
405c9168
BJ
92 ip = mtod(m, struct ip *);
93 }
4ad99bae 94 if (ipcksum)
7c08c626 95 if (ip->ip_sum = in_cksum(m, hlen)) {
4ad99bae
BJ
96 ipstat.ips_badsum++;
97 goto bad;
e1d82856 98 }
4ad99bae
BJ
99
100 /*
101 * Convert fields to host representation.
102 */
cdad2eb1 103 ip->ip_len = ntohs((u_short)ip->ip_len);
9dc8d46a
SL
104 if (ip->ip_len < hlen) {
105 ipstat.ips_badlen++;
106 goto bad;
107 }
e6dd2097 108 ip->ip_id = ntohs(ip->ip_id);
4ad99bae 109 ip->ip_off = ntohs((u_short)ip->ip_off);
e1d82856 110
d10bd5b7 111 /*
e6dd2097
BJ
112 * Check that the amount of data in the buffers
113 * is as at least much as the IP header would have us expect.
114 * Trim mbufs if longer than we expect.
115 * Drop packet if shorter than we expect.
d10bd5b7 116 */
9c0ca361 117 i = -ip->ip_len;
405c9168 118 m0 = m;
9c0ca361 119 for (;;) {
e1d82856 120 i += m->m_len;
9c0ca361
BJ
121 if (m->m_next == 0)
122 break;
123 m = m->m_next;
1dd55890 124 }
9c0ca361
BJ
125 if (i != 0) {
126 if (i < 0) {
405c9168 127 ipstat.ips_tooshort++;
4ad99bae 128 goto bad;
405c9168 129 }
9c0ca361
BJ
130 if (i <= m->m_len)
131 m->m_len -= i;
132 else
133 m_adj(m0, -i);
d10bd5b7 134 }
9c0ca361 135 m = m0;
e1d82856 136
e6dd2097
BJ
137 /*
138 * Process options and, if not destined for us,
72e4f44e
SL
139 * ship it on. ip_dooptions returns 1 when an
140 * error was detected (causing an icmp message
141 * to be sent).
e6dd2097 142 */
72e4f44e
SL
143 if (hlen > sizeof (struct ip) && ip_dooptions(ip))
144 goto next;
ee787340
SL
145
146 /*
c124e997
SL
147 * Fast check on the first internet
148 * interface in the list.
ee787340
SL
149 */
150 if (ifinet) {
151 struct sockaddr_in *sin;
152
153 sin = (struct sockaddr_in *)&ifinet->if_addr;
154 if (sin->sin_addr.s_addr == ip->ip_dst.s_addr)
155 goto ours;
cdff57cc 156 sin = (struct sockaddr_in *)&ifinet->if_broadaddr;
c124e997
SL
157 if ((ifinet->if_flags & IFF_BROADCAST) &&
158 sin->sin_addr.s_addr == ip->ip_dst.s_addr)
159 goto ours;
ee787340 160 }
fb729471
SL
161/* BEGIN GROT */
162#include "nd.h"
163#if NND > 0
164 /*
165 * Diskless machines don't initially know
166 * their address, so take packets from them
167 * if we're acting as a network disk server.
168 */
169 if (ip->ip_dst.s_addr == INADDR_ANY &&
170 (in_netof(ip->ip_src) == INADDR_ANY &&
171 in_lnaof(ip->ip_src) != INADDR_ANY))
172 goto ours;
173#endif
174/* END GROT */
ee787340
SL
175 ipaddr.sin_addr = ip->ip_dst;
176 if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0) {
72e4f44e 177 ip_forward(ip);
8a13b737 178 goto next;
d10bd5b7 179 }
e1d82856 180
ee787340 181ours:
e6dd2097
BJ
182 /*
183 * Look for queue of fragments
184 * of this datagram.
185 */
186 for (fp = ipq.next; fp != &ipq; fp = fp->next)
187 if (ip->ip_id == fp->ipq_id &&
188 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
189 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
190 ip->ip_p == fp->ipq_p)
191 goto found;
192 fp = 0;
193found:
e1d82856 194
e6dd2097
BJ
195 /*
196 * Adjust ip_len to not reflect header,
197 * set ip_mff if more fragments are expected,
198 * convert offset of this to bytes.
199 */
200 ip->ip_len -= hlen;
eb44bfb2 201 ((struct ipasfrag *)ip)->ipf_mff = 0;
e6dd2097 202 if (ip->ip_off & IP_MF)
eb44bfb2 203 ((struct ipasfrag *)ip)->ipf_mff = 1;
e6dd2097 204 ip->ip_off <<= 3;
e1d82856 205
e6dd2097
BJ
206 /*
207 * If datagram marked as having more fragments
208 * or if this is not the first fragment,
209 * attempt reassembly; if it succeeds, proceed.
210 */
eb44bfb2
BJ
211 if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
212 ip = ip_reass((struct ipasfrag *)ip, fp);
e6dd2097 213 if (ip == 0)
8a13b737 214 goto next;
e6dd2097
BJ
215 hlen = ip->ip_hl << 2;
216 m = dtom(ip);
217 } else
218 if (fp)
e16de434 219 ip_freef(fp);
4ad99bae
BJ
220
221 /*
222 * Switch out to protocol's input routine.
223 */
59965020 224 (*inetsw[ip_protox[ip->ip_p]].pr_input)(m);
8a13b737 225 goto next;
4ad99bae
BJ
226bad:
227 m_freem(m);
8a13b737 228 goto next;
e6dd2097 229}
e1d82856 230
e6dd2097
BJ
231/*
232 * Take incoming datagram fragment and try to
4ad99bae 233 * reassemble it into whole datagram. If a chain for
e6dd2097
BJ
234 * reassembly of this datagram already exists, then it
235 * is given as fp; otherwise have to make a chain.
236 */
237struct ip *
238ip_reass(ip, fp)
eb44bfb2 239 register struct ipasfrag *ip;
e6dd2097
BJ
240 register struct ipq *fp;
241{
242 register struct mbuf *m = dtom(ip);
eb44bfb2 243 register struct ipasfrag *q;
e6dd2097
BJ
244 struct mbuf *t;
245 int hlen = ip->ip_hl << 2;
246 int i, next;
d10bd5b7 247
e6dd2097
BJ
248 /*
249 * Presence of header sizes in mbufs
250 * would confuse code below.
251 */
252 m->m_off += hlen;
253 m->m_len -= hlen;
d10bd5b7 254
e6dd2097
BJ
255 /*
256 * If first fragment to arrive, create a reassembly queue.
257 */
258 if (fp == 0) {
cce93e4b 259 if ((t = m_get(M_WAIT, MT_FTABLE)) == NULL)
e6dd2097 260 goto dropfrag;
e6dd2097
BJ
261 fp = mtod(t, struct ipq *);
262 insque(fp, &ipq);
263 fp->ipq_ttl = IPFRAGTTL;
264 fp->ipq_p = ip->ip_p;
265 fp->ipq_id = ip->ip_id;
eb44bfb2
BJ
266 fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
267 fp->ipq_src = ((struct ip *)ip)->ip_src;
268 fp->ipq_dst = ((struct ip *)ip)->ip_dst;
405c9168
BJ
269 q = (struct ipasfrag *)fp;
270 goto insert;
e6dd2097 271 }
e1d82856 272
e6dd2097
BJ
273 /*
274 * Find a segment which begins after this one does.
275 */
eb44bfb2 276 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
e6dd2097
BJ
277 if (q->ip_off > ip->ip_off)
278 break;
e1d82856 279
e6dd2097
BJ
280 /*
281 * If there is a preceding segment, it may provide some of
282 * our data already. If so, drop the data from the incoming
283 * segment. If it provides all of our data, drop us.
284 */
eb44bfb2
BJ
285 if (q->ipf_prev != (struct ipasfrag *)fp) {
286 i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
e6dd2097
BJ
287 if (i > 0) {
288 if (i >= ip->ip_len)
289 goto dropfrag;
290 m_adj(dtom(ip), i);
291 ip->ip_off += i;
292 ip->ip_len -= i;
e1d82856 293 }
d10bd5b7 294 }
e1d82856 295
e6dd2097
BJ
296 /*
297 * While we overlap succeeding segments trim them or,
298 * if they are completely covered, dequeue them.
299 */
eb44bfb2 300 while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
e6dd2097
BJ
301 i = (ip->ip_off + ip->ip_len) - q->ip_off;
302 if (i < q->ip_len) {
303 q->ip_len -= i;
c107df34 304 q->ip_off += i;
e6dd2097
BJ
305 m_adj(dtom(q), i);
306 break;
307 }
eb44bfb2
BJ
308 q = q->ipf_next;
309 m_freem(dtom(q->ipf_prev));
310 ip_deq(q->ipf_prev);
e6dd2097 311 }
e1d82856 312
405c9168 313insert:
e6dd2097
BJ
314 /*
315 * Stick new segment in its place;
316 * check for complete reassembly.
317 */
eb44bfb2 318 ip_enq(ip, q->ipf_prev);
e6dd2097 319 next = 0;
eb44bfb2 320 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
e6dd2097
BJ
321 if (q->ip_off != next)
322 return (0);
323 next += q->ip_len;
324 }
eb44bfb2 325 if (q->ipf_prev->ipf_mff)
e6dd2097 326 return (0);
e1d82856 327
e6dd2097
BJ
328 /*
329 * Reassembly is complete; concatenate fragments.
330 */
331 q = fp->ipq_next;
332 m = dtom(q);
333 t = m->m_next;
334 m->m_next = 0;
335 m_cat(m, t);
dfb346d0
BJ
336 q = q->ipf_next;
337 while (q != (struct ipasfrag *)fp) {
338 t = dtom(q);
339 q = q->ipf_next;
340 m_cat(m, t);
341 }
e1d82856 342
e6dd2097
BJ
343 /*
344 * Create header for new ip packet by
345 * modifying header of first packet;
346 * dequeue and discard fragment reassembly header.
347 * Make header visible.
348 */
349 ip = fp->ipq_next;
350 ip->ip_len = next;
eb44bfb2
BJ
351 ((struct ip *)ip)->ip_src = fp->ipq_src;
352 ((struct ip *)ip)->ip_dst = fp->ipq_dst;
e6dd2097 353 remque(fp);
cdad2eb1 354 (void) m_free(dtom(fp));
e6dd2097 355 m = dtom(ip);
eb44bfb2
BJ
356 m->m_len += sizeof (struct ipasfrag);
357 m->m_off -= sizeof (struct ipasfrag);
358 return ((struct ip *)ip);
e6dd2097
BJ
359
360dropfrag:
361 m_freem(m);
362 return (0);
e1d82856
BJ
363}
364
e6dd2097
BJ
365/*
366 * Free a fragment reassembly header and all
367 * associated datagrams.
368 */
e6dd2097
BJ
369ip_freef(fp)
370 struct ipq *fp;
e1d82856 371{
e16de434 372 register struct ipasfrag *q, *p;
e6dd2097 373
e16de434
SL
374 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
375 p = q->ipf_next;
376 ip_deq(q);
e6dd2097 377 m_freem(dtom(q));
e16de434
SL
378 }
379 remque(fp);
380 (void) m_free(dtom(fp));
e1d82856
BJ
381}
382
e6dd2097
BJ
383/*
384 * Put an ip fragment on a reassembly chain.
385 * Like insque, but pointers in middle of structure.
386 */
387ip_enq(p, prev)
eb44bfb2 388 register struct ipasfrag *p, *prev;
e1d82856 389{
e1d82856 390
eb44bfb2
BJ
391 p->ipf_prev = prev;
392 p->ipf_next = prev->ipf_next;
393 prev->ipf_next->ipf_prev = p;
394 prev->ipf_next = p;
e1d82856
BJ
395}
396
e6dd2097
BJ
397/*
398 * To ip_enq as remque is to insque.
399 */
400ip_deq(p)
eb44bfb2 401 register struct ipasfrag *p;
e1d82856 402{
e6dd2097 403
eb44bfb2
BJ
404 p->ipf_prev->ipf_next = p->ipf_next;
405 p->ipf_next->ipf_prev = p->ipf_prev;
e1d82856
BJ
406}
407
e6dd2097
BJ
408/*
409 * IP timer processing;
410 * if a timer expires on a reassembly
411 * queue, discard it.
412 */
d52566dd 413ip_slowtimo()
e1d82856
BJ
414{
415 register struct ipq *fp;
e6dd2097 416 int s = splnet();
e1d82856 417
4aed14e3
BJ
418 fp = ipq.next;
419 if (fp == 0) {
420 splx(s);
421 return;
422 }
e16de434
SL
423 while (fp != &ipq) {
424 --fp->ipq_ttl;
425 fp = fp->next;
426 if (fp->prev->ipq_ttl == 0)
427 ip_freef(fp->prev);
428 }
e6dd2097 429 splx(s);
e1d82856
BJ
430}
431
4ad99bae
BJ
432/*
433 * Drain off all datagram fragments.
434 */
d52566dd
BJ
435ip_drain()
436{
437
4ad99bae 438 while (ipq.next != &ipq)
e16de434 439 ip_freef(ipq.next);
d52566dd 440}
2b4b57cd 441
e6dd2097
BJ
442/*
443 * Do option processing on a datagram,
444 * possibly discarding it if bad options
445 * are encountered.
446 */
447ip_dooptions(ip)
448 struct ip *ip;
e1d82856 449{
e6dd2097 450 register u_char *cp;
72e4f44e 451 int opt, optlen, cnt, code, type;
2b4b57cd 452 struct in_addr *sin;
d52566dd 453 register struct ip_timestamp *ipt;
4ad99bae
BJ
454 register struct ifnet *ifp;
455 struct in_addr t;
e6dd2097
BJ
456
457 cp = (u_char *)(ip + 1);
458 cnt = (ip->ip_hl << 2) - sizeof (struct ip);
459 for (; cnt > 0; cnt -= optlen, cp += optlen) {
460 opt = cp[0];
461 if (opt == IPOPT_EOL)
462 break;
463 if (opt == IPOPT_NOP)
464 optlen = 1;
465 else
466 optlen = cp[1];
467 switch (opt) {
e1d82856 468
e6dd2097
BJ
469 default:
470 break;
e1d82856 471
4ad99bae
BJ
472 /*
473 * Source routing with record.
474 * Find interface with current destination address.
475 * If none on this machine then drop if strictly routed,
476 * or do nothing if loosely routed.
477 * Record interface address and bring up next address
478 * component. If strictly routed make sure next
479 * address on directly accessible net.
480 */
e6dd2097 481 case IPOPT_LSRR:
a71ece0a 482 case IPOPT_SSRR:
d52566dd 483 if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1))
e6dd2097 484 break;
2b4b57cd 485 sin = (struct in_addr *)(cp + cp[2]);
ee787340
SL
486 ipaddr.sin_addr = *sin;
487 ifp = if_ifwithaddr((struct sockaddr *)&ipaddr);
72e4f44e 488 type = ICMP_UNREACH, code = ICMP_UNREACH_SRCFAIL;
4ad99bae
BJ
489 if (ifp == 0) {
490 if (opt == IPOPT_SSRR)
491 goto bad;
492 break;
e6dd2097 493 }
4ad99bae
BJ
494 t = ip->ip_dst; ip->ip_dst = *sin; *sin = t;
495 cp[2] += 4;
496 if (cp[2] > optlen - (sizeof (long) - 1))
497 break;
498 ip->ip_dst = sin[1];
ee787340 499 if (opt == IPOPT_SSRR &&
6187f8f4 500 if_ifonnetof(in_netof(ip->ip_dst)) == 0)
4ad99bae 501 goto bad;
e6dd2097
BJ
502 break;
503
504 case IPOPT_TS:
72e4f44e
SL
505 code = cp - (u_char *)ip;
506 type = ICMP_PARAMPROB;
d52566dd
BJ
507 ipt = (struct ip_timestamp *)cp;
508 if (ipt->ipt_len < 5)
e6dd2097 509 goto bad;
d52566dd
BJ
510 if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
511 if (++ipt->ipt_oflw == 0)
e6dd2097 512 goto bad;
e6dd2097
BJ
513 break;
514 }
2b4b57cd 515 sin = (struct in_addr *)(cp+cp[2]);
d52566dd 516 switch (ipt->ipt_flg) {
e1d82856 517
e6dd2097
BJ
518 case IPOPT_TS_TSONLY:
519 break;
e1d82856 520
e6dd2097 521 case IPOPT_TS_TSANDADDR:
d52566dd 522 if (ipt->ipt_ptr + 8 > ipt->ipt_len)
e6dd2097 523 goto bad;
ee787340
SL
524 if (ifinet == 0)
525 goto bad; /* ??? */
526 *sin++ = ((struct sockaddr_in *)&ifinet->if_addr)->sin_addr;
e6dd2097
BJ
527 break;
528
529 case IPOPT_TS_PRESPEC:
ee787340 530 ipaddr.sin_addr = *sin;
5cdc4d65 531 if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
4ad99bae 532 continue;
d52566dd 533 if (ipt->ipt_ptr + 8 > ipt->ipt_len)
e6dd2097 534 goto bad;
d52566dd 535 ipt->ipt_ptr += 4;
e1d82856
BJ
536 break;
537
538 default:
e6dd2097 539 goto bad;
e1d82856 540 }
2b4b57cd 541 *(n_time *)sin = iptime();
d52566dd 542 ipt->ipt_ptr += 4;
e6dd2097 543 }
e1d82856 544 }
72e4f44e 545 return (0);
e6dd2097 546bad:
72e4f44e
SL
547 icmp_error(ip, type, code);
548 return (1);
e1d82856
BJ
549}
550
e6dd2097 551/*
4ad99bae
BJ
552 * Strip out IP options, at higher
553 * level protocol in the kernel.
554 * Second argument is buffer to which options
555 * will be moved, and return value is their length.
e6dd2097 556 */
7c08c626 557ip_stripoptions(ip, mopt)
e6dd2097 558 struct ip *ip;
7c08c626 559 struct mbuf *mopt;
e1d82856 560{
e6dd2097
BJ
561 register int i;
562 register struct mbuf *m;
e6dd2097 563 int olen;
e6dd2097
BJ
564
565 olen = (ip->ip_hl<<2) - sizeof (struct ip);
4ad99bae
BJ
566 m = dtom(ip);
567 ip++;
7c08c626
BJ
568 if (mopt) {
569 mopt->m_len = olen;
570 mopt->m_off = MMINOFF;
571 bcopy((caddr_t)ip, mtod(m, caddr_t), (unsigned)olen);
572 }
e6dd2097 573 i = m->m_len - (sizeof (struct ip) + olen);
cdad2eb1 574 bcopy((caddr_t)ip+olen, (caddr_t)ip, (unsigned)i);
4aed14e3 575 m->m_len -= olen;
e1d82856 576}
72e4f44e 577
39674d5f 578u_char inetctlerrmap[] = {
72e4f44e 579 ECONNABORTED, ECONNABORTED, 0, 0,
67387c9c
SL
580 0, 0,
581 EHOSTDOWN, EHOSTUNREACH, ENETUNREACH, EHOSTUNREACH,
72e4f44e
SL
582 ECONNREFUSED, ECONNREFUSED, EMSGSIZE, 0,
583 0, 0, 0, 0
584};
585
586ip_ctlinput(cmd, arg)
587 int cmd;
588 caddr_t arg;
589{
39d536e6 590 struct in_addr *in;
39674d5f 591 int tcp_abort(), udp_abort();
72e4f44e
SL
592 extern struct inpcb tcb, udb;
593
594 if (cmd < 0 || cmd > PRC_NCMDS)
595 return;
39674d5f 596 if (inetctlerrmap[cmd] == 0)
72e4f44e
SL
597 return; /* XXX */
598 if (cmd == PRC_IFDOWN)
39d536e6 599 in = &((struct sockaddr_in *)arg)->sin_addr;
72e4f44e 600 else if (cmd == PRC_HOSTDEAD || cmd == PRC_HOSTUNREACH)
39d536e6 601 in = (struct in_addr *)arg;
72e4f44e 602 else
39d536e6 603 in = &((struct icmp *)arg)->icmp_ip.ip_dst;
a8d3bf7f 604/* THIS IS VERY QUESTIONABLE, SHOULD HIT ALL PROTOCOLS */
39d536e6
BJ
605 in_pcbnotify(&tcb, in, (int)inetctlerrmap[cmd], tcp_abort);
606 in_pcbnotify(&udb, in, (int)inetctlerrmap[cmd], udp_abort);
72e4f44e
SL
607}
608
609int ipprintfs = 0;
610int ipforwarding = 1;
611/*
612 * Forward a packet. If some error occurs return the sender
613 * and icmp packet. Note we can't always generate a meaningful
614 * icmp message because icmp doesn't have a large enough repetoire
615 * of codes and types.
616 */
617ip_forward(ip)
618 register struct ip *ip;
619{
620 register int error, type, code;
67387c9c 621 struct mbuf *mopt, *mcopy;
72e4f44e
SL
622
623 if (ipprintfs)
624 printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
625 ip->ip_dst, ip->ip_ttl);
626 if (ipforwarding == 0) {
627 /* can't tell difference between net and host */
628 type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
629 goto sendicmp;
630 }
631 if (ip->ip_ttl < IPTTLDEC) {
632 type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
633 goto sendicmp;
634 }
635 ip->ip_ttl -= IPTTLDEC;
cce93e4b 636 mopt = m_get(M_DONTWAIT, MT_DATA);
9dc8d46a 637 if (mopt == NULL) {
72e4f44e
SL
638 m_freem(dtom(ip));
639 return;
640 }
67387c9c
SL
641
642 /*
643 * Save at most 64 bytes of the packet in case
644 * we need to generate an ICMP message to the src.
645 */
348901af 646 mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64));
72e4f44e
SL
647 ip_stripoptions(ip, mopt);
648
649 /* last 0 here means no directed broadcast */
a1edc12b 650 if ((error = ip_output(dtom(ip), mopt, (struct route *)0, 0)) == 0) {
67387c9c
SL
651 if (mcopy)
652 m_freem(mcopy);
72e4f44e 653 return;
67387c9c
SL
654 }
655 ip = mtod(mcopy, struct ip *);
656 type = ICMP_UNREACH, code = 0; /* need ``undefined'' */
657 switch (error) {
658
659 case ENETUNREACH:
660 case ENETDOWN:
72e4f44e 661 code = ICMP_UNREACH_NET;
67387c9c
SL
662 break;
663
664 case EMSGSIZE:
72e4f44e 665 code = ICMP_UNREACH_NEEDFRAG;
67387c9c
SL
666 break;
667
668 case EPERM:
669 code = ICMP_UNREACH_PORT;
670 break;
671
672 case ENOBUFS:
673 type = ICMP_SOURCEQUENCH;
674 break;
675
676 case EHOSTDOWN:
677 case EHOSTUNREACH:
678 code = ICMP_UNREACH_HOST;
679 break;
680 }
72e4f44e
SL
681sendicmp:
682 icmp_error(ip, type, code);
683}