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