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