source: rtems/cpukit/libnetworking/netinet/ip_input.c @ 0b07d87

4.104.114.84.95
Last change on this file since 0b07d87 was 0b07d87, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/28/07 at 04:40:36

2007-03-28 Ralf Corsépius <ralf.corsepius@…>

  • libnetworking/netinet/ip_input.c: Eliminate P(). Change "int next" to "int32_t next" for 16bit targets.
  • Property mode set to 100644
File size: 35.4 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *      @(#)ip_input.c  8.2 (Berkeley) 1/4/94
30 * $Id$
31 *      $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $
32 */
33
34#define _IP_VHL
35
36#include "opt_ipfw.h"
37
38#include <stddef.h>
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/malloc.h>
43#include <sys/mbuf.h>
44#include <sys/domain.h>
45#include <sys/protosw.h>
46#include <sys/socket.h>
47#include <sys/errno.h>
48#include <sys/time.h>
49#include <sys/kernel.h>
50#include <sys/syslog.h>
51#include <sys/sysctl.h>
52
53#include <net/if.h>
54#include <net/if_dl.h>
55#include <net/route.h>
56#include <net/netisr.h>
57
58#include <netinet/in.h>
59#include <netinet/in_systm.h>
60#include <netinet/in_var.h>
61#include <netinet/ip.h>
62#include <netinet/in_pcb.h>
63#include <netinet/in_var.h>
64#include <netinet/ip_var.h>
65#include <netinet/ip_icmp.h>
66#include <machine/in_cksum.h>
67
68#include <sys/socketvar.h>
69
70#ifdef IPFIREWALL
71#include <netinet/ip_fw.h>
72#endif
73
74int rsvp_on = 0;
75static int ip_rsvp_on;
76struct socket *ip_rsvpd;
77
78int     ipforwarding = 0;
79SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW,
80        &ipforwarding, 0, "");
81
82static int      ipsendredirects = 1; /* XXX */
83SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
84        &ipsendredirects, 0, "");
85
86int     ip_defttl = IPDEFTTL;
87SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
88        &ip_defttl, 0, "");
89
90static int      ip_dosourceroute = 0;
91SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
92        &ip_dosourceroute, 0, "");
93
94static int      ip_acceptsourceroute = 0;
95SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
96        CTLFLAG_RW, &ip_acceptsourceroute, 0, "");
97#ifdef DIAGNOSTIC
98static int      ipprintfs = 0;
99#endif
100
101extern  struct domain inetdomain;
102extern  struct protosw inetsw[];
103u_char  ip_protox[IPPROTO_MAX];
104static int      ipqmaxlen = IFQ_MAXLEN;
105struct  in_ifaddr *in_ifaddr;                   /* first inet address */
106struct  ifqueue ipintrq;
107SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RD,
108        &ipintrq.ifq_maxlen, 0, "");
109SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
110        &ipintrq.ifq_drops, 0, "");
111
112struct ipstat ipstat;
113
114/* Packet reassembly stuff */
115#define IPREASS_NHASH_LOG2      6
116#define IPREASS_NHASH           (1 << IPREASS_NHASH_LOG2)
117#define IPREASS_HMASK           (IPREASS_NHASH - 1)
118#define IPREASS_HASH(x,y) \
119        (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
120
121static struct ipq ipq[IPREASS_NHASH];
122static int    nipq = 0;         /* total # of reass queues */
123static int    maxnipq;
124
125#ifdef IPCTL_DEFMTU
126SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
127        &ip_mtu, 0, "");
128#endif
129
130#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
131#undef COMPAT_IPFW
132#define COMPAT_IPFW 1
133#else
134#undef COMPAT_IPFW
135#endif
136
137#ifdef COMPAT_IPFW
138/* Firewall hooks */
139ip_fw_chk_t *ip_fw_chk_ptr;
140ip_fw_ctl_t *ip_fw_ctl_ptr;
141
142/* IP Network Address Translation (NAT) hooks */
143ip_nat_t *ip_nat_ptr;
144ip_nat_ctl_t *ip_nat_ctl_ptr;
145#endif
146
147/*
148 * We need to save the IP options in case a protocol wants to respond
149 * to an incoming packet over the same route if the packet got here
150 * using IP source routing.  This allows connection establishment and
151 * maintenance when the remote end is on a network that is not known
152 * to us.
153 */
154static int      ip_nhops = 0;
155static  struct ip_srcrt {
156        struct  in_addr dst;                    /* final destination */
157        char    nop;                            /* one NOP to align */
158        char    srcopt[IPOPT_OFFSET + 1];       /* OPTVAL, OLEN and OFFSET */
159        struct  in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
160} ip_srcrt;
161
162#ifdef IPDIVERT
163/*
164 * Shared variable between ip_input() and ip_reass() to communicate
165 * about which packets, once assembled from fragments, get diverted,
166 * and to which port.
167 */
168static u_short  frag_divert_port;
169#endif
170
171static void save_rte(u_char *, struct in_addr);
172static void      ip_deq(struct ipasfrag *);
173static int       ip_dooptions(struct mbuf *);
174static void      ip_enq(struct ipasfrag *, struct ipasfrag *);
175static void      ip_forward(struct mbuf *, int);
176static void      ip_freef(struct ipq *);
177static struct ip *
178         ip_reass(struct ipasfrag *, struct ipq *, struct ipq *);
179static struct in_ifaddr *
180         ip_rtaddr(struct in_addr);
181void    ipintr(void);
182/*
183 * IP initialization: fill in IP protocol switch table.
184 * All protocols not implemented in kernel go to raw IP protocol handler.
185 */
186void
187ip_init()
188{
189        register struct protosw *pr;
190        register int i;
191
192        pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
193        if (pr == 0)
194                panic("ip_init");
195        for (i = 0; i < IPPROTO_MAX; i++)
196                ip_protox[i] = pr - inetsw;
197        for (pr = inetdomain.dom_protosw;
198            pr < inetdomain.dom_protoswNPROTOSW; pr++)
199                if (pr->pr_domain->dom_family == PF_INET &&
200                    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
201                        ip_protox[pr->pr_protocol] = pr - inetsw;
202
203        for (i = 0; i < IPREASS_NHASH; i++)
204            ipq[i].next = ipq[i].prev = &ipq[i];
205
206        maxnipq = nmbclusters/4;
207
208        ip_id = rtems_bsdnet_seconds_since_boot() & 0xffff;
209        ipintrq.ifq_maxlen = ipqmaxlen;
210#ifdef IPFIREWALL
211        ip_fw_init();
212#endif
213#ifdef IPNAT
214        ip_nat_init();
215#endif
216
217}
218
219static struct   sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
220static struct   route ipforward_rt;
221
222/*
223 * Ip input routine.  Checksum and byte swap header.  If fragmented
224 * try to reassemble.  Process options.  Pass to next level.
225 */
226void
227ip_input(struct mbuf *m)
228{
229        struct ip *ip = NULL;
230        struct ipq *fp;
231        struct in_ifaddr *ia = NULL;
232        int    i, hlen;
233        u_short sum;
234
235#ifdef  DIAGNOSTIC
236        if ((m->m_flags & M_PKTHDR) == 0)
237                panic("ip_input no HDR");
238#endif
239        /*
240         * If no IP addresses have been set yet but the interfaces
241         * are receiving, can't do anything with incoming packets yet.
242         */
243        if (in_ifaddr == NULL)
244                goto bad;
245        ipstat.ips_total++;
246
247        if (m->m_pkthdr.len < sizeof(struct ip))
248                goto tooshort;
249
250#if defined(DIAGNOSTIC) && defined(ORIGINAL_FREEBSD_CODE)
251        if (m->m_len < sizeof(struct ip))
252                panic("ipintr mbuf too short");
253#endif
254
255        if (m->m_len < sizeof (struct ip) &&
256            (m = m_pullup(m, sizeof (struct ip))) == NULL) {
257                ipstat.ips_toosmall++;
258                return;
259        }
260        ip = mtod(m, struct ip *);
261
262        if (IP_VHL_V(ip->ip_vhl) != IPVERSION) {
263                ipstat.ips_badvers++;
264                goto bad;
265        }
266
267        hlen = IP_VHL_HL(ip->ip_vhl) << 2;
268        if (hlen < sizeof(struct ip)) { /* minimum header length */
269                ipstat.ips_badhlen++;
270                goto bad;
271        }
272        if (hlen > m->m_len) {
273                if ((m = m_pullup(m, hlen)) == NULL) {
274                        ipstat.ips_badhlen++;
275                        return;
276                }
277                ip = mtod(m, struct ip *);
278        }
279        if (hlen == sizeof(struct ip)) {
280                sum = in_cksum_hdr(ip);
281        } else {
282                sum = in_cksum(m, hlen);
283        }
284        if (sum) {
285                ipstat.ips_badsum++;
286                goto bad;
287        }
288
289        /*
290         * Convert fields to host representation.
291         */
292        NTOHS(ip->ip_len);
293        if (ip->ip_len < hlen) {
294                ipstat.ips_badlen++;
295                goto bad;
296        }
297        NTOHS(ip->ip_id);
298        NTOHS(ip->ip_off);
299
300        /*
301         * Check that the amount of data in the buffers
302         * is as at least much as the IP header would have us expect.
303         * Trim mbufs if longer than we expect.
304         * Drop packet if shorter than we expect.
305         */
306        if (m->m_pkthdr.len < ip->ip_len) {
307tooshort:
308                ipstat.ips_tooshort++;
309                goto bad;
310        }
311        if (m->m_pkthdr.len > ip->ip_len) {
312                if (m->m_len == m->m_pkthdr.len) {
313                        m->m_len = ip->ip_len;
314                        m->m_pkthdr.len = ip->ip_len;
315                } else
316                        m_adj(m, ip->ip_len - m->m_pkthdr.len);
317        }
318        /*
319         * IpHack's section.
320         * Right now when no processing on packet has done
321         * and it is still fresh out of network we do our black
322         * deals with it.
323         * - Firewall: deny/allow/divert
324         * - Xlate: translate packet's addr/port (NAT).
325         * - Wrap: fake packet's addr/port <unimpl.>
326         * - Encapsulate: put it in another IP and send out. <unimp.>
327         */
328
329#ifdef COMPAT_IPFW
330        if (ip_fw_chk_ptr) {
331#ifdef IPDIVERT
332                u_short port;
333
334                port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, ip_divert_ignore, &m);
335                ip_divert_ignore = 0;
336                if (port) {                     /* Divert packet */
337                        frag_divert_port = port;
338                        goto ours;
339                }
340#else
341                /* If ipfw says divert, we have to just drop packet */
342                if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, 0, &m)) {
343                        m_freem(m);
344                        m = NULL;
345                }
346#endif
347                if (!m)
348                        return;
349        }
350
351        if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN))
352                return;
353#endif
354
355        /*
356         * Process options and, if not destined for us,
357         * ship it on.  ip_dooptions returns 1 when an
358         * error was detected (causing an icmp message
359         * to be sent and the original packet to be freed).
360         */
361        ip_nhops = 0;           /* for source routed packets */
362        if (hlen > sizeof (struct ip) && ip_dooptions(m))
363                return;
364
365        /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
366         * matter if it is destined to another node, or whether it is
367         * a multicast one, RSVP wants it! and prevents it from being forwarded
368         * anywhere else. Also checks if the rsvp daemon is running before
369         * grabbing the packet.
370         */
371        if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
372                goto ours;
373
374        /*
375         * Check our list of addresses, to see if the packet is for us.
376         */
377        for (ia = in_ifaddr; ia; ia = ia->ia_next) {
378#define satosin(sa)     ((struct sockaddr_in *)(sa))
379
380                if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
381                        goto ours;
382#ifdef BOOTP_COMPAT
383                if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
384                        goto ours;
385#endif
386                if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) {
387                        if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
388                            ip->ip_dst.s_addr)
389                                goto ours;
390                        if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
391                                goto ours;
392                }
393        }
394        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
395                struct in_multi *inm;
396                if (ip_mrouter) {
397                        /*
398                         * If we are acting as a multicast router, all
399                         * incoming multicast packets are passed to the
400                         * kernel-level multicast forwarding function.
401                         * The packet is returned (relatively) intact; if
402                         * ip_mforward() returns a non-zero value, the packet
403                         * must be discarded, else it may be accepted below.
404                         *
405                         * (The IP ident field is put in the same byte order
406                         * as expected when ip_mforward() is called from
407                         * ip_output().)
408                         */
409                        ip->ip_id = htons(ip->ip_id);
410                        if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
411                                ipstat.ips_cantforward++;
412                                m_freem(m);
413                                return;
414                        }
415                        ip->ip_id = ntohs(ip->ip_id);
416
417                        /*
418                         * The process-level routing daemon needs to receive
419                         * all multicast IGMP packets, whether or not this
420                         * host belongs to their destination groups.
421                         */
422                        if (ip->ip_p == IPPROTO_IGMP)
423                                goto ours;
424                        ipstat.ips_forward++;
425                }
426                /*
427                 * See if we belong to the destination multicast group on the
428                 * arrival interface.
429                 */
430                IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
431                if (inm == NULL) {
432                        ipstat.ips_cantforward++;
433                        m_freem(m);
434                        return;
435                }
436                goto ours;
437        }
438        if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
439                goto ours;
440        if (ip->ip_dst.s_addr == INADDR_ANY)
441                goto ours;
442
443        /*
444         * Not for us; forward if possible and desirable.
445         */
446        if (ipforwarding == 0) {
447                ipstat.ips_cantforward++;
448                m_freem(m);
449        } else {
450                ip_forward(m, 0);
451        }
452        return;
453
454ours:
455
456        /*
457         * If offset or IP_MF are set, must reassemble.
458         * Otherwise, nothing need be done.
459         * (We could look in the reassembly queue to see
460         * if the packet was previously fragmented,
461         * but it's not worth the time; just let them time out.)
462         */
463        if (ip->ip_off &~ (IP_DF | IP_RF)) {
464                if (m->m_flags & M_EXT) {               /* XXX */
465                        if ((m = m_pullup(m, sizeof (struct ip))) == 0) {
466                                ipstat.ips_toosmall++;
467#ifdef IPDIVERT
468                                frag_divert_port = 0;
469#endif
470                                return;
471                        }
472                        ip = mtod(m, struct ip *);
473                }
474                sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
475                /*
476                 * Look for queue of fragments
477                 * of this datagram.
478                 */
479                for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next)
480                        if (ip->ip_id == fp->ipq_id &&
481                            ip->ip_src.s_addr == fp->ipq_src.s_addr &&
482                            ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
483                            ip->ip_p == fp->ipq_p)
484                                goto found;
485
486                fp = 0;
487
488                /* check if there's a place for the new queue */
489                if (nipq > maxnipq) {
490                    /*
491                     * drop something from the tail of the current queue
492                     * before proceeding further
493                     */
494                    if (ipq[sum].prev == &ipq[sum]) {   /* gak */
495                        for (i = 0; i < IPREASS_NHASH; i++) {
496                            if (ipq[i].prev != &ipq[i]) {
497                                ip_freef(ipq[i].prev);
498                                break;
499                            }
500                        }
501                    } else
502                        ip_freef(ipq[sum].prev);
503                }
504found:
505                /*
506                 * Adjust ip_len to not reflect header,
507                 * set ip_mff if more fragments are expected,
508                 * convert offset of this to bytes.
509                 */
510                ip->ip_len -= hlen;
511                ((struct ipasfrag *)ip)->ipf_mff &= ~1;
512                if (ip->ip_off & IP_MF)
513                        ((struct ipasfrag *)ip)->ipf_mff |= 1;
514                ip->ip_off <<= 3;
515
516                /*
517                 * If datagram marked as having more fragments
518                 * or if this is not the first fragment,
519                 * attempt reassembly; if it succeeds, proceed.
520                 */
521                if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
522                        ipstat.ips_fragments++;
523                        ip = ip_reass((struct ipasfrag *)ip, fp, &ipq[sum]);
524                        if (ip == 0)
525                                return;
526                        ipstat.ips_reassembled++;
527                        m = dtom(ip);
528#ifdef IPDIVERT
529                        if (frag_divert_port) {
530                                ip->ip_len += hlen;
531                                HTONS(ip->ip_len);
532                                HTONS(ip->ip_off);
533                                HTONS(ip->ip_id);
534                                ip->ip_sum = 0;
535                                ip->ip_sum = in_cksum_hdr(ip);
536                                NTOHS(ip->ip_id);
537                                NTOHS(ip->ip_off);
538                                NTOHS(ip->ip_len);
539                                ip->ip_len -= hlen;
540                        }
541#endif
542                } else
543                        if (fp)
544                                ip_freef(fp);
545        } else
546                ip->ip_len -= hlen;
547
548#ifdef IPDIVERT
549        /*
550         * Divert reassembled packets to the divert protocol if required
551         */
552        if (frag_divert_port) {
553                ipstat.ips_delivered++;
554                ip_divert_port = frag_divert_port;
555                frag_divert_port = 0;
556                (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen);
557                return;
558        }
559
560        /* Don't let packets divert themselves */
561        if (ip->ip_p == IPPROTO_DIVERT) {
562                ipstat.ips_noproto++;
563                goto bad;
564        }
565#endif
566
567        /*
568         * Switch out to protocol's input routine.
569         */
570        ipstat.ips_delivered++;
571        (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
572        return;
573bad:
574        m_freem(m);
575}
576
577/*
578 * IP software interrupt routine - to go away sometime soon
579 */
580void
581ipintr(void)
582{
583        int s;
584        struct mbuf *m;
585
586        while(1) {
587                s = splimp();
588                IF_DEQUEUE(&ipintrq, m);
589                splx(s);
590                if (m == 0)
591                        return;
592                ip_input(m);
593        }
594}
595
596NETISR_SET(NETISR_IP, ipintr);
597 
598/*
599 * Take incoming datagram fragment and try to
600 * reassemble it into whole datagram.  If a chain for
601 * reassembly of this datagram already exists, then it
602 * is given as fp; otherwise have to make a chain.
603 */
604static struct ip *
605ip_reass(ip, fp, where)
606        register struct ipasfrag *ip;
607        register struct ipq *fp;
608        struct   ipq    *where;
609{
610        register struct mbuf *m = dtom(ip);
611        register struct ipasfrag *q;
612        struct mbuf *t;
613        int hlen = ip->ip_hl << 2;
614        int i;
615        int32_t next;
616
617        /*
618         * Presence of header sizes in mbufs
619         * would confuse code below.
620         */
621        m->m_data += hlen;
622        m->m_len -= hlen;
623
624        /*
625         * If first fragment to arrive, create a reassembly queue.
626         */
627        if (fp == 0) {
628                if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
629                        goto dropfrag;
630                fp = mtod(t, struct ipq *);
631                insque(fp, where);
632                nipq++;
633                fp->ipq_ttl = IPFRAGTTL;
634                fp->ipq_p = ip->ip_p;
635                fp->ipq_id = ip->ip_id;
636                fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
637                fp->ipq_src = ((struct ip *)ip)->ip_src;
638                fp->ipq_dst = ((struct ip *)ip)->ip_dst;
639#ifdef IPDIVERT
640                fp->ipq_divert = 0;
641#endif
642                q = (struct ipasfrag *)fp;
643                goto insert;
644        }
645
646        /*
647         * Find a segment which begins after this one does.
648         */
649        for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
650                if (q->ip_off > ip->ip_off)
651                        break;
652
653        /*
654         * If there is a preceding segment, it may provide some of
655         * our data already.  If so, drop the data from the incoming
656         * segment.  If it provides all of our data, drop us.
657         */
658        if (q->ipf_prev != (struct ipasfrag *)fp) {
659                i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
660                if (i > 0) {
661                        if (i >= ip->ip_len)
662                                goto dropfrag;
663                        m_adj(dtom(ip), i);
664                        ip->ip_off += i;
665                        ip->ip_len -= i;
666                }
667        }
668
669        /*
670         * While we overlap succeeding segments trim them or,
671         * if they are completely covered, dequeue them.
672         */
673        while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
674                struct mbuf *m0;
675
676                i = (ip->ip_off + ip->ip_len) - q->ip_off;
677                if (i < q->ip_len) {
678                        q->ip_len -= i;
679                        q->ip_off += i;
680                        m_adj(dtom(q), i);
681                        break;
682                }
683                m0 = dtom(q);
684                q = q->ipf_next;
685                ip_deq(q->ipf_prev);
686                m_freem(m0);
687        }
688
689insert:
690
691#ifdef IPDIVERT
692        /*
693         * Any fragment diverting causes the whole packet to divert
694         */
695        if (frag_divert_port != 0)
696                fp->ipq_divert = frag_divert_port;
697        frag_divert_port = 0;
698#endif
699
700        /*
701         * Stick new segment in its place;
702         * check for complete reassembly.
703         */
704        ip_enq(ip, q->ipf_prev);
705        next = 0;
706        for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
707                if (q->ip_off != next)
708                        return (0);
709                next += q->ip_len;
710        }
711        if (q->ipf_prev->ipf_mff & 1)
712                return (0);
713
714        /*
715         * Reassembly is complete.  Make sure the packet is a sane size.
716         */
717        if (next + (IP_VHL_HL(((struct ip *)fp->ipq_next)->ip_vhl) << 2)
718                                                        > IP_MAXPACKET) {
719                ipstat.ips_toolong++;
720                ip_freef(fp);
721                return (0);
722        }
723
724        /*
725         * Concatenate fragments.
726         */
727        q = fp->ipq_next;
728        m = dtom(q);
729        t = m->m_next;
730        m->m_next = 0;
731        m_cat(m, t);
732        q = q->ipf_next;
733        while (q != (struct ipasfrag *)fp) {
734                t = dtom(q);
735                q = q->ipf_next;
736                m_cat(m, t);
737        }
738
739#ifdef IPDIVERT
740        /*
741         * Record divert port for packet, if any
742         */
743        frag_divert_port = fp->ipq_divert;
744#endif
745
746        /*
747         * Create header for new ip packet by modifying header of first
748         * packet;  dequeue and discard fragment reassembly header.
749         * Make header visible.
750         */
751        ip = fp->ipq_next;
752        ip->ip_len = next;
753        ip->ipf_mff &= ~1;
754        ((struct ip *)ip)->ip_src = fp->ipq_src;
755        ((struct ip *)ip)->ip_dst = fp->ipq_dst;
756        remque(fp);
757        nipq--;
758        (void) m_free(dtom(fp));
759        m = dtom(ip);
760        m->m_len += (ip->ip_hl << 2);
761        m->m_data -= (ip->ip_hl << 2);
762        /* some debugging cruft by sklower, below, will go away soon */
763        if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
764                register int plen = 0;
765                for (t = m; m; m = m->m_next)
766                        plen += m->m_len;
767                t->m_pkthdr.len = plen;
768        }
769        return ((struct ip *)ip);
770
771dropfrag:
772        ipstat.ips_fragdropped++;
773        m_freem(m);
774        return (0);
775}
776
777/*
778 * Free a fragment reassembly header and all
779 * associated datagrams.
780 */
781static void
782ip_freef(fp)
783        struct ipq *fp;
784{
785        register struct ipasfrag *q, *p;
786
787        for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
788                p = q->ipf_next;
789                ip_deq(q);
790                m_freem(dtom(q));
791        }
792        remque(fp);
793        (void) m_free(dtom(fp));
794        nipq--;
795}
796
797/*
798 * Put an ip fragment on a reassembly chain.
799 * Like insque, but pointers in middle of structure.
800 */
801static void
802ip_enq(p, prev)
803        register struct ipasfrag *p, *prev;
804{
805
806        p->ipf_prev = prev;
807        p->ipf_next = prev->ipf_next;
808        prev->ipf_next->ipf_prev = p;
809        prev->ipf_next = p;
810}
811
812/*
813 * To ip_enq as remque is to insque.
814 */
815static void
816ip_deq(p)
817        register struct ipasfrag *p;
818{
819
820        p->ipf_prev->ipf_next = p->ipf_next;
821        p->ipf_next->ipf_prev = p->ipf_prev;
822}
823
824/*
825 * IP timer processing;
826 * if a timer expires on a reassembly
827 * queue, discard it.
828 */
829void
830ip_slowtimo()
831{
832        register struct ipq *fp;
833        int s = splnet();
834        int i;
835
836        for (i = 0; i < IPREASS_NHASH; i++) {
837                fp = ipq[i].next;
838                if (fp == 0)
839                        continue;
840                while (fp != &ipq[i]) {
841                        --fp->ipq_ttl;
842                        fp = fp->next;
843                        if (fp->prev->ipq_ttl == 0) {
844                                ipstat.ips_fragtimeout++;
845                                ip_freef(fp->prev);
846                        }
847                }
848        }
849        splx(s);
850}
851
852/*
853 * Drain off all datagram fragments.
854 */
855void
856ip_drain()
857{
858        int     i;
859
860        for (i = 0; i < IPREASS_NHASH; i++) {
861                while (ipq[i].next != &ipq[i]) {
862                        ipstat.ips_fragdropped++;
863                        ip_freef(ipq[i].next);
864                }
865        }
866        in_rtqdrain();
867}
868
869/*
870 * Do option processing on a datagram,
871 * possibly discarding it if bad options are encountered,
872 * or forwarding it if source-routed.
873 * Returns 1 if packet has been forwarded/freed,
874 * 0 if the packet should be processed further.
875 */
876static int
877ip_dooptions(m)
878        struct mbuf *m;
879{
880        register struct ip *ip = mtod(m, struct ip *);
881        register u_char *cp;
882        register struct ip_timestamp *ipt;
883        register struct in_ifaddr *ia;
884        int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
885        struct in_addr *sin, dst;
886        n_time ntime;
887
888        dst = ip->ip_dst;
889        cp = (u_char *)(ip + 1);
890        cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
891        for (; cnt > 0; cnt -= optlen, cp += optlen) {
892                opt = cp[IPOPT_OPTVAL];
893                if (opt == IPOPT_EOL)
894                        break;
895                if (opt == IPOPT_NOP)
896                        optlen = 1;
897                else {
898                        optlen = cp[IPOPT_OLEN];
899                        if (optlen <= 0 || optlen > cnt) {
900                                code = &cp[IPOPT_OLEN] - (u_char *)ip;
901                                goto bad;
902                        }
903                }
904                switch (opt) {
905
906                default:
907                        break;
908
909                /*
910                 * Source routing with record.
911                 * Find interface with current destination address.
912                 * If none on this machine then drop if strictly routed,
913                 * or do nothing if loosely routed.
914                 * Record interface address and bring up next address
915                 * component.  If strictly routed make sure next
916                 * address is on directly accessible net.
917                 */
918                case IPOPT_LSRR:
919                case IPOPT_SSRR:
920                        if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
921                                code = &cp[IPOPT_OFFSET] - (u_char *)ip;
922                                goto bad;
923                        }
924                        ipaddr.sin_addr = ip->ip_dst;
925                        ia = (struct in_ifaddr *)
926                                ifa_ifwithaddr((struct sockaddr *)&ipaddr);
927                        if (ia == 0) {
928                                if (opt == IPOPT_SSRR) {
929                                        type = ICMP_UNREACH;
930                                        code = ICMP_UNREACH_SRCFAIL;
931                                        goto bad;
932                                }
933                                if (!ip_dosourceroute)
934                                        goto nosourcerouting;
935                                /*
936                                 * Loose routing, and not at next destination
937                                 * yet; nothing to do except forward.
938                                 */
939                                break;
940                        }
941                        off--;                  /* 0 origin */
942                        if (off > optlen - sizeof(struct in_addr)) {
943                                /*
944                                 * End of source route.  Should be for us.
945                                 */
946                                if (!ip_acceptsourceroute)
947                                        goto nosourcerouting;
948                                save_rte(cp, ip->ip_src);
949                                break;
950                        }
951
952                        if (!ip_dosourceroute) {
953                                char buf[4*sizeof "123"];
954
955nosourcerouting:
956                                strcpy(buf, inet_ntoa(ip->ip_dst));
957                                log(LOG_WARNING,
958                                    "attempted source route from %s to %s\n",
959                                    inet_ntoa(ip->ip_src), buf);
960                                type = ICMP_UNREACH;
961                                code = ICMP_UNREACH_SRCFAIL;
962                                goto bad;
963                        }
964
965                        /*
966                         * locate outgoing interface
967                         */
968                        (void)memcpy(&ipaddr.sin_addr, cp + off,
969                            sizeof(ipaddr.sin_addr));
970
971                        if (opt == IPOPT_SSRR) {
972#define INA     struct in_ifaddr *
973#define SA      struct sockaddr *
974                            if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
975                                ia = (INA)ifa_ifwithnet((SA)&ipaddr);
976                        } else
977                                ia = ip_rtaddr(ipaddr.sin_addr);
978                        if (ia == 0) {
979                                type = ICMP_UNREACH;
980                                code = ICMP_UNREACH_SRCFAIL;
981                                goto bad;
982                        }
983                        ip->ip_dst = ipaddr.sin_addr;
984                        (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
985                            sizeof(struct in_addr));
986                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
987                        /*
988                         * Let ip_intr's mcast routing check handle mcast pkts
989                         */
990                        forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
991                        break;
992
993                case IPOPT_RR:
994                        if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
995                                code = &cp[IPOPT_OFFSET] - (u_char *)ip;
996                                goto bad;
997                        }
998                        /*
999                         * If no space remains, ignore.
1000                         */
1001                        off--;                  /* 0 origin */
1002                        if (off > optlen - sizeof(struct in_addr))
1003                                break;
1004                        (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1005                            sizeof(ipaddr.sin_addr));
1006                        /*
1007                         * locate outgoing interface; if we're the destination,
1008                         * use the incoming interface (should be same).
1009                         */
1010                        if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
1011                            (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
1012                                type = ICMP_UNREACH;
1013                                code = ICMP_UNREACH_HOST;
1014                                goto bad;
1015                        }
1016                        (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
1017                            sizeof(struct in_addr));
1018                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1019                        break;
1020
1021                case IPOPT_TS:
1022                        code = cp - (u_char *)ip;
1023                        ipt = (struct ip_timestamp *)cp;
1024                        if (ipt->ipt_len < 5)
1025                                goto bad;
1026                        if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
1027                                if (++ipt->ipt_oflw == 0)
1028                                        goto bad;
1029                                break;
1030                        }
1031                        sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
1032                        switch (ipt->ipt_flg) {
1033
1034                        case IPOPT_TS_TSONLY:
1035                                break;
1036
1037                        case IPOPT_TS_TSANDADDR:
1038                                if (ipt->ipt_ptr + sizeof(n_time) +
1039                                    sizeof(struct in_addr) > ipt->ipt_len)
1040                                        goto bad;
1041                                ipaddr.sin_addr = dst;
1042                                ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1043                                                            m->m_pkthdr.rcvif);
1044                                if (ia == 0)
1045                                        continue;
1046                                (void)memcpy(sin, &IA_SIN(ia)->sin_addr,
1047                                    sizeof(struct in_addr));
1048                                ipt->ipt_ptr += sizeof(struct in_addr);
1049                                break;
1050
1051                        case IPOPT_TS_PRESPEC:
1052                                if (ipt->ipt_ptr + sizeof(n_time) +
1053                                    sizeof(struct in_addr) > ipt->ipt_len)
1054                                        goto bad;
1055                                (void)memcpy(&ipaddr.sin_addr, sin,
1056                                    sizeof(struct in_addr));
1057                                if (ifa_ifwithaddr((SA)&ipaddr) == 0)
1058                                        continue;
1059                                ipt->ipt_ptr += sizeof(struct in_addr);
1060                                break;
1061
1062                        default:
1063                                goto bad;
1064                        }
1065                        ntime = iptime();
1066                        (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime,
1067                            sizeof(n_time));
1068                        ipt->ipt_ptr += sizeof(n_time);
1069                }
1070        }
1071        if (forward && ipforwarding) {
1072                ip_forward(m, 1);
1073                return (1);
1074        }
1075        return (0);
1076bad:
1077        ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2;   /* XXX icmp_error adds in hdr length */
1078        icmp_error(m, type, code, 0, 0);
1079        ipstat.ips_badoptions++;
1080        return (1);
1081}
1082
1083/*
1084 * Given address of next destination (final or next hop),
1085 * return internet address info of interface to be used to get there.
1086 */
1087static struct in_ifaddr *
1088ip_rtaddr(dst)
1089         struct in_addr dst;
1090{
1091        register struct sockaddr_in *sin;
1092
1093        sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
1094
1095        if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
1096                if (ipforward_rt.ro_rt) {
1097                        RTFREE(ipforward_rt.ro_rt);
1098                        ipforward_rt.ro_rt = 0;
1099                }
1100                sin->sin_family = AF_INET;
1101                sin->sin_len = sizeof(*sin);
1102                sin->sin_addr = dst;
1103
1104                rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1105        }
1106        if (ipforward_rt.ro_rt == 0)
1107                return ((struct in_ifaddr *)0);
1108        return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa);
1109}
1110
1111/*
1112 * Save incoming source route for use in replies,
1113 * to be picked up later by ip_srcroute if the receiver is interested.
1114 */
1115void
1116save_rte(option, dst)
1117        u_char *option;
1118        struct in_addr dst;
1119{
1120        unsigned olen;
1121
1122        olen = option[IPOPT_OLEN];
1123#ifdef DIAGNOSTIC
1124        if (ipprintfs)
1125                printf("save_rte: olen %d\n", olen);
1126#endif
1127        if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
1128                return;
1129        bcopy(option, ip_srcrt.srcopt, olen);
1130        ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1131        ip_srcrt.dst = dst;
1132}
1133
1134/*
1135 * Retrieve incoming source route for use in replies,
1136 * in the same form used by setsockopt.
1137 * The first hop is placed before the options, will be removed later.
1138 */
1139struct mbuf *
1140ip_srcroute()
1141{
1142        register struct in_addr *p, *q;
1143        register struct mbuf *m;
1144
1145        if (ip_nhops == 0)
1146                return ((struct mbuf *)0);
1147        m = m_get(M_DONTWAIT, MT_SOOPTS);
1148        if (m == 0)
1149                return ((struct mbuf *)0);
1150
1151#define OPTSIZ  (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
1152
1153        /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1154        m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
1155            OPTSIZ;
1156#ifdef DIAGNOSTIC
1157        if (ipprintfs)
1158                printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
1159#endif
1160
1161        /*
1162         * First save first hop for return route
1163         */
1164        p = &ip_srcrt.route[ip_nhops - 1];
1165        *(mtod(m, struct in_addr *)) = *p--;
1166#ifdef DIAGNOSTIC
1167        if (ipprintfs)
1168                printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr));
1169#endif
1170
1171        /*
1172         * Copy option fields and padding (nop) to mbuf.
1173         */
1174        ip_srcrt.nop = IPOPT_NOP;
1175        ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
1176        (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
1177            &ip_srcrt.nop, OPTSIZ);
1178        q = (struct in_addr *)(mtod(m, caddr_t) +
1179            sizeof(struct in_addr) + OPTSIZ);
1180#undef OPTSIZ
1181        /*
1182         * Record return path as an IP source route,
1183         * reversing the path (pointers are now aligned).
1184         */
1185        while (p >= ip_srcrt.route) {
1186#ifdef DIAGNOSTIC
1187                if (ipprintfs)
1188                        printf(" %lx", ntohl(q->s_addr));
1189#endif
1190                *q++ = *p--;
1191        }
1192        /*
1193         * Last hop goes to final destination.
1194         */
1195        *q = ip_srcrt.dst;
1196#ifdef DIAGNOSTIC
1197        if (ipprintfs)
1198                printf(" %lx\n", ntohl(q->s_addr));
1199#endif
1200        return (m);
1201}
1202
1203/*
1204 * Strip out IP options, at higher
1205 * level protocol in the kernel.
1206 * Second argument is buffer to which options
1207 * will be moved, and return value is their length.
1208 * XXX should be deleted; last arg currently ignored.
1209 */
1210void
1211ip_stripoptions(m, mopt)
1212        register struct mbuf *m;
1213        struct mbuf *mopt;
1214{
1215        register int i;
1216        struct ip *ip = mtod(m, struct ip *);
1217        register caddr_t opts;
1218        int olen;
1219
1220        olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1221        opts = (caddr_t)(ip + 1);
1222        i = m->m_len - (sizeof (struct ip) + olen);
1223        bcopy(opts + olen, opts, (unsigned)i);
1224        m->m_len -= olen;
1225        if (m->m_flags & M_PKTHDR)
1226                m->m_pkthdr.len -= olen;
1227        ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2);
1228}
1229
1230u_char inetctlerrmap[PRC_NCMDS] = {
1231        0,              0,              0,              0,
1232        0,              EMSGSIZE,       EHOSTDOWN,      EHOSTUNREACH,
1233        EHOSTUNREACH,   EHOSTUNREACH,   ECONNREFUSED,   ECONNREFUSED,
1234        EMSGSIZE,       EHOSTUNREACH,   0,              0,
1235        0,              0,              0,              0,
1236        ENOPROTOOPT
1237};
1238
1239/*
1240 * Forward a packet.  If some error occurs return the sender
1241 * an icmp packet.  Note we can't always generate a meaningful
1242 * icmp message because icmp doesn't have a large enough repertoire
1243 * of codes and types.
1244 *
1245 * If not forwarding, just drop the packet.  This could be confusing
1246 * if ipforwarding was zero but some routing protocol was advancing
1247 * us as a gateway to somewhere.  However, we must let the routing
1248 * protocol deal with that.
1249 *
1250 * The srcrt parameter indicates whether the packet is being forwarded
1251 * via a source route.
1252 */
1253static void
1254ip_forward(struct mbuf *m, int srcrt)
1255{
1256        struct ip *ip = mtod(m, struct ip *);
1257        register struct sockaddr_in *sin;
1258        register struct rtentry *rt;
1259        int error, type = 0, code = 0;
1260        struct mbuf *mcopy;
1261        n_long dest;
1262        struct ifnet *destifp;
1263
1264        dest = 0;
1265#ifdef DIAGNOSTIC
1266        if (ipprintfs)
1267                printf("forward: src %lx dst %lx ttl %x\n",
1268                        ip->ip_src.s_addr, ip->ip_dst.s_addr, ip->ip_ttl);
1269#endif
1270
1271
1272        if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) {
1273                ipstat.ips_cantforward++;
1274                m_freem(m);
1275                return;
1276        }
1277        HTONS(ip->ip_id);
1278        if (ip->ip_ttl <= IPTTLDEC) {
1279                icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0);
1280                return;
1281        }
1282        ip->ip_ttl -= IPTTLDEC;
1283
1284        sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
1285        if ((rt = ipforward_rt.ro_rt) == 0 ||
1286            ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
1287                if (ipforward_rt.ro_rt) {
1288                        RTFREE(ipforward_rt.ro_rt);
1289                        ipforward_rt.ro_rt = 0;
1290                }
1291                sin->sin_family = AF_INET;
1292                sin->sin_len = sizeof(*sin);
1293                sin->sin_addr = ip->ip_dst;
1294
1295                rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1296                if (ipforward_rt.ro_rt == 0) {
1297                        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
1298                        return;
1299                }
1300                rt = ipforward_rt.ro_rt;
1301        }
1302
1303        /*
1304         * Save at most 64 bytes of the packet in case
1305         * we need to generate an ICMP message to the src.
1306         */
1307        mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64));
1308
1309        /*
1310         * If forwarding packet using same interface that it came in on,
1311         * perhaps should send a redirect to sender to shortcut a hop.
1312         * Only send redirect if source is sending directly to us,
1313         * and if packet was not source routed (or has any options).
1314         * Also, don't send redirect if forwarding using a default route
1315         * or a route modified by a redirect.
1316         */
1317#define satosin(sa)     ((struct sockaddr_in *)(sa))
1318        if (rt->rt_ifp == m->m_pkthdr.rcvif &&
1319            (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
1320            satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
1321            ipsendredirects && !srcrt) {
1322#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
1323                u_long src = ntohl(ip->ip_src.s_addr);
1324
1325                if (RTA(rt) &&
1326                    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1327                    if (rt->rt_flags & RTF_GATEWAY)
1328                        dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
1329                    else
1330                        dest = ip->ip_dst.s_addr;
1331                    /* Router requirements says to only send host redirects */
1332                    type = ICMP_REDIRECT;
1333                    code = ICMP_REDIRECT_HOST;
1334#ifdef DIAGNOSTIC
1335                    if (ipprintfs)
1336                        printf("redirect (%d) to %lx\n", code, (u_long)dest);
1337#endif
1338                }
1339        }
1340
1341        error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
1342                          IP_FORWARDING, 0);
1343        if (error)
1344                ipstat.ips_cantforward++;
1345        else {
1346                ipstat.ips_forward++;
1347                if (type)
1348                        ipstat.ips_redirectsent++;
1349                else {
1350                        if (mcopy)
1351                                m_freem(mcopy);
1352                        return;
1353                }
1354        }
1355        if (mcopy == NULL)
1356                return;
1357        destifp = NULL;
1358
1359        switch (error) {
1360
1361        case 0:                         /* forwarded, but need redirect */
1362                /* type, code set above */
1363                break;
1364
1365        case ENETUNREACH:               /* shouldn't happen, checked above */
1366        case EHOSTUNREACH:
1367        case ENETDOWN:
1368        case EHOSTDOWN:
1369        default:
1370                type = ICMP_UNREACH;
1371                code = ICMP_UNREACH_HOST;
1372                break;
1373
1374        case EMSGSIZE:
1375                type = ICMP_UNREACH;
1376                code = ICMP_UNREACH_NEEDFRAG;
1377                if (ipforward_rt.ro_rt)
1378                        destifp = ipforward_rt.ro_rt->rt_ifp;
1379                ipstat.ips_cantfrag++;
1380                break;
1381
1382        case ENOBUFS:
1383                type = ICMP_SOURCEQUENCH;
1384                code = 0;
1385                break;
1386        }
1387        icmp_error(mcopy, type, code, dest, destifp);
1388}
1389
1390void
1391ip_savecontrol(inp, mp, ip, m)
1392        register struct inpcb *inp;
1393        register struct mbuf **mp;
1394        register struct ip *ip;
1395        register struct mbuf *m;
1396{
1397        if (inp->inp_socket->so_options & SO_TIMESTAMP) {
1398                struct timeval tv;
1399
1400                microtime(&tv);
1401                *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
1402                        SCM_TIMESTAMP, SOL_SOCKET);
1403                if (*mp)
1404                        mp = &(*mp)->m_next;
1405        }
1406        if (inp->inp_flags & INP_RECVDSTADDR) {
1407                *mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
1408                    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
1409                if (*mp)
1410                        mp = &(*mp)->m_next;
1411        }
1412#ifdef notyet
1413        /* XXX
1414         * Moving these out of udp_input() made them even more broken
1415         * than they already were.
1416         */
1417        /* options were tossed already */
1418        if (inp->inp_flags & INP_RECVOPTS) {
1419                *mp = sbcreatecontrol((caddr_t) opts_deleted_above,
1420                    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
1421                if (*mp)
1422                        mp = &(*mp)->m_next;
1423        }
1424        /* ip_srcroute doesn't do what we want here, need to fix */
1425        if (inp->inp_flags & INP_RECVRETOPTS) {
1426                *mp = sbcreatecontrol((caddr_t) ip_srcroute(),
1427                    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
1428                if (*mp)
1429                        mp = &(*mp)->m_next;
1430        }
1431#endif
1432        if (inp->inp_flags & INP_RECVIF) {
1433                struct sockaddr_dl sdl;
1434
1435                sdl.sdl_len = offsetof(struct sockaddr_dl, sdl_data[0]);
1436                sdl.sdl_family = AF_LINK;
1437                sdl.sdl_index = m->m_pkthdr.rcvif ?
1438                        m->m_pkthdr.rcvif->if_index : 0;
1439                sdl.sdl_nlen = sdl.sdl_alen = sdl.sdl_slen = 0;
1440                *mp = sbcreatecontrol((caddr_t) &sdl, sdl.sdl_len,
1441                        IP_RECVIF, IPPROTO_IP);
1442                if (*mp)
1443                        mp = &(*mp)->m_next;
1444        }
1445}
1446
1447int
1448ip_rsvp_init(struct socket *so)
1449{
1450        if (so->so_type != SOCK_RAW ||
1451            so->so_proto->pr_protocol != IPPROTO_RSVP)
1452                return EOPNOTSUPP;
1453
1454        if (ip_rsvpd != NULL)
1455                return EADDRINUSE;
1456
1457        ip_rsvpd = so;
1458        /*
1459         * This may seem silly, but we need to be sure we don't over-increment
1460         * the RSVP counter, in case something slips up.
1461         */
1462        if (!ip_rsvp_on) {
1463                ip_rsvp_on = 1;
1464                rsvp_on++;
1465        }
1466
1467        return 0;
1468}
1469
1470int
1471ip_rsvp_done(void)
1472{
1473        ip_rsvpd = NULL;
1474        /*
1475         * This may seem silly, but we need to be sure we don't over-decrement
1476         * the RSVP counter, in case something slips up.
1477         */
1478        if (ip_rsvp_on) {
1479                ip_rsvp_on = 0;
1480                rsvp_on--;
1481        }
1482        return 0;
1483}
Note: See TracBrowser for help on using the repository browser.