don't put ESC-9's at top of page
[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 *
773dfe90 6 * @(#)ip_input.c 6.15 (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 */
72e4f44e
SL
180 if (hlen > sizeof (struct ip) && ip_dooptions(ip))
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 */
498ip_dooptions(ip)
499 struct ip *ip;
e1d82856 500{
e6dd2097 501 register u_char *cp;
8fb48289 502 int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB;
d52566dd 503 register struct ip_timestamp *ipt;
8fb48289
MK
504 register struct in_ifaddr *ia;
505 struct in_addr *sin;
506 n_time ntime;
e6dd2097
BJ
507
508 cp = (u_char *)(ip + 1);
509 cnt = (ip->ip_hl << 2) - sizeof (struct ip);
510 for (; cnt > 0; cnt -= optlen, cp += optlen) {
8fb48289 511 opt = cp[IPOPT_OPTVAL];
e6dd2097
BJ
512 if (opt == IPOPT_EOL)
513 break;
514 if (opt == IPOPT_NOP)
515 optlen = 1;
942169f7 516 else {
8fb48289
MK
517 optlen = cp[IPOPT_OLEN];
518 if (optlen <= 0 || optlen > cnt) {
519 code = &cp[IPOPT_OLEN] - (u_char *)ip;
36bb5f94 520 goto bad;
8fb48289 521 }
942169f7 522 }
e6dd2097 523 switch (opt) {
e1d82856 524
e6dd2097
BJ
525 default:
526 break;
e1d82856 527
4ad99bae
BJ
528 /*
529 * Source routing with record.
530 * Find interface with current destination address.
531 * If none on this machine then drop if strictly routed,
532 * or do nothing if loosely routed.
533 * Record interface address and bring up next address
534 * component. If strictly routed make sure next
535 * address on directly accessible net.
536 */
e6dd2097 537 case IPOPT_LSRR:
a71ece0a 538 case IPOPT_SSRR:
8fb48289
MK
539 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
540 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
541 goto bad;
542 }
543 ipaddr.sin_addr = ip->ip_dst;
544 ia = (struct in_ifaddr *)
545 ifa_ifwithaddr((struct sockaddr *)&ipaddr);
546 if (ia == 0) {
547 if (opt == IPOPT_SSRR) {
548 type = ICMP_UNREACH;
549 code = ICMP_UNREACH_SRCFAIL;
4ad99bae 550 goto bad;
8fb48289
MK
551 }
552 /*
553 * Loose routing, and not at next destination
554 * yet; nothing to do except forward.
555 */
4ad99bae 556 break;
e6dd2097 557 }
8fb48289
MK
558 off--; /* 0 origin */
559 if (off > optlen - sizeof(struct in_addr)) {
560 /*
561 * End of source route. Should be for us.
562 */
563 save_rte(cp, ip->ip_src);
4ad99bae 564 break;
8fb48289
MK
565 }
566 /*
567 * locate outgoing interface
568 */
569 bcopy(cp + off, (caddr_t)&ipaddr.sin_addr,
570 sizeof(ipaddr.sin_addr));
571 if ((opt == IPOPT_SSRR &&
572 in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) ||
573 (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
574 type = ICMP_UNREACH;
575 code = ICMP_UNREACH_SRCFAIL;
4ad99bae 576 goto bad;
8fb48289
MK
577 }
578 ip->ip_dst = ipaddr.sin_addr;
579 bcopy(&(IA_SIN(ia)->sin_addr), cp + off,
580 sizeof(struct in_addr));
581 cp[IPOPT_OFFSET] += sizeof(struct in_addr);
582 break;
583
584 case IPOPT_RR:
585 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
586 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
587 goto bad;
588 }
589 /*
590 * If no space remains, ignore.
591 */
592 off--; /* 0 origin */
593 if (off > optlen - sizeof(struct in_addr))
594 break;
595 bcopy(cp + off, (caddr_t)ipaddr.sin_addr,
596 sizeof(ipaddr.sin_addr));
597 /*
598 * locate outgoing interface
599 */
600 if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
601 type = ICMP_UNREACH;
602 code = ICMP_UNREACH_SRCFAIL;
603 goto bad;
604 }
605 bcopy(&(IA_SIN(ia)->sin_addr), cp + off,
606 sizeof(struct in_addr));
607 cp[IPOPT_OFFSET] += sizeof(struct in_addr);
e6dd2097
BJ
608 break;
609
610 case IPOPT_TS:
72e4f44e 611 code = cp - (u_char *)ip;
d52566dd
BJ
612 ipt = (struct ip_timestamp *)cp;
613 if (ipt->ipt_len < 5)
e6dd2097 614 goto bad;
d52566dd
BJ
615 if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
616 if (++ipt->ipt_oflw == 0)
e6dd2097 617 goto bad;
e6dd2097
BJ
618 break;
619 }
8fb48289 620 sin = (struct in_addr *)(cp+cp[IPOPT_OFFSET]-1);
d52566dd 621 switch (ipt->ipt_flg) {
e1d82856 622
e6dd2097
BJ
623 case IPOPT_TS_TSONLY:
624 break;
e1d82856 625
e6dd2097 626 case IPOPT_TS_TSANDADDR:
8fb48289
MK
627 if (ipt->ipt_ptr + sizeof(n_time) +
628 sizeof(struct in_addr) > ipt->ipt_len)
e6dd2097 629 goto bad;
f223fa7d 630 if (in_ifaddr == 0)
ee787340 631 goto bad; /* ??? */
8fb48289
MK
632 bcopy((caddr_t)&IA_SIN(in_ifaddr)->sin_addr,
633 (caddr_t)sin, sizeof(struct in_addr));
634 sin++;
e6dd2097
BJ
635 break;
636
637 case IPOPT_TS_PRESPEC:
8fb48289
MK
638 bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
639 sizeof(struct in_addr));
f223fa7d 640 if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
4ad99bae 641 continue;
8fb48289
MK
642 if (ipt->ipt_ptr + sizeof(n_time) +
643 sizeof(struct in_addr) > ipt->ipt_len)
e6dd2097 644 goto bad;
8fb48289 645 ipt->ipt_ptr += sizeof(struct in_addr);
e1d82856
BJ
646 break;
647
648 default:
e6dd2097 649 goto bad;
e1d82856 650 }
8fb48289
MK
651 ntime = iptime();
652 bcopy((caddr_t)&ntime, (caddr_t)sin, sizeof(n_time));
653 ipt->ipt_ptr += sizeof(n_time);
e6dd2097 654 }
e1d82856 655 }
72e4f44e 656 return (0);
e6dd2097 657bad:
72e4f44e
SL
658 icmp_error(ip, type, code);
659 return (1);
e1d82856
BJ
660}
661
8fb48289
MK
662/*
663 * Given address of next destination (final or next hop),
664 * return internet address info of interface to be used to get there.
665 */
666struct in_ifaddr *
667ip_rtaddr(dst)
668 struct in_addr dst;
669{
670 register struct sockaddr_in *sin;
671 register struct in_ifaddr *ia;
672
673 sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
674
675 if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
676 if (ipforward_rt.ro_rt) {
677 RTFREE(ipforward_rt.ro_rt);
678 ipforward_rt.ro_rt = 0;
679 }
680 sin->sin_family = AF_INET;
681 sin->sin_addr = dst;
682
683 rtalloc(&ipforward_rt);
684 }
685 if (ipforward_rt.ro_rt == 0)
686 return ((struct in_ifaddr *)0);
687 /*
688 * Find address associated with outgoing interface.
689 */
690 for (ia = in_ifaddr; ia; ia = ia->ia_next)
691 if (ia->ia_ifp == ipforward_rt.ro_rt->rt_ifp)
692 break;
693 return (ia);
694}
695
696/*
697 * Save incoming source route for use in replies,
698 * to be picked up later by ip_srcroute if the receiver is interested.
699 */
700save_rte(option, dst)
701 caddr_t option;
702 struct in_addr dst;
703{
704 int olen;
705 extern ipprintfs;
706
707 olen = option[IPOPT_OLEN];
708 if (olen > sizeof(ip_srcrt) - 1) {
709 if (ipprintfs)
710 printf("save_rte: olen %d\n", olen);
711 return;
712 }
713 bcopy(option, (caddr_t)ip_srcrt.srcopt, olen);
714 ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
715 ip_srcrt.route[ip_nhops++] = dst;
716}
717
718/*
719 * Retrieve incoming source route for use in replies,
720 * in the same form used by setsockopt.
721 * The first hop is placed before the options, will be removed later.
722 */
723struct mbuf *
724ip_srcroute()
725{
726 register struct in_addr *p, *q;
727 register struct mbuf *m;
728
729 if (ip_nhops == 0)
730 return ((struct mbuf *)0);
731 m = m_get(M_WAIT, MT_SOOPTS);
732 m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1;
733
734 /*
735 * First save first hop for return route
736 */
737 p = &ip_srcrt.route[ip_nhops - 1];
738 *(mtod(m, struct in_addr *)) = *p--;
739
740 /*
741 * Copy option fields and padding (nop) to mbuf.
742 */
743 ip_srcrt.nop = IPOPT_NOP;
744 bcopy((caddr_t)&ip_srcrt, mtod(m, caddr_t) + sizeof(struct in_addr),
745 IPOPT_OFFSET + 1 + 1);
746 q = (struct in_addr *)(mtod(m, caddr_t) +
747 sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1);
748 /*
749 * Record return path as an IP source route,
750 * reversing the path (pointers are now aligned).
751 */
752 while (p >= ip_srcrt.route)
753 *q++ = *p--;
754 return (m);
755}
756
e6dd2097 757/*
4ad99bae
BJ
758 * Strip out IP options, at higher
759 * level protocol in the kernel.
760 * Second argument is buffer to which options
761 * will be moved, and return value is their length.
e6dd2097 762 */
7c08c626 763ip_stripoptions(ip, mopt)
e6dd2097 764 struct ip *ip;
7c08c626 765 struct mbuf *mopt;
e1d82856 766{
e6dd2097
BJ
767 register int i;
768 register struct mbuf *m;
8fb48289 769 register caddr_t opts;
e6dd2097 770 int olen;
e6dd2097
BJ
771
772 olen = (ip->ip_hl<<2) - sizeof (struct ip);
4ad99bae 773 m = dtom(ip);
8fb48289 774 opts = (caddr_t)(ip + 1);
7c08c626
BJ
775 if (mopt) {
776 mopt->m_len = olen;
777 mopt->m_off = MMINOFF;
8fb48289 778 bcopy(opts, mtod(mopt, caddr_t), (unsigned)olen);
7c08c626 779 }
e6dd2097 780 i = m->m_len - (sizeof (struct ip) + olen);
8fb48289 781 bcopy(opts + olen, opts, (unsigned)i);
4aed14e3 782 m->m_len -= olen;
8fb48289 783 ip->ip_hl = sizeof(struct ip) >> 2;
e1d82856 784}
72e4f44e 785
0ecfeefb 786u_char inetctlerrmap[PRC_NCMDS] = {
8fb48289 787 0, 0, 0, 0,
0ecfeefb
SL
788 0, 0, EHOSTDOWN, EHOSTUNREACH,
789 ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
8fb48289
MK
790 EMSGSIZE, EHOSTUNREACH, 0, 0,
791 0, 0, 0, 0,
792 ENOPROTOOPT
72e4f44e
SL
793};
794
8fb48289
MK
795#ifndef IPFORWARDING
796#define IPFORWARDING 1
797#endif
798#ifndef IPSENDREDIRECTS
799#define IPSENDREDIRECTS 1
800#endif
72e4f44e 801int ipprintfs = 0;
8fb48289
MK
802int ipforwarding = IPFORWARDING;
803extern int in_interfaces;
804int ipsendredirects = IPSENDREDIRECTS;
805
72e4f44e
SL
806/*
807 * Forward a packet. If some error occurs return the sender
f223fa7d 808 * an icmp packet. Note we can't always generate a meaningful
8fb48289 809 * icmp message because icmp doesn't have a large enough repertoire
72e4f44e
SL
810 * of codes and types.
811 */
8fb48289 812ip_forward(ip, ifp)
72e4f44e 813 register struct ip *ip;
8fb48289 814 struct ifnet *ifp;
72e4f44e 815{
8fb48289
MK
816 register int error, type = 0, code;
817 register struct sockaddr_in *sin;
f223fa7d 818 struct mbuf *mcopy;
8fb48289 819 struct in_addr dest;
72e4f44e 820
8fb48289
MK
821#ifdef lint
822 dest.s_addr = 0;
823#endif
72e4f44e
SL
824 if (ipprintfs)
825 printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
826 ip->ip_dst, ip->ip_ttl);
f223fa7d 827 ip->ip_id = htons(ip->ip_id);
8fb48289 828 if (ipforwarding == 0 || in_interfaces <= 1) {
72e4f44e
SL
829 /* can't tell difference between net and host */
830 type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
831 goto sendicmp;
832 }
833 if (ip->ip_ttl < IPTTLDEC) {
834 type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
835 goto sendicmp;
836 }
837 ip->ip_ttl -= IPTTLDEC;
67387c9c
SL
838
839 /*
840 * Save at most 64 bytes of the packet in case
841 * we need to generate an ICMP message to the src.
842 */
348901af 843 mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64));
72e4f44e 844
8fb48289
MK
845 sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
846 if (ipforward_rt.ro_rt == 0 ||
847 ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
848 if (ipforward_rt.ro_rt) {
849 RTFREE(ipforward_rt.ro_rt);
850 ipforward_rt.ro_rt = 0;
851 }
852 sin->sin_family = AF_INET;
853 sin->sin_addr = ip->ip_dst;
854
855 rtalloc(&ipforward_rt);
856 }
857 /*
858 * If forwarding packet using same interface that it came in on,
859 * perhaps should send a redirect to sender to shortcut a hop.
860 * Only send redirect if source is sending directly to us,
861 * and if packet was not source routed (or has any options).
862 */
863 if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp &&
864 ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) {
865 struct in_ifaddr *ia;
866 extern struct in_ifaddr *ifptoia();
867 u_long src = ntohl(ip->ip_src.s_addr);
868 u_long dst = ntohl(ip->ip_dst.s_addr);
869
870 if ((ia = ifptoia(ifp)) &&
871 (src & ia->ia_subnetmask) == ia->ia_subnet) {
872 if (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY)
873 dest = satosin(&ipforward_rt.ro_rt->rt_gateway)->sin_addr;
874 else
875 dest = ip->ip_dst;
876 /*
877 * If the destination is reached by a route to host,
878 * is directly on the attached net (!),
879 * or if the destination is on a subnet of a local net
880 * not known to the source net, use host redirect.
881 * (We may be the correct first hop for other subnets.)
882 */
883 type = ICMP_REDIRECT;
884 code = ICMP_REDIRECT_NET;
885 if ((ipforward_rt.ro_rt->rt_flags & RTF_HOST) ||
886 (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) == 0)
887 code = ICMP_REDIRECT_HOST;
888 else for (ia = in_ifaddr; ia = ia->ia_next; )
889 if ((dst & ia->ia_netmask) == ia->ia_net) {
890 if ((src & ia->ia_netmask) != ia->ia_net)
891 code = ICMP_REDIRECT_HOST;
892 break;
893 }
894 if (ipprintfs)
895 printf("redirect (%d) to %x\n", code, dest);
896 }
897 }
898
899 error = ip_output(dtom(ip), (struct mbuf *)0, &ipforward_rt,
f223fa7d 900 IP_FORWARDING);
8fb48289
MK
901 if (error)
902 ipstat.ips_cantforward++;
903 else if (type)
904 ipstat.ips_redirectsent++;
905 else {
67387c9c
SL
906 if (mcopy)
907 m_freem(mcopy);
ac066ae1 908 ipstat.ips_forward++;
72e4f44e 909 return;
67387c9c 910 }
9dfd168a
SL
911 if (mcopy == NULL)
912 return;
67387c9c 913 ip = mtod(mcopy, struct ip *);
8fb48289 914 type = ICMP_UNREACH;
67387c9c
SL
915 switch (error) {
916
8fb48289
MK
917 case 0: /* forwarded, but need redirect */
918 type = ICMP_REDIRECT;
919 /* code set above */
920 break;
921
67387c9c
SL
922 case ENETUNREACH:
923 case ENETDOWN:
72e4f44e 924 code = ICMP_UNREACH_NET;
67387c9c
SL
925 break;
926
927 case EMSGSIZE:
72e4f44e 928 code = ICMP_UNREACH_NEEDFRAG;
67387c9c
SL
929 break;
930
931 case EPERM:
932 code = ICMP_UNREACH_PORT;
933 break;
934
935 case ENOBUFS:
936 type = ICMP_SOURCEQUENCH;
937 break;
938
939 case EHOSTDOWN:
940 case EHOSTUNREACH:
941 code = ICMP_UNREACH_HOST;
942 break;
943 }
72e4f44e 944sendicmp:
8fb48289 945 icmp_error(ip, type, code, dest);
72e4f44e 946}