needed seek *inside* the loop for retries; add (undoc) -# flag
[unix-history] / usr / src / sys / netinet / ip_input.c
CommitLineData
8ae0e4b4 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
2b6b6284 3 * All rights reserved.
8ae0e4b4 4 *
2b6b6284
KB
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of California at Berkeley. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
11 *
12 * @(#)ip_input.c 7.8 (Berkeley) %G%
8ae0e4b4 13 */
6e8b2eca 14
20666ad3
JB
15#include "param.h"
16#include "systm.h"
17#include "mbuf.h"
18#include "domain.h"
19#include "protosw.h"
20#include "socket.h"
21#include "errno.h"
22#include "time.h"
23#include "kernel.h"
6e7edb25
BJ
24
25#include "../net/if.h"
26#include "../net/route.h"
f4d55810 27
20666ad3
JB
28#include "in.h"
29#include "in_pcb.h"
30#include "in_systm.h"
f223fa7d 31#include "in_var.h"
20666ad3
JB
32#include "ip.h"
33#include "ip_var.h"
34#include "ip_icmp.h"
35#include "tcp.h"
e6dd2097 36
eb44bfb2 37u_char ip_protox[IPPROTO_MAX];
1e977657 38int ipqmaxlen = IFQ_MAXLEN;
f223fa7d 39struct in_ifaddr *in_ifaddr; /* first inet address */
eb44bfb2 40
8fb48289
MK
41/*
42 * We need to save the IP options in case a protocol wants to respond
43 * to an incoming packet over the same route if the packet got here
44 * using IP source routing. This allows connection establishment and
45 * maintenance when the remote end is on a network that is not known
46 * to us.
47 */
48int ip_nhops = 0;
49static struct ip_srcrt {
50 char nop; /* one NOP to align */
51 char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */
52 struct in_addr route[MAX_IPOPTLEN];
53} ip_srcrt;
54
d52566dd 55/*
b454c3ea 56 * IP initialization: fill in IP protocol switch table.
405c9168 57 * All protocols not implemented in kernel go to raw IP protocol handler.
d52566dd
BJ
58 */
59ip_init()
60{
eb44bfb2
BJ
61 register struct protosw *pr;
62 register int i;
eb44bfb2 63
8fb48289 64 pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
eb44bfb2
BJ
65 if (pr == 0)
66 panic("ip_init");
67 for (i = 0; i < IPPROTO_MAX; i++)
59965020
BJ
68 ip_protox[i] = pr - inetsw;
69 for (pr = inetdomain.dom_protosw;
36bb5f94 70 pr < inetdomain.dom_protoswNPROTOSW; pr++)
abe04898 71 if (pr->pr_domain->dom_family == PF_INET &&
eb44bfb2 72 pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
59965020 73 ip_protox[pr->pr_protocol] = pr - inetsw;
d52566dd 74 ipq.next = ipq.prev = &ipq;
b2ac7f3b 75 ip_id = time.tv_sec & 0xffff;
1e977657 76 ipintrq.ifq_maxlen = ipqmaxlen;
d52566dd
BJ
77}
78
eb44bfb2 79u_char ipcksum = 1;
e6dd2097 80struct ip *ip_reass();
ee787340 81struct sockaddr_in ipaddr = { AF_INET };
8fb48289 82struct route ipforward_rt;
e6dd2097 83
e6dd2097
BJ
84/*
85 * Ip input routine. Checksum and byte swap header. If fragmented
86 * try to reassamble. If complete and fragment queue exists, discard.
87 * Process options. Pass to next level.
88 */
8a13b737 89ipintr()
e1d82856 90{
2b4b57cd 91 register struct ip *ip;
8a13b737 92 register struct mbuf *m;
a8d3bf7f 93 struct mbuf *m0;
e6dd2097 94 register int i;
e1d82856 95 register struct ipq *fp;
f223fa7d 96 register struct in_ifaddr *ia;
8fb48289 97 struct ifnet *ifp;
8a13b737 98 int hlen, s;
e1d82856 99
8a13b737 100next:
e6dd2097 101 /*
8a13b737
BJ
102 * Get next datagram off input queue and get IP header
103 * in first mbuf.
e6dd2097 104 */
8a13b737 105 s = splimp();
8fb48289 106 IF_DEQUEUEIF(&ipintrq, m, ifp);
8a13b737 107 splx(s);
7ac98d3c 108 if (m == 0)
8a13b737 109 return;
773dfe90
MK
110 /*
111 * If no IP addresses have been set yet but the interfaces
112 * are receiving, can't do anything with incoming packets yet.
113 */
114 if (in_ifaddr == NULL)
115 goto bad;
7922844b 116 ipstat.ips_total++;
9411b6be 117 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) &&
9dc8d46a
SL
118 (m = m_pullup(m, sizeof (struct ip))) == 0) {
119 ipstat.ips_toosmall++;
120 goto next;
121 }
e6dd2097 122 ip = mtod(m, struct ip *);
f223fa7d 123 hlen = ip->ip_hl << 2;
8fb48289 124 if (hlen < sizeof(struct ip)) { /* minimum header length */
f223fa7d 125 ipstat.ips_badhlen++;
ac066ae1 126 goto bad;
f223fa7d
MK
127 }
128 if (hlen > m->m_len) {
9dc8d46a
SL
129 if ((m = m_pullup(m, hlen)) == 0) {
130 ipstat.ips_badhlen++;
131 goto next;
132 }
405c9168
BJ
133 ip = mtod(m, struct ip *);
134 }
4ad99bae 135 if (ipcksum)
7c08c626 136 if (ip->ip_sum = in_cksum(m, hlen)) {
4ad99bae
BJ
137 ipstat.ips_badsum++;
138 goto bad;
e1d82856 139 }
4ad99bae
BJ
140
141 /*
142 * Convert fields to host representation.
143 */
cdad2eb1 144 ip->ip_len = ntohs((u_short)ip->ip_len);
9dc8d46a
SL
145 if (ip->ip_len < hlen) {
146 ipstat.ips_badlen++;
147 goto bad;
148 }
e6dd2097 149 ip->ip_id = ntohs(ip->ip_id);
4ad99bae 150 ip->ip_off = ntohs((u_short)ip->ip_off);
e1d82856 151
d10bd5b7 152 /*
e6dd2097
BJ
153 * Check that the amount of data in the buffers
154 * is as at least much as the IP header would have us expect.
155 * Trim mbufs if longer than we expect.
156 * Drop packet if shorter than we expect.
d10bd5b7 157 */
8fb48289 158 i = -(u_short)ip->ip_len;
405c9168 159 m0 = m;
9c0ca361 160 for (;;) {
e1d82856 161 i += m->m_len;
9c0ca361
BJ
162 if (m->m_next == 0)
163 break;
164 m = m->m_next;
1dd55890 165 }
9c0ca361
BJ
166 if (i != 0) {
167 if (i < 0) {
405c9168 168 ipstat.ips_tooshort++;
842b6bb5 169 m = m0;
4ad99bae 170 goto bad;
405c9168 171 }
9c0ca361
BJ
172 if (i <= m->m_len)
173 m->m_len -= i;
174 else
175 m_adj(m0, -i);
d10bd5b7 176 }
9c0ca361 177 m = m0;
e1d82856 178
e6dd2097
BJ
179 /*
180 * Process options and, if not destined for us,
72e4f44e
SL
181 * ship it on. ip_dooptions returns 1 when an
182 * error was detected (causing an icmp message
ac066ae1 183 * to be sent and the original packet to be freed).
e6dd2097 184 */
8fb48289 185 ip_nhops = 0; /* for source routed packets */
c45e83d2 186 if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp))
72e4f44e 187 goto next;
ee787340
SL
188
189 /*
f223fa7d 190 * Check our list of addresses, to see if the packet is for us.
ee787340 191 */
f223fa7d
MK
192 for (ia = in_ifaddr; ia; ia = ia->ia_next) {
193#define satosin(sa) ((struct sockaddr_in *)(sa))
194
195 if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
8fb48289 196 goto ours;
4afb57fa
MK
197 if (
198#ifdef DIRECTED_BROADCAST
199 ia->ia_ifp == ifp &&
200#endif
201 (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
b2a3d559 202 u_long t;
4afb57fa
MK
203
204 if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
205 ip->ip_dst.s_addr)
206 goto ours;
207 if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
208 goto ours;
209 /*
210 * Look for all-0's host part (old broadcast addr),
211 * either for subnet or net.
212 */
b2a3d559
MK
213 t = ntohl(ip->ip_dst.s_addr);
214 if (t == ia->ia_subnet)
4afb57fa 215 goto ours;
b2a3d559 216 if (t == ia->ia_net)
4afb57fa
MK
217 goto ours;
218 }
d10bd5b7 219 }
8fb48289
MK
220 if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
221 goto ours;
222 if (ip->ip_dst.s_addr == INADDR_ANY)
223 goto ours;
e1d82856 224
8fb48289
MK
225 /*
226 * Not for us; forward if possible and desirable.
227 */
228 ip_forward(ip, ifp);
229 goto next;
230
231ours:
e6dd2097
BJ
232 /*
233 * Look for queue of fragments
234 * of this datagram.
235 */
236 for (fp = ipq.next; fp != &ipq; fp = fp->next)
237 if (ip->ip_id == fp->ipq_id &&
238 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
239 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
240 ip->ip_p == fp->ipq_p)
241 goto found;
242 fp = 0;
243found:
e1d82856 244
e6dd2097
BJ
245 /*
246 * Adjust ip_len to not reflect header,
247 * set ip_mff if more fragments are expected,
248 * convert offset of this to bytes.
249 */
250 ip->ip_len -= hlen;
eb44bfb2 251 ((struct ipasfrag *)ip)->ipf_mff = 0;
e6dd2097 252 if (ip->ip_off & IP_MF)
eb44bfb2 253 ((struct ipasfrag *)ip)->ipf_mff = 1;
e6dd2097 254 ip->ip_off <<= 3;
e1d82856 255
e6dd2097
BJ
256 /*
257 * If datagram marked as having more fragments
258 * or if this is not the first fragment,
259 * attempt reassembly; if it succeeds, proceed.
260 */
eb44bfb2 261 if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
8fb48289 262 ipstat.ips_fragments++;
eb44bfb2 263 ip = ip_reass((struct ipasfrag *)ip, fp);
e6dd2097 264 if (ip == 0)
8a13b737 265 goto next;
e6dd2097
BJ
266 m = dtom(ip);
267 } else
268 if (fp)
e16de434 269 ip_freef(fp);
4ad99bae
BJ
270
271 /*
272 * Switch out to protocol's input routine.
273 */
8fb48289 274 (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp);
8a13b737 275 goto next;
4ad99bae
BJ
276bad:
277 m_freem(m);
8a13b737 278 goto next;
e6dd2097 279}
e1d82856 280
e6dd2097
BJ
281/*
282 * Take incoming datagram fragment and try to
4ad99bae 283 * reassemble it into whole datagram. If a chain for
e6dd2097
BJ
284 * reassembly of this datagram already exists, then it
285 * is given as fp; otherwise have to make a chain.
286 */
287struct ip *
288ip_reass(ip, fp)
eb44bfb2 289 register struct ipasfrag *ip;
e6dd2097
BJ
290 register struct ipq *fp;
291{
292 register struct mbuf *m = dtom(ip);
eb44bfb2 293 register struct ipasfrag *q;
e6dd2097
BJ
294 struct mbuf *t;
295 int hlen = ip->ip_hl << 2;
296 int i, next;
d10bd5b7 297
e6dd2097
BJ
298 /*
299 * Presence of header sizes in mbufs
300 * would confuse code below.
301 */
302 m->m_off += hlen;
303 m->m_len -= hlen;
d10bd5b7 304
e6dd2097
BJ
305 /*
306 * If first fragment to arrive, create a reassembly queue.
307 */
308 if (fp == 0) {
13494852 309 if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
e6dd2097 310 goto dropfrag;
e6dd2097
BJ
311 fp = mtod(t, struct ipq *);
312 insque(fp, &ipq);
313 fp->ipq_ttl = IPFRAGTTL;
314 fp->ipq_p = ip->ip_p;
315 fp->ipq_id = ip->ip_id;
eb44bfb2
BJ
316 fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
317 fp->ipq_src = ((struct ip *)ip)->ip_src;
318 fp->ipq_dst = ((struct ip *)ip)->ip_dst;
405c9168
BJ
319 q = (struct ipasfrag *)fp;
320 goto insert;
e6dd2097 321 }
e1d82856 322
e6dd2097
BJ
323 /*
324 * Find a segment which begins after this one does.
325 */
eb44bfb2 326 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
e6dd2097
BJ
327 if (q->ip_off > ip->ip_off)
328 break;
e1d82856 329
e6dd2097
BJ
330 /*
331 * If there is a preceding segment, it may provide some of
332 * our data already. If so, drop the data from the incoming
333 * segment. If it provides all of our data, drop us.
334 */
eb44bfb2
BJ
335 if (q->ipf_prev != (struct ipasfrag *)fp) {
336 i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
e6dd2097
BJ
337 if (i > 0) {
338 if (i >= ip->ip_len)
339 goto dropfrag;
340 m_adj(dtom(ip), i);
341 ip->ip_off += i;
342 ip->ip_len -= i;
e1d82856 343 }
d10bd5b7 344 }
e1d82856 345
e6dd2097
BJ
346 /*
347 * While we overlap succeeding segments trim them or,
348 * if they are completely covered, dequeue them.
349 */
eb44bfb2 350 while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
e6dd2097
BJ
351 i = (ip->ip_off + ip->ip_len) - q->ip_off;
352 if (i < q->ip_len) {
353 q->ip_len -= i;
c107df34 354 q->ip_off += i;
e6dd2097
BJ
355 m_adj(dtom(q), i);
356 break;
357 }
eb44bfb2
BJ
358 q = q->ipf_next;
359 m_freem(dtom(q->ipf_prev));
360 ip_deq(q->ipf_prev);
e6dd2097 361 }
e1d82856 362
405c9168 363insert:
e6dd2097
BJ
364 /*
365 * Stick new segment in its place;
366 * check for complete reassembly.
367 */
eb44bfb2 368 ip_enq(ip, q->ipf_prev);
e6dd2097 369 next = 0;
eb44bfb2 370 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
e6dd2097
BJ
371 if (q->ip_off != next)
372 return (0);
373 next += q->ip_len;
374 }
eb44bfb2 375 if (q->ipf_prev->ipf_mff)
e6dd2097 376 return (0);
e1d82856 377
e6dd2097
BJ
378 /*
379 * Reassembly is complete; concatenate fragments.
380 */
381 q = fp->ipq_next;
382 m = dtom(q);
383 t = m->m_next;
384 m->m_next = 0;
385 m_cat(m, t);
dfb346d0
BJ
386 q = q->ipf_next;
387 while (q != (struct ipasfrag *)fp) {
388 t = dtom(q);
389 q = q->ipf_next;
390 m_cat(m, t);
391 }
e1d82856 392
e6dd2097
BJ
393 /*
394 * Create header for new ip packet by
395 * modifying header of first packet;
396 * dequeue and discard fragment reassembly header.
397 * Make header visible.
398 */
399 ip = fp->ipq_next;
400 ip->ip_len = next;
eb44bfb2
BJ
401 ((struct ip *)ip)->ip_src = fp->ipq_src;
402 ((struct ip *)ip)->ip_dst = fp->ipq_dst;
e6dd2097 403 remque(fp);
cdad2eb1 404 (void) m_free(dtom(fp));
e6dd2097 405 m = dtom(ip);
8fb48289
MK
406 m->m_len += (ip->ip_hl << 2);
407 m->m_off -= (ip->ip_hl << 2);
eb44bfb2 408 return ((struct ip *)ip);
e6dd2097
BJ
409
410dropfrag:
8fb48289 411 ipstat.ips_fragdropped++;
e6dd2097
BJ
412 m_freem(m);
413 return (0);
e1d82856
BJ
414}
415
e6dd2097
BJ
416/*
417 * Free a fragment reassembly header and all
418 * associated datagrams.
419 */
e6dd2097
BJ
420ip_freef(fp)
421 struct ipq *fp;
e1d82856 422{
e16de434 423 register struct ipasfrag *q, *p;
e6dd2097 424
e16de434
SL
425 for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
426 p = q->ipf_next;
427 ip_deq(q);
e6dd2097 428 m_freem(dtom(q));
e16de434
SL
429 }
430 remque(fp);
431 (void) m_free(dtom(fp));
e1d82856
BJ
432}
433
e6dd2097
BJ
434/*
435 * Put an ip fragment on a reassembly chain.
436 * Like insque, but pointers in middle of structure.
437 */
438ip_enq(p, prev)
eb44bfb2 439 register struct ipasfrag *p, *prev;
e1d82856 440{
e1d82856 441
eb44bfb2
BJ
442 p->ipf_prev = prev;
443 p->ipf_next = prev->ipf_next;
444 prev->ipf_next->ipf_prev = p;
445 prev->ipf_next = p;
e1d82856
BJ
446}
447
e6dd2097
BJ
448/*
449 * To ip_enq as remque is to insque.
450 */
451ip_deq(p)
eb44bfb2 452 register struct ipasfrag *p;
e1d82856 453{
e6dd2097 454
eb44bfb2
BJ
455 p->ipf_prev->ipf_next = p->ipf_next;
456 p->ipf_next->ipf_prev = p->ipf_prev;
e1d82856
BJ
457}
458
e6dd2097
BJ
459/*
460 * IP timer processing;
461 * if a timer expires on a reassembly
462 * queue, discard it.
463 */
d52566dd 464ip_slowtimo()
e1d82856
BJ
465{
466 register struct ipq *fp;
e6dd2097 467 int s = splnet();
e1d82856 468
4aed14e3
BJ
469 fp = ipq.next;
470 if (fp == 0) {
471 splx(s);
472 return;
473 }
e16de434
SL
474 while (fp != &ipq) {
475 --fp->ipq_ttl;
476 fp = fp->next;
8fb48289
MK
477 if (fp->prev->ipq_ttl == 0) {
478 ipstat.ips_fragtimeout++;
e16de434 479 ip_freef(fp->prev);
8fb48289 480 }
e16de434 481 }
e6dd2097 482 splx(s);
e1d82856
BJ
483}
484
4ad99bae
BJ
485/*
486 * Drain off all datagram fragments.
487 */
d52566dd
BJ
488ip_drain()
489{
490
8fb48289
MK
491 while (ipq.next != &ipq) {
492 ipstat.ips_fragdropped++;
e16de434 493 ip_freef(ipq.next);
8fb48289 494 }
d52566dd 495}
2b4b57cd 496
1846019d 497extern struct in_ifaddr *ifptoia();
8fb48289
MK
498struct in_ifaddr *ip_rtaddr();
499
e6dd2097
BJ
500/*
501 * Do option processing on a datagram,
502 * possibly discarding it if bad options
503 * are encountered.
504 */
c45e83d2
MK
505ip_dooptions(ip, ifp)
506 register struct ip *ip;
507 struct ifnet *ifp;
e1d82856 508{
e6dd2097 509 register u_char *cp;
8fb48289 510 int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB;
d52566dd 511 register struct ip_timestamp *ipt;
8fb48289
MK
512 register struct in_ifaddr *ia;
513 struct in_addr *sin;
514 n_time ntime;
e6dd2097
BJ
515
516 cp = (u_char *)(ip + 1);
517 cnt = (ip->ip_hl << 2) - sizeof (struct ip);
518 for (; cnt > 0; cnt -= optlen, cp += optlen) {
8fb48289 519 opt = cp[IPOPT_OPTVAL];
e6dd2097
BJ
520 if (opt == IPOPT_EOL)
521 break;
522 if (opt == IPOPT_NOP)
523 optlen = 1;
942169f7 524 else {
8fb48289
MK
525 optlen = cp[IPOPT_OLEN];
526 if (optlen <= 0 || optlen > cnt) {
527 code = &cp[IPOPT_OLEN] - (u_char *)ip;
36bb5f94 528 goto bad;
8fb48289 529 }
942169f7 530 }
e6dd2097 531 switch (opt) {
e1d82856 532
e6dd2097
BJ
533 default:
534 break;
e1d82856 535
4ad99bae
BJ
536 /*
537 * Source routing with record.
538 * Find interface with current destination address.
539 * If none on this machine then drop if strictly routed,
540 * or do nothing if loosely routed.
541 * Record interface address and bring up next address
542 * component. If strictly routed make sure next
543 * address on directly accessible net.
544 */
e6dd2097 545 case IPOPT_LSRR:
a71ece0a 546 case IPOPT_SSRR:
8fb48289
MK
547 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
548 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
549 goto bad;
550 }
551 ipaddr.sin_addr = ip->ip_dst;
552 ia = (struct in_ifaddr *)
553 ifa_ifwithaddr((struct sockaddr *)&ipaddr);
554 if (ia == 0) {
555 if (opt == IPOPT_SSRR) {
556 type = ICMP_UNREACH;
557 code = ICMP_UNREACH_SRCFAIL;
4ad99bae 558 goto bad;
8fb48289
MK
559 }
560 /*
561 * Loose routing, and not at next destination
562 * yet; nothing to do except forward.
563 */
4ad99bae 564 break;
e6dd2097 565 }
8fb48289
MK
566 off--; /* 0 origin */
567 if (off > optlen - sizeof(struct in_addr)) {
568 /*
569 * End of source route. Should be for us.
570 */
571 save_rte(cp, ip->ip_src);
4ad99bae 572 break;
8fb48289
MK
573 }
574 /*
575 * locate outgoing interface
576 */
8011f5df 577 bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
8fb48289
MK
578 sizeof(ipaddr.sin_addr));
579 if ((opt == IPOPT_SSRR &&
580 in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) ||
581 (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
582 type = ICMP_UNREACH;
583 code = ICMP_UNREACH_SRCFAIL;
4ad99bae 584 goto bad;
8fb48289
MK
585 }
586 ip->ip_dst = ipaddr.sin_addr;
8011f5df
MK
587 bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
588 (caddr_t)(cp + off), sizeof(struct in_addr));
8fb48289
MK
589 cp[IPOPT_OFFSET] += sizeof(struct in_addr);
590 break;
591
592 case IPOPT_RR:
593 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
594 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
595 goto bad;
596 }
597 /*
598 * If no space remains, ignore.
599 */
600 off--; /* 0 origin */
601 if (off > optlen - sizeof(struct in_addr))
602 break;
c13e44b4 603 bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
8fb48289
MK
604 sizeof(ipaddr.sin_addr));
605 /*
606 * locate outgoing interface
607 */
608 if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
609 type = ICMP_UNREACH;
d89cc5db 610 code = ICMP_UNREACH_HOST;
8fb48289
MK
611 goto bad;
612 }
8011f5df
MK
613 bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
614 (caddr_t)(cp + off), sizeof(struct in_addr));
8fb48289 615 cp[IPOPT_OFFSET] += sizeof(struct in_addr);
e6dd2097
BJ
616 break;
617
618 case IPOPT_TS:
72e4f44e 619 code = cp - (u_char *)ip;
d52566dd
BJ
620 ipt = (struct ip_timestamp *)cp;
621 if (ipt->ipt_len < 5)
e6dd2097 622 goto bad;
d52566dd
BJ
623 if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
624 if (++ipt->ipt_oflw == 0)
e6dd2097 625 goto bad;
e6dd2097
BJ
626 break;
627 }
1846019d 628 sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
d52566dd 629 switch (ipt->ipt_flg) {
e1d82856 630
e6dd2097
BJ
631 case IPOPT_TS_TSONLY:
632 break;
e1d82856 633
e6dd2097 634 case IPOPT_TS_TSANDADDR:
8fb48289
MK
635 if (ipt->ipt_ptr + sizeof(n_time) +
636 sizeof(struct in_addr) > ipt->ipt_len)
e6dd2097 637 goto bad;
1846019d
MK
638 ia = ifptoia(ifp);
639 bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
8fb48289 640 (caddr_t)sin, sizeof(struct in_addr));
1846019d 641 ipt->ipt_ptr += sizeof(struct in_addr);
e6dd2097
BJ
642 break;
643
644 case IPOPT_TS_PRESPEC:
1846019d
MK
645 if (ipt->ipt_ptr + sizeof(n_time) +
646 sizeof(struct in_addr) > ipt->ipt_len)
647 goto bad;
8fb48289
MK
648 bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
649 sizeof(struct in_addr));
f223fa7d 650 if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
4ad99bae 651 continue;
8fb48289 652 ipt->ipt_ptr += sizeof(struct in_addr);
e1d82856
BJ
653 break;
654
655 default:
e6dd2097 656 goto bad;
e1d82856 657 }
8fb48289 658 ntime = iptime();
1846019d
MK
659 bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
660 sizeof(n_time));
8fb48289 661 ipt->ipt_ptr += sizeof(n_time);
e6dd2097 662 }
e1d82856 663 }
72e4f44e 664 return (0);
e6dd2097 665bad:
c45e83d2 666 icmp_error(ip, type, code, ifp);
72e4f44e 667 return (1);
e1d82856
BJ
668}
669
8fb48289
MK
670/*
671 * Given address of next destination (final or next hop),
672 * return internet address info of interface to be used to get there.
673 */
674struct in_ifaddr *
675ip_rtaddr(dst)
676 struct in_addr dst;
677{
678 register struct sockaddr_in *sin;
679 register struct in_ifaddr *ia;
680
681 sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
682
683 if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
684 if (ipforward_rt.ro_rt) {
685 RTFREE(ipforward_rt.ro_rt);
686 ipforward_rt.ro_rt = 0;
687 }
688 sin->sin_family = AF_INET;
689 sin->sin_addr = dst;
690
691 rtalloc(&ipforward_rt);
692 }
693 if (ipforward_rt.ro_rt == 0)
694 return ((struct in_ifaddr *)0);
695 /*
696 * Find address associated with outgoing interface.
697 */
698 for (ia = in_ifaddr; ia; ia = ia->ia_next)
699 if (ia->ia_ifp == ipforward_rt.ro_rt->rt_ifp)
700 break;
701 return (ia);
702}
703
704/*
705 * Save incoming source route for use in replies,
706 * to be picked up later by ip_srcroute if the receiver is interested.
707 */
708save_rte(option, dst)
8011f5df 709 u_char *option;
8fb48289
MK
710 struct in_addr dst;
711{
8011f5df 712 unsigned olen;
8fb48289
MK
713 extern ipprintfs;
714
715 olen = option[IPOPT_OLEN];
716 if (olen > sizeof(ip_srcrt) - 1) {
717 if (ipprintfs)
718 printf("save_rte: olen %d\n", olen);
719 return;
720 }
8011f5df 721 bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen);
8fb48289
MK
722 ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
723 ip_srcrt.route[ip_nhops++] = dst;
724}
725
726/*
727 * Retrieve incoming source route for use in replies,
728 * in the same form used by setsockopt.
729 * The first hop is placed before the options, will be removed later.
730 */
731struct mbuf *
732ip_srcroute()
733{
734 register struct in_addr *p, *q;
735 register struct mbuf *m;
736
737 if (ip_nhops == 0)
738 return ((struct mbuf *)0);
13494852
MK
739 m = m_get(M_DONTWAIT, MT_SOOPTS);
740 if (m == 0)
741 return ((struct mbuf *)0);
8fb48289
MK
742 m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1;
743
744 /*
745 * First save first hop for return route
746 */
747 p = &ip_srcrt.route[ip_nhops - 1];
748 *(mtod(m, struct in_addr *)) = *p--;
749
750 /*
751 * Copy option fields and padding (nop) to mbuf.
752 */
753 ip_srcrt.nop = IPOPT_NOP;
754 bcopy((caddr_t)&ip_srcrt, mtod(m, caddr_t) + sizeof(struct in_addr),
755 IPOPT_OFFSET + 1 + 1);
756 q = (struct in_addr *)(mtod(m, caddr_t) +
757 sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1);
758 /*
759 * Record return path as an IP source route,
760 * reversing the path (pointers are now aligned).
761 */
762 while (p >= ip_srcrt.route)
763 *q++ = *p--;
764 return (m);
765}
766
e6dd2097 767/*
4ad99bae
BJ
768 * Strip out IP options, at higher
769 * level protocol in the kernel.
770 * Second argument is buffer to which options
771 * will be moved, and return value is their length.
e6dd2097 772 */
7c08c626 773ip_stripoptions(ip, mopt)
e6dd2097 774 struct ip *ip;
7c08c626 775 struct mbuf *mopt;
e1d82856 776{
e6dd2097
BJ
777 register int i;
778 register struct mbuf *m;
8fb48289 779 register caddr_t opts;
e6dd2097 780 int olen;
e6dd2097
BJ
781
782 olen = (ip->ip_hl<<2) - sizeof (struct ip);
4ad99bae 783 m = dtom(ip);
8fb48289 784 opts = (caddr_t)(ip + 1);
7c08c626
BJ
785 if (mopt) {
786 mopt->m_len = olen;
787 mopt->m_off = MMINOFF;
8fb48289 788 bcopy(opts, mtod(mopt, caddr_t), (unsigned)olen);
7c08c626 789 }
e6dd2097 790 i = m->m_len - (sizeof (struct ip) + olen);
8fb48289 791 bcopy(opts + olen, opts, (unsigned)i);
4aed14e3 792 m->m_len -= olen;
8fb48289 793 ip->ip_hl = sizeof(struct ip) >> 2;
e1d82856 794}
72e4f44e 795
0ecfeefb 796u_char inetctlerrmap[PRC_NCMDS] = {
8fb48289 797 0, 0, 0, 0,
0ecfeefb
SL
798 0, 0, EHOSTDOWN, EHOSTUNREACH,
799 ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
8fb48289
MK
800 EMSGSIZE, EHOSTUNREACH, 0, 0,
801 0, 0, 0, 0,
802 ENOPROTOOPT
72e4f44e
SL
803};
804
8fb48289
MK
805#ifndef IPFORWARDING
806#define IPFORWARDING 1
807#endif
808#ifndef IPSENDREDIRECTS
809#define IPSENDREDIRECTS 1
810#endif
72e4f44e 811int ipprintfs = 0;
8fb48289
MK
812int ipforwarding = IPFORWARDING;
813extern int in_interfaces;
814int ipsendredirects = IPSENDREDIRECTS;
815
72e4f44e
SL
816/*
817 * Forward a packet. If some error occurs return the sender
f223fa7d 818 * an icmp packet. Note we can't always generate a meaningful
8fb48289 819 * icmp message because icmp doesn't have a large enough repertoire
72e4f44e 820 * of codes and types.
c0a9b2bd
MK
821 *
822 * If not forwarding (possibly because we have only a single external
823 * network), just drop the packet. This could be confusing if ipforwarding
824 * was zero but some routing protocol was advancing us as a gateway
825 * to somewhere. However, we must let the routing protocol deal with that.
72e4f44e 826 */
8fb48289 827ip_forward(ip, ifp)
72e4f44e 828 register struct ip *ip;
8fb48289 829 struct ifnet *ifp;
72e4f44e 830{
8fb48289
MK
831 register int error, type = 0, code;
832 register struct sockaddr_in *sin;
f223fa7d 833 struct mbuf *mcopy;
8fb48289 834 struct in_addr dest;
72e4f44e 835
8fb48289 836 dest.s_addr = 0;
72e4f44e
SL
837 if (ipprintfs)
838 printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
839 ip->ip_dst, ip->ip_ttl);
f223fa7d 840 ip->ip_id = htons(ip->ip_id);
8fb48289 841 if (ipforwarding == 0 || in_interfaces <= 1) {
c0a9b2bd 842 ipstat.ips_cantforward++;
72427e98
MK
843#ifdef GATEWAY
844 type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
845 goto sendicmp;
846#else
c0a9b2bd
MK
847 m_freem(dtom(ip));
848 return;
72427e98 849#endif
72e4f44e 850 }
c13e44b4 851 if (ip->ip_ttl <= IPTTLDEC) {
72e4f44e
SL
852 type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
853 goto sendicmp;
854 }
855 ip->ip_ttl -= IPTTLDEC;
67387c9c
SL
856
857 /*
858 * Save at most 64 bytes of the packet in case
859 * we need to generate an ICMP message to the src.
860 */
58bca61d 861 mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64));
72e4f44e 862
8fb48289
MK
863 sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
864 if (ipforward_rt.ro_rt == 0 ||
865 ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
866 if (ipforward_rt.ro_rt) {
867 RTFREE(ipforward_rt.ro_rt);
868 ipforward_rt.ro_rt = 0;
869 }
870 sin->sin_family = AF_INET;
871 sin->sin_addr = ip->ip_dst;
872
873 rtalloc(&ipforward_rt);
874 }
875 /*
876 * If forwarding packet using same interface that it came in on,
877 * perhaps should send a redirect to sender to shortcut a hop.
878 * Only send redirect if source is sending directly to us,
879 * and if packet was not source routed (or has any options).
83dfdaa9
MK
880 * Also, don't send redirect if forwarding using a default route
881 * or a route modfied by a redirect.
8fb48289 882 */
83dfdaa9 883#define satosin(sa) ((struct sockaddr_in *)(sa))
8fb48289 884 if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp &&
fc7b8b1e 885 (ipforward_rt.ro_rt->rt_flags & RTF_DYNAMIC) == 0 &&
83dfdaa9 886 satosin(&ipforward_rt.ro_rt->rt_dst)->sin_addr.s_addr != 0 &&
8fb48289
MK
887 ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) {
888 struct in_ifaddr *ia;
8fb48289
MK
889 u_long src = ntohl(ip->ip_src.s_addr);
890 u_long dst = ntohl(ip->ip_dst.s_addr);
891
892 if ((ia = ifptoia(ifp)) &&
893 (src & ia->ia_subnetmask) == ia->ia_subnet) {
894 if (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY)
895 dest = satosin(&ipforward_rt.ro_rt->rt_gateway)->sin_addr;
896 else
897 dest = ip->ip_dst;
898 /*
899 * If the destination is reached by a route to host,
020b84ae
MK
900 * is on a subnet of a local net, or is directly
901 * on the attached net (!), use host redirect.
8fb48289
MK
902 * (We may be the correct first hop for other subnets.)
903 */
904 type = ICMP_REDIRECT;
905 code = ICMP_REDIRECT_NET;
906 if ((ipforward_rt.ro_rt->rt_flags & RTF_HOST) ||
907 (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) == 0)
908 code = ICMP_REDIRECT_HOST;
909 else for (ia = in_ifaddr; ia = ia->ia_next; )
910 if ((dst & ia->ia_netmask) == ia->ia_net) {
020b84ae
MK
911 if (ia->ia_subnetmask != ia->ia_netmask)
912 code = ICMP_REDIRECT_HOST;
8fb48289
MK
913 break;
914 }
915 if (ipprintfs)
916 printf("redirect (%d) to %x\n", code, dest);
917 }
918 }
919
920 error = ip_output(dtom(ip), (struct mbuf *)0, &ipforward_rt,
f223fa7d 921 IP_FORWARDING);
8fb48289
MK
922 if (error)
923 ipstat.ips_cantforward++;
924 else if (type)
925 ipstat.ips_redirectsent++;
926 else {
67387c9c
SL
927 if (mcopy)
928 m_freem(mcopy);
ac066ae1 929 ipstat.ips_forward++;
72e4f44e 930 return;
67387c9c 931 }
9dfd168a
SL
932 if (mcopy == NULL)
933 return;
67387c9c 934 ip = mtod(mcopy, struct ip *);
8fb48289 935 type = ICMP_UNREACH;
67387c9c
SL
936 switch (error) {
937
8fb48289
MK
938 case 0: /* forwarded, but need redirect */
939 type = ICMP_REDIRECT;
940 /* code set above */
941 break;
942
67387c9c
SL
943 case ENETUNREACH:
944 case ENETDOWN:
d933432a
MK
945 if (in_localaddr(ip->ip_dst))
946 code = ICMP_UNREACH_HOST;
947 else
948 code = ICMP_UNREACH_NET;
67387c9c
SL
949 break;
950
951 case EMSGSIZE:
72e4f44e 952 code = ICMP_UNREACH_NEEDFRAG;
67387c9c
SL
953 break;
954
955 case EPERM:
956 code = ICMP_UNREACH_PORT;
957 break;
958
959 case ENOBUFS:
960 type = ICMP_SOURCEQUENCH;
961 break;
962
963 case EHOSTDOWN:
964 case EHOSTUNREACH:
965 code = ICMP_UNREACH_HOST;
966 break;
967 }
72e4f44e 968sendicmp:
c45e83d2 969 icmp_error(ip, type, code, ifp, dest);
72e4f44e 970}