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