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