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