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