Annotation of XNU/bsd/netinet/ip_output.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * Copyright (c) 1982, 1986, 1988, 1990, 1993
                     24:  *     The Regents of the University of California.  All rights reserved.
                     25:  *
                     26:  * Redistribution and use in source and binary forms, with or without
                     27:  * modification, are permitted provided that the following conditions
                     28:  * are met:
                     29:  * 1. Redistributions of source code must retain the above copyright
                     30:  *    notice, this list of conditions and the following disclaimer.
                     31:  * 2. Redistributions in binary form must reproduce the above copyright
                     32:  *    notice, this list of conditions and the following disclaimer in the
                     33:  *    documentation and/or other materials provided with the distribution.
                     34:  * 3. All advertising materials mentioning features or use of this software
                     35:  *    must display the following acknowledgement:
                     36:  *     This product includes software developed by the University of
                     37:  *     California, Berkeley and its contributors.
                     38:  * 4. Neither the name of the University nor the names of its contributors
                     39:  *    may be used to endorse or promote products derived from this software
                     40:  *    without specific prior written permission.
                     41:  *
                     42:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     43:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     44:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     45:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     46:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     47:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     48:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     49:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     50:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     51:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     52:  * SUCH DAMAGE.
                     53:  *
                     54:  *     @(#)ip_output.c 8.3 (Berkeley) 1/21/94
                     55:  */
                     56: 
                     57: #define _IP_VHL
                     58: 
                     59: #if ISFB31
                     60: #include "opt_ipfw.h"
                     61: #include "opt_ipdn.h"
                     62: #include "opt_ipdivert.h"
                     63: #include "opt_ipfilter.h"
                     64: #endif
                     65: 
                     66: #include <sys/param.h>
                     67: #include <sys/systm.h>
                     68: #include <sys/kernel.h>
                     69: #include <sys/malloc.h>
                     70: #include <sys/mbuf.h>
                     71: #include <sys/protosw.h>
                     72: #include <sys/socket.h>
                     73: #include <sys/socketvar.h>
                     74: 
                     75: #include <net/if.h>
                     76: #include <net/route.h>
                     77: 
                     78: #include <netinet/in.h>
                     79: #include <netinet/in_systm.h>
                     80: #include <netinet/ip.h>
                     81: #include <netinet/in_pcb.h>
                     82: #include <netinet/in_var.h>
                     83: #include <netinet/ip_var.h>
                     84: #include <net/dlil.h>
                     85: 
                     86: #ifdef vax
                     87: #include <machine/mtpr.h>
                     88: #endif
                     89: 
                     90: #if ISFB31
                     91: #include <machine/in_cksum.h>
                     92: 
                     93: static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
                     94: #endif
                     95: 
                     96: #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
                     97: #undef COMPAT_IPFW
                     98: #define COMPAT_IPFW 1
                     99: #else
                    100: #undef COMPAT_IPFW
                    101: #endif
                    102: 
                    103: #if COMPAT_IPFW
                    104: #include <netinet/ip_fw.h>
                    105: #endif
                    106: 
                    107: #if DUMMYNET
                    108: #include <netinet/ip_dummynet.h>
                    109: #endif
                    110: 
                    111: #if IPFIREWALL_FORWARD_DEBUG
                    112: #define print_ip(a)     printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
                    113:                                                  (ntohl(a.s_addr)>>16)&0xFF,\
                    114:                                                  (ntohl(a.s_addr)>>8)&0xFF,\
                    115:                                                  (ntohl(a.s_addr))&0xFF);
                    116: #endif
                    117: 
                    118: u_short ip_id;
                    119: 
                    120: static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
                    121: static void    ip_mloopback
                    122:        __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int));
                    123: static int     ip_getmoptions
                    124:        __P((struct sockopt *, struct ip_moptions *));
                    125: static int     ip_pcbopts __P((int, struct mbuf **, struct mbuf *));
                    126: static int     ip_setmoptions
                    127:        __P((struct sockopt *, struct ip_moptions **));
                    128: static u_long  lo_dl_tag = 0;
                    129: 
                    130: #if IPFILTER_LKM || IPFILTER
                    131: int    ip_optcopy __P((struct ip *, struct ip *));
                    132: extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **));
                    133: #else
                    134: static int     ip_optcopy __P((struct ip *, struct ip *));
                    135: #endif
                    136: 
                    137: 
                    138: extern struct protosw inetsw[];
                    139: 
                    140: /*
                    141:  * IP output.  The packet in mbuf chain m contains a skeletal IP
                    142:  * header (with len, off, ttl, proto, tos, src, dst).
                    143:  * The mbuf chain containing the packet will be freed.
                    144:  * The mbuf opt, if present, will not be freed.
                    145:  */
                    146: int
                    147: ip_output(m0, opt, ro, flags, imo)
                    148:        struct mbuf *m0;
                    149:        struct mbuf *opt;
                    150:        struct route *ro;
                    151:        int flags;
                    152:        struct ip_moptions *imo;
                    153: {
                    154:        struct ip *ip, *mhip;
                    155:        struct ifnet *ifp;
                    156:        u_long       dl_tag;
                    157:        struct mbuf *m = m0;
                    158:        int hlen = sizeof (struct ip);
                    159:        int len, off, error = 0;
                    160:        struct sockaddr_in *dst;
                    161:        struct in_ifaddr *ia;
                    162:        int isbroadcast;
                    163: #if IPFIREWALL_FORWARD
                    164:        int fwd_rewrite_src = 0;
                    165: #endif
                    166: 
                    167: #if !IPDIVERT /* dummy variable for the firewall code to play with */
                    168:         u_short ip_divert_cookie = 0 ;
                    169: #endif
                    170: #if COMPAT_IPFW
                    171:        struct ip_fw_chain *rule = NULL ;
                    172: #endif
                    173: 
                    174: #if IPFIREWALL && DUMMYNET
                    175:         /*  
                    176:          * dummynet packet are prepended a vestigial mbuf with
                    177:          * m_type = MT_DUMMYNET and m_data pointing to the matching
                    178:          * rule.
                    179:          */ 
                    180:         if (m->m_type == MT_DUMMYNET) {
                    181:             struct mbuf *tmp_m = m ;
                    182:             /*
                    183:              * the packet was already tagged, so part of the
                    184:              * processing was already done, and we need to go down.
                    185:              * opt, flags and imo have already been used, and now
                    186:              * they are used to hold ifp and hlen and NULL, respectively.
                    187:              */
                    188:             rule = (struct ip_fw_chain *)(m->m_data) ;
                    189:             m = m->m_next ;
                    190:             FREE(tmp_m, M_IPFW);
                    191:             ip = mtod(m, struct ip *);
                    192:             dst = (struct sockaddr_in *)&ro->ro_dst;
                    193:             ifp = (struct ifnet *)opt;
                    194:             hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
                    195:             opt = NULL ;
                    196:             flags = 0 ; /* XXX is this correct ? */
                    197:             goto sendit;
                    198:         } else
                    199:             rule = NULL ;
                    200: #endif
                    201: 
                    202: #if    DIAGNOSTIC
                    203:        if ((m->m_flags & M_PKTHDR) == 0)
                    204:                panic("ip_output no HDR");
                    205:        if (!ro)
                    206:                panic("ip_output no route, proto = %d",
                    207:                      mtod(m, struct ip *)->ip_p);
                    208: #endif
                    209:        if (opt) {
                    210:                m = ip_insertoptions(m, opt, &len);
                    211:                hlen = len;
                    212:        }
                    213:        ip = mtod(m, struct ip *);
                    214:        /*
                    215:         * Fill in IP header.
                    216:         */
                    217:        if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
                    218:                ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2);
                    219:                ip->ip_off &= IP_DF;
                    220:                ip->ip_id = htons(ip_id++);
                    221:                ipstat.ips_localout++;
                    222:        } else {
                    223:                hlen = IP_VHL_HL(ip->ip_vhl) << 2;
                    224:        }
                    225: 
                    226:        dst = (struct sockaddr_in *)&ro->ro_dst;
                    227:        /*
                    228:         * If there is a cached route,
                    229:         * check that it is to the same destination
                    230:         * and is still up.  If not, free it and try again.
                    231:         */
                    232:        if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
                    233:           dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
                    234:                RTFREE(ro->ro_rt);
                    235:                ro->ro_rt = (struct rtentry *)0;
                    236:        }
                    237:        if (ro->ro_rt == 0) {
                    238:                dst->sin_family = AF_INET;
                    239:                dst->sin_len = sizeof(*dst);
                    240:                dst->sin_addr = ip->ip_dst;
                    241:        }
                    242:        /*
                    243:         * If routing to interface only,
                    244:         * short circuit routing lookup.
                    245:         */
                    246: #define ifatoia(ifa)   ((struct in_ifaddr *)(ifa))
                    247: #define sintosa(sin)   ((struct sockaddr *)(sin))
                    248:        if (flags & IP_ROUTETOIF) {
                    249:                if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
                    250:                    (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
                    251:                        ipstat.ips_noroute++;
                    252:                        error = ENETUNREACH;
                    253:                        goto bad;
                    254:                }
                    255:                ifp = ia->ia_ifp;
                    256:                dl_tag = ia->ia_ifa.ifa_dlt;
                    257:                ip->ip_ttl = 1;
                    258:                isbroadcast = in_broadcast(dst->sin_addr, ifp);
                    259:        } else {
                    260:                /*
                    261:                 * If this is the case, we probably don't want to allocate
                    262:                 * a protocol-cloned route since we didn't get one from the
                    263:                 * ULP.  This lets TCP do its thing, while not burdening
                    264:                 * forwarding or ICMP with the overhead of cloning a route.
                    265:                 * Of course, we still want to do any cloning requested by
                    266:                 * the link layer, as this is probably required in all cases
                    267:                 * for correct operation (as it is for ARP).
                    268:                 */
                    269:                if (ro->ro_rt == 0)
                    270:                        rtalloc_ign(ro, RTF_PRCLONING);
                    271:                if (ro->ro_rt == 0) {
                    272:                        ipstat.ips_noroute++;
                    273:                        error = EHOSTUNREACH;
                    274:                        goto bad;
                    275:                }
                    276:                ia = ifatoia(ro->ro_rt->rt_ifa);
                    277:                ifp = ro->ro_rt->rt_ifp;
                    278:                dl_tag = ro->ro_rt->rt_dlt;
                    279:                ro->ro_rt->rt_use++;
                    280:                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                    281:                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
                    282:                if (ro->ro_rt->rt_flags & RTF_HOST)
                    283:                        isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST);
                    284:                else
                    285:                        isbroadcast = in_broadcast(dst->sin_addr, ifp);
                    286:        }
                    287:        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
                    288:                struct in_multi *inm;
                    289: 
                    290:                m->m_flags |= M_MCAST;
                    291:                /*
                    292:                 * IP destination address is multicast.  Make sure "dst"
                    293:                 * still points to the address in "ro".  (It may have been
                    294:                 * changed to point to a gateway address, above.)
                    295:                 */
                    296:                dst = (struct sockaddr_in *)&ro->ro_dst;
                    297:                /*
                    298:                 * See if the caller provided any multicast options
                    299:                 */
                    300:                if (imo != NULL) {
                    301:                        ip->ip_ttl = imo->imo_multicast_ttl;
                    302:                        if (imo->imo_multicast_ifp != NULL)
                    303:                                ifp = imo->imo_multicast_ifp;
                    304:                        if (imo->imo_multicast_vif != -1)
                    305:                                ip->ip_src.s_addr =
                    306:                                    ip_mcast_src(imo->imo_multicast_vif);
                    307:                } else
                    308:                        ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
                    309:                /*
                    310:                 * Confirm that the outgoing interface supports multicast.
                    311:                 */
                    312:                if ((imo == NULL) || (imo->imo_multicast_vif == -1)) {
                    313:                        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
                    314:                                ipstat.ips_noroute++;
                    315:                                error = ENETUNREACH;
                    316:                                goto bad;
                    317:                        }
                    318:                }
                    319:                /*
                    320:                 * If source address not specified yet, use address
                    321:                 * of outgoing interface.
                    322:                 */
                    323:                if (ip->ip_src.s_addr == INADDR_ANY) {
                    324:                        register struct in_ifaddr *ia1;
                    325: 
                    326:                        for (ia1 = in_ifaddrhead.tqh_first; ia1;
                    327:                             ia1 = ia1->ia_link.tqe_next)
                    328:                                if (ia1->ia_ifp == ifp) {
                    329:                                        ip->ip_src = IA_SIN(ia1)->sin_addr;
                    330:                                        break;
                    331:                                }
                    332:                }
                    333: 
                    334:                IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
                    335:                if (inm != NULL &&
                    336:                   (imo == NULL || imo->imo_multicast_loop)) {
                    337:                        /*
                    338:                         * If we belong to the destination multicast group
                    339:                         * on the outgoing interface, and the caller did not
                    340:                         * forbid loopback, loop back a copy.
                    341:                         */
                    342:                        ip_mloopback(ifp, m, dst, hlen);
                    343:                }
                    344:                else {
                    345:                        /*
                    346:                         * If we are acting as a multicast router, perform
                    347:                         * multicast forwarding as if the packet had just
                    348:                         * arrived on the interface to which we are about
                    349:                         * to send.  The multicast forwarding function
                    350:                         * recursively calls this function, using the
                    351:                         * IP_FORWARDING flag to prevent infinite recursion.
                    352:                         *
                    353:                         * Multicasts that are looped back by ip_mloopback(),
                    354:                         * above, will be forwarded by the ip_input() routine,
                    355:                         * if necessary.
                    356:                         */
                    357:                        if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
                    358:                                /*
                    359:                                 * Check if rsvp daemon is running. If not, don't
                    360:                                 * set ip_moptions. This ensures that the packet
                    361:                                 * is multicast and not just sent down one link
                    362:                                 * as prescribed by rsvpd.
                    363:                                 */
                    364:                                if (!rsvp_on)
                    365:                                  imo = NULL;
                    366:                                if (ip_mforward(ip, ifp, m, imo) != 0) {
                    367:                                        m_freem(m);
                    368:                                        goto done;
                    369:                                }
                    370:                        }
                    371:                }
                    372: 
                    373:                /*
                    374:                 * Multicasts with a time-to-live of zero may be looped-
                    375:                 * back, above, but must not be transmitted on a network.
                    376:                 * Also, multicasts addressed to the loopback interface
                    377:                 * are not sent -- the above call to ip_mloopback() will
                    378:                 * loop back a copy if this host actually belongs to the
                    379:                 * destination group on the loopback interface.
                    380:                 */
                    381:                if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) {
                    382:                        m_freem(m);
                    383:                        goto done;
                    384:                }
                    385: 
                    386:                goto sendit;
                    387:        }
                    388: #ifndef notdef
                    389:        /*
                    390:         * If source address not specified yet, use address
                    391:         * of outgoing interface.
                    392:         */
                    393:        if (ip->ip_src.s_addr == INADDR_ANY) {
                    394:                ip->ip_src = IA_SIN(ia)->sin_addr;
                    395: #if IPFIREWALL_FORWARD
                    396:                /* Keep note that we did this - if the firewall changes
                    397:                 * the next-hop, our interface may change, changing the
                    398:                 * default source IP. It's a shame so much effort happens
                    399:                 * twice. Oh well. 
                    400:                 */
                    401:                fwd_rewrite_src++;
                    402: #endif /* IPFIREWALL_FORWARD */
                    403:        }
                    404: #endif /* notdef */
                    405:        /*
                    406:         * Verify that we have any chance at all of being able to queue
                    407:         *      the packet or packet fragments
                    408:         */
                    409:        if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
                    410:                ifp->if_snd.ifq_maxlen) {
                    411:                        error = ENOBUFS;
                    412:                        goto bad;
                    413:        }
                    414: 
                    415:        /*
                    416:         * Look for broadcast address and
                    417:         * and verify user is allowed to send
                    418:         * such a packet.
                    419:         */
                    420:        if (isbroadcast) {
                    421:                if ((ifp->if_flags & IFF_BROADCAST) == 0) {
                    422:                        error = EADDRNOTAVAIL;
                    423:                        goto bad;
                    424:                }
                    425:                if ((flags & IP_ALLOWBROADCAST) == 0) {
                    426:                        error = EACCES;
                    427:                        goto bad;
                    428:                }
                    429:                /* don't allow broadcast messages to be fragmented */
                    430:                if ((u_short)ip->ip_len > ifp->if_mtu) {
                    431:                        error = EMSGSIZE;
                    432:                        goto bad;
                    433:                }
                    434:                m->m_flags |= M_BCAST;
                    435:        } else {
                    436:                m->m_flags &= ~M_BCAST;
                    437:        }
                    438: 
                    439: sendit:
                    440:        /*
                    441:         * IpHack's section.
                    442:         * - Xlate: translate packet's addr/port (NAT).
                    443:         * - Firewall: deny/allow/etc.
                    444:         * - Wrap: fake packet's addr/port <unimpl.>
                    445:         * - Encapsulate: put it in another IP and send out. <unimp.>
                    446:         */ 
                    447: #if IPFILTER || IPFILTER_LKM
                    448:        if (fr_checkp) {
                    449:                struct  mbuf    *m1 = m;
                    450: 
                    451:                if ((error = (*fr_checkp)(ip, hlen, ifp, 1, &m1)) || !m1)
                    452:                        goto done;
                    453:                ip = mtod(m = m1, struct ip *);
                    454:        }
                    455: #endif
                    456: 
                    457: #if COMPAT_IPFW
                    458:         if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, ifp, IP_NAT_OUT)) {
                    459:                error = EACCES; 
                    460:                goto done;
                    461:        }
                    462: 
                    463:        /*
                    464:         * Check with the firewall...
                    465:         */
                    466:        if (ip_fw_chk_ptr) {
                    467:                struct sockaddr_in *old = dst;
                    468: 
                    469:                off = (*ip_fw_chk_ptr)(&ip,
                    470:                    hlen, ifp, &ip_divert_cookie, &m, &rule, &dst);
                    471:                 /*
                    472:                  * On return we must do the following:
                    473:                  * m == NULL         -> drop the pkt
                    474:                  * 1<=off<= 0xffff   -> DIVERT
                    475:                  * (off & 0x10000)   -> send to a DUMMYNET pipe
                    476:                  * dst != old        -> IPFIREWALL_FORWARD
                    477:                  * off==0, dst==old  -> accept
                    478:                  * If some of the above modules is not compiled in, then
                    479:                  * we should't have to check the corresponding condition
                    480:                  * (because the ipfw control socket should not accept
                    481:                  * unsupported rules), but better play safe and drop
                    482:                  * packets in case of doubt.
                    483:                  */
                    484:                if (!m) { /* firewall said to reject */
                    485:                        error = EACCES;
                    486:                        goto done;
                    487:                }
                    488:                if (off == 0 && dst == old) /* common case */
                    489:                        goto pass ;
                    490: #if DUMMYNET
                    491:                 if (off & 0x10000) {  
                    492:                     /*
                    493:                      * pass the pkt to dummynet. Need to include
                    494:                      * pipe number, m, ifp, ro, hlen because these are
                    495:                      * not recomputed in the next pass.
                    496:                      * All other parameters have been already used and
                    497:                      * so they are not needed anymore. 
                    498:                      * XXX note: if the ifp or ro entry are deleted
                    499:                      * while a pkt is in dummynet, we are in trouble!
                    500:                      */ 
                    501:                     dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,hlen,rule);
                    502:                        goto done;
                    503:                }
                    504: #endif   
                    505: #if IPDIVERT
                    506:                 if (off > 0 && off < 0x10000) {         /* Divert packet */
                    507:                        ip_divert_port = off & 0xffff ;
                    508:                        (*ip_protox[IPPROTO_DIVERT]->pr_input)(m, 0);
                    509:                        goto done;
                    510:                }
                    511: #endif
                    512: 
                    513: #if IPFIREWALL_FORWARD
                    514:                /* Here we check dst to make sure it's directly reachable on the
                    515:                 * interface we previously thought it was.
                    516:                 * If it isn't (which may be likely in some situations) we have
                    517:                 * to re-route it (ie, find a route for the next-hop and the
                    518:                 * associated interface) and set them here. This is nested
                    519:                 * forwarding which in most cases is undesirable, except where
                    520:                 * such control is nigh impossible. So we do it here.
                    521:                 * And I'm babbling.
                    522:                 */
                    523:                if (off == 0 && old != dst) {
                    524:                        struct in_ifaddr *ia;
                    525: 
                    526:                        /* It's changed... */
                    527:                        /* There must be a better way to do this next line... */
                    528:                        static struct route sro_fwd, *ro_fwd = &sro_fwd;
                    529: #if IPFIREWALL_FORWARD_DEBUG
                    530:                        printf("IPFIREWALL_FORWARD: New dst ip: ");
                    531:                        print_ip(dst->sin_addr);
                    532:                        printf("\n");
                    533: #endif
                    534:                        /*
                    535:                         * We need to figure out if we have been forwarded
                    536:                         * to a local socket. If so then we should somehow 
                    537:                         * "loop back" to ip_input, and get directed to the
                    538:                         * PCB as if we had received this packet. This is
                    539:                         * because it may be dificult to identify the packets
                    540:                         * you want to forward until they are being output
                    541:                         * and have selected an interface. (e.g. locally
                    542:                         * initiated packets) If we used the loopback inteface,
                    543:                         * we would not be able to control what happens 
                    544:                         * as the packet runs through ip_input() as
                    545:                         * it is done through a ISR.
                    546:                         */
                    547:                        for (ia = TAILQ_FIRST(&in_ifaddrhead); ia;
                    548:                                        ia = TAILQ_NEXT(ia, ia_link)) {
                    549:                                /*
                    550:                                 * If the addr to forward to is one
                    551:                                 * of ours, we pretend to
                    552:                                 * be the destination for this packet.
                    553:                                 */
                    554:                                if (IA_SIN(ia)->sin_addr.s_addr ==
                    555:                                                 dst->sin_addr.s_addr)
                    556:                                        break;
                    557:                        }
                    558:                        if (ia) {
                    559:                                /* tell ip_input "dont filter" */
                    560:                                ip_fw_fwd_addr = dst;
                    561:                                if (m->m_pkthdr.rcvif == NULL)
                    562:                                        m->m_pkthdr.rcvif = ifunit("lo0");
                    563:                                ip->ip_len = htons((u_short)ip->ip_len);
                    564:                                ip->ip_off = htons((u_short)ip->ip_off);
                    565:                                ip->ip_sum = 0;
                    566:                                
                    567:                                ip->ip_sum = in_cksum(m, hlen);
                    568: 
                    569:                                ip_input(m);
                    570:                                goto done;
                    571:                        }
                    572:                        /* Some of the logic for this was
                    573:                         * nicked from above.
                    574:                         *
                    575:                         * This rewrites the cached route in a local PCB.
                    576:                         * Is this what we want to do?
                    577:                         */
                    578:                        bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
                    579: 
                    580:                        ro_fwd->ro_rt = 0;
                    581:                        rtalloc_ign(ro_fwd, RTF_PRCLONING);
                    582: 
                    583:                        if (ro_fwd->ro_rt == 0) {
                    584:                                ipstat.ips_noroute++;
                    585:                                error = EHOSTUNREACH;
                    586:                                goto bad;
                    587:                        }
                    588: 
                    589:                        ia = ifatoia(ro_fwd->ro_rt->rt_ifa);
                    590:                        ifp = ro_fwd->ro_rt->rt_ifp;
                    591:                        dl_tag = ro->ro_rt->rt_dlt;
                    592:                        ro_fwd->ro_rt->rt_use++;
                    593:                        if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
                    594:                                dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway;
                    595:                        if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
                    596:                                isbroadcast =
                    597:                                    (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
                    598:                        else
                    599:                                isbroadcast = in_broadcast(dst->sin_addr, ifp);
                    600:                        RTFREE(ro->ro_rt);
                    601:                        ro->ro_rt = ro_fwd->ro_rt;
                    602:                        dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
                    603: 
                    604:                        /*
                    605:                         * If we added a default src ip earlier,
                    606:                         * which would have been gotten from the-then
                    607:                         * interface, do it again, from the new one.
                    608:                         */
                    609:                        if (fwd_rewrite_src)
                    610:                                ip->ip_src = IA_SIN(ia)->sin_addr;
                    611:                        goto pass ;
                    612:                }
                    613: #endif /* IPFIREWALL_FORWARD */
                    614:                 /*
                    615:                  * if we get here, none of the above matches, and 
                    616:                  * we have to drop the pkt
                    617:                  */
                    618:                m_freem(m);
                    619:                 error = EACCES; /* not sure this is the right error msg */
                    620:                 goto done;
                    621:        }
                    622: #endif /* COMPAT_IPFW */
                    623: 
                    624: pass:
                    625:        /*
                    626:         * If small enough for interface, can just send directly.
                    627:         */
                    628:        if ((u_short)ip->ip_len <= ifp->if_mtu) {
                    629:                ip->ip_len = htons((u_short)ip->ip_len);
                    630:                ip->ip_off = htons((u_short)ip->ip_off);
                    631:                ip->ip_sum = 0;
                    632:                ip->ip_sum = in_cksum(m, hlen);
                    633:                error = dlil_output(dl_tag, m, (void *) ro->ro_rt,
                    634:                                    (struct sockaddr *)dst, 0);
                    635:                goto done;
                    636:        }
                    637:        /*
                    638:         * Too large for interface; fragment if possible.
                    639:         * Must be able to put at least 8 bytes per fragment.
                    640:         */
                    641:        if (ip->ip_off & IP_DF) {
                    642:                error = EMSGSIZE;
                    643:                /*
                    644:                 * This case can happen if the user changed the MTU
                    645:                 * of an interface after enabling IP on it.  Because
                    646:                 * most netifs don't keep track of routes pointing to
                    647:                 * them, there is no way for one to update all its
                    648:                 * routes when the MTU is changed.
                    649:                 */
                    650:                if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST))
                    651:                    && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU)
                    652:                    && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
                    653:                        ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
                    654:                }
                    655:                ipstat.ips_cantfrag++;
                    656:                goto bad;
                    657:        }
                    658:        len = (ifp->if_mtu - hlen) &~ 7;
                    659:        if (len < 8) {
                    660:                error = EMSGSIZE;
                    661:                goto bad;
                    662:        }
                    663: 
                    664:     {
                    665:        int mhlen, firstlen = len;
                    666:        struct mbuf **mnext = &m->m_nextpkt;
                    667: 
                    668:        /*
                    669:         * Loop through length of segment after first fragment,
                    670:         * make new header and copy data of each part and link onto chain.
                    671:         */
                    672:        m0 = m;
                    673:        mhlen = sizeof (struct ip);
                    674:        for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
                    675:                MGETHDR(m, M_DONTWAIT, MT_HEADER);
                    676:                if (m == 0) {
                    677:                        error = ENOBUFS;
                    678:                        ipstat.ips_odropped++;
                    679:                        goto sendorfree;
                    680:                }
                    681:                m->m_flags |= (m0->m_flags & M_MCAST);
                    682:                m->m_data += max_linkhdr;
                    683:                mhip = mtod(m, struct ip *);
                    684:                *mhip = *ip;
                    685:                if (hlen > sizeof (struct ip)) {
                    686:                        mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
                    687:                        mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2);
                    688:                }
                    689:                m->m_len = mhlen;
                    690:                mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
                    691:                if (ip->ip_off & IP_MF)
                    692:                        mhip->ip_off |= IP_MF;
                    693:                if (off + len >= (u_short)ip->ip_len)
                    694:                        len = (u_short)ip->ip_len - off;
                    695:                else
                    696:                        mhip->ip_off |= IP_MF;
                    697:                mhip->ip_len = htons((u_short)(len + mhlen));
                    698:                m->m_next = m_copy(m0, off, len);
                    699:                if (m->m_next == 0) {
                    700:                        (void) m_free(m);
                    701:                        error = ENOBUFS;        /* ??? */
                    702:                        ipstat.ips_odropped++;
                    703:                        goto sendorfree;
                    704:                }
                    705:                m->m_pkthdr.len = mhlen + len;
                    706:                m->m_pkthdr.rcvif = (struct ifnet *)0;
                    707:                mhip->ip_off = htons((u_short)mhip->ip_off);
                    708:                mhip->ip_sum = 0;
                    709:                mhip->ip_sum = in_cksum(m, mhlen);
                    710:                *mnext = m;
                    711:                mnext = &m->m_nextpkt;
                    712:                ipstat.ips_ofragments++;
                    713:        }
                    714:        /*
                    715:         * Update first fragment by trimming what's been copied out
                    716:         * and updating header, then send each fragment (in order).
                    717:         */
                    718:        m = m0;
                    719:        m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
                    720:        m->m_pkthdr.len = hlen + firstlen;
                    721:        ip->ip_len = htons((u_short)m->m_pkthdr.len);
                    722:        ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
                    723:        ip->ip_sum = 0;
                    724:        ip->ip_sum = in_cksum(m, hlen);
                    725: 
                    726: sendorfree:
                    727:        for (m = m0; m; m = m0) {
                    728:                m0 = m->m_nextpkt;
                    729:                m->m_nextpkt = 0;
                    730:                if (error == 0)
                    731:                    error = dlil_output(dl_tag, m, (void *) ro->ro_rt,
                    732:                                        (struct sockaddr *)dst, 0);
                    733:                else
                    734:                        m_freem(m);
                    735:        }
                    736: 
                    737:        if (error == 0)
                    738:                ipstat.ips_fragmented++;
                    739:     }
                    740: done:
                    741:        return (error);
                    742: bad:
                    743:        m_freem(m0);
                    744:        goto done;
                    745: }
                    746: 
                    747: /*
                    748:  * Insert IP options into preformed packet.
                    749:  * Adjust IP destination as required for IP source routing,
                    750:  * as indicated by a non-zero in_addr at the start of the options.
                    751:  *
                    752:  * XXX This routine assumes that the packet has no options in place.
                    753:  */
                    754: static struct mbuf *
                    755: ip_insertoptions(m, opt, phlen)
                    756:        register struct mbuf *m;
                    757:        struct mbuf *opt;
                    758:        int *phlen;
                    759: {
                    760:        register struct ipoption *p = mtod(opt, struct ipoption *);
                    761:        struct mbuf *n;
                    762:        register struct ip *ip = mtod(m, struct ip *);
                    763:        unsigned optlen;
                    764: 
                    765:        optlen = opt->m_len - sizeof(p->ipopt_dst);
                    766:        if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
                    767:                return (m);             /* XXX should fail */
                    768:        if (p->ipopt_dst.s_addr)
                    769:                ip->ip_dst = p->ipopt_dst;
                    770:        if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
                    771:                MGETHDR(n, M_DONTWAIT, MT_HEADER);
                    772:                if (n == 0)
                    773:                        return (m);
                    774:                n->m_pkthdr.len = m->m_pkthdr.len + optlen;
                    775:                m->m_len -= sizeof(struct ip);
                    776:                m->m_data += sizeof(struct ip);
                    777:                n->m_next = m;
                    778:                m = n;
                    779:                m->m_len = optlen + sizeof(struct ip);
                    780:                m->m_data += max_linkhdr;
                    781:                (void)memcpy(mtod(m, void *), ip, sizeof(struct ip));
                    782:        } else {
                    783:                m->m_data -= optlen;
                    784:                m->m_len += optlen;
                    785:                m->m_pkthdr.len += optlen;
                    786:                ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
                    787:        }
                    788:        ip = mtod(m, struct ip *);
                    789:        bcopy(p->ipopt_list, ip + 1, optlen);
                    790:        *phlen = sizeof(struct ip) + optlen;
                    791:        ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2);
                    792:        ip->ip_len += optlen;
                    793:        return (m);
                    794: }
                    795: 
                    796: /*
                    797:  * Copy options from ip to jp,
                    798:  * omitting those not copied during fragmentation.
                    799:  */
                    800: #if !IPFILTER && !IPFILTER_LKM
                    801: static
                    802: #endif
                    803: int
                    804: ip_optcopy(ip, jp)
                    805:        struct ip *ip, *jp;
                    806: {
                    807:        register u_char *cp, *dp;
                    808:        int opt, optlen, cnt;
                    809: 
                    810:        cp = (u_char *)(ip + 1);
                    811:        dp = (u_char *)(jp + 1);
                    812:        cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
                    813:        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                    814:                opt = cp[0];
                    815:                if (opt == IPOPT_EOL)
                    816:                        break;
                    817:                if (opt == IPOPT_NOP) {
                    818:                        /* Preserve for IP mcast tunnel's LSRR alignment. */
                    819:                        *dp++ = IPOPT_NOP;
                    820:                        optlen = 1;
                    821:                        continue;
                    822:                } else
                    823:                        optlen = cp[IPOPT_OLEN];
                    824:                /* bogus lengths should have been caught by ip_dooptions */
                    825:                if (optlen > cnt)
                    826:                        optlen = cnt;
                    827:                if (IPOPT_COPIED(opt)) {
                    828:                        bcopy(cp, dp, optlen);
                    829:                        dp += optlen;
                    830:                }
                    831:        }
                    832:        for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
                    833:                *dp++ = IPOPT_EOL;
                    834:        return (optlen);
                    835: }
                    836: 
                    837: /*
                    838:  * IP socket option processing.
                    839:  */
                    840: int
                    841: ip_ctloutput(so, sopt)
                    842:        struct socket *so;
                    843:        struct sockopt *sopt;
                    844: {
                    845:        struct  inpcb *inp = sotoinpcb(so);
                    846:        int     error, optval;
                    847: 
                    848:        error = optval = 0;
                    849:        if (sopt->sopt_level != IPPROTO_IP) {
                    850:                return (EINVAL);
                    851:        }
                    852: 
                    853:        switch (sopt->sopt_dir) {
                    854:        case SOPT_SET:
                    855:                switch (sopt->sopt_name) {
                    856:                case IP_OPTIONS:
                    857: #ifdef notyet
                    858:                case IP_RETOPTS:
                    859: #endif
                    860:                {
                    861:                        struct mbuf *m;
                    862:                        if (sopt->sopt_valsize > MLEN) {
                    863:                                error = EMSGSIZE;
                    864:                                break;
                    865:                        }
                    866:                        MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER);
                    867:                        if (m == 0) {
                    868:                                error = ENOBUFS;
                    869:                                break;
                    870:                        }
                    871:                        m->m_len = sopt->sopt_valsize;
                    872:                        error = sooptcopyin(sopt, mtod(m, char *), m->m_len,
                    873:                                            m->m_len);
                    874:                        
                    875:                        return (ip_pcbopts(sopt->sopt_name, &inp->inp_options,
                    876:                                           m));
                    877:                }
                    878: 
                    879:                case IP_TOS:
                    880:                case IP_TTL:
                    881:                case IP_RECVOPTS:
                    882:                case IP_RECVRETOPTS:
                    883:                case IP_RECVDSTADDR:
                    884:                case IP_RECVIF:
                    885:                        error = sooptcopyin(sopt, &optval, sizeof optval,
                    886:                                            sizeof optval);
                    887:                        if (error)
                    888:                                break;
                    889: 
                    890:                        switch (sopt->sopt_name) {
                    891:                        case IP_TOS:
                    892:                                inp->inp_ip_tos = optval;
                    893:                                break;
                    894: 
                    895:                        case IP_TTL:
                    896:                                inp->inp_ip_ttl = optval;
                    897:                                break;
                    898: #define        OPTSET(bit) \
                    899:        if (optval) \
                    900:                inp->inp_flags |= bit; \
                    901:        else \
                    902:                inp->inp_flags &= ~bit;
                    903: 
                    904:                        case IP_RECVOPTS:
                    905:                                OPTSET(INP_RECVOPTS);
                    906:                                break;
                    907: 
                    908:                        case IP_RECVRETOPTS:
                    909:                                OPTSET(INP_RECVRETOPTS);
                    910:                                break;
                    911: 
                    912:                        case IP_RECVDSTADDR:
                    913:                                OPTSET(INP_RECVDSTADDR);
                    914:                                break;
                    915: 
                    916:                        case IP_RECVIF:
                    917:                                OPTSET(INP_RECVIF);
                    918:                                break;
                    919:                        }
                    920:                        break;
                    921: #undef OPTSET
                    922: 
                    923:                case IP_MULTICAST_IF:
                    924:                case IP_MULTICAST_VIF:
                    925:                case IP_MULTICAST_TTL:
                    926:                case IP_MULTICAST_LOOP:
                    927:                case IP_ADD_MEMBERSHIP:
                    928:                case IP_DROP_MEMBERSHIP:
                    929:                        error = ip_setmoptions(sopt, &inp->inp_moptions);
                    930:                        break;
                    931: 
                    932:                case IP_PORTRANGE:
                    933:                        error = sooptcopyin(sopt, &optval, sizeof optval,
                    934:                                            sizeof optval);
                    935:                        if (error)
                    936:                                break;
                    937: 
                    938:                        switch (optval) {
                    939:                        case IP_PORTRANGE_DEFAULT:
                    940:                                inp->inp_flags &= ~(INP_LOWPORT);
                    941:                                inp->inp_flags &= ~(INP_HIGHPORT);
                    942:                                break;
                    943: 
                    944:                        case IP_PORTRANGE_HIGH:
                    945:                                inp->inp_flags &= ~(INP_LOWPORT);
                    946:                                inp->inp_flags |= INP_HIGHPORT;
                    947:                                break;
                    948: 
                    949:                        case IP_PORTRANGE_LOW:
                    950:                                inp->inp_flags &= ~(INP_HIGHPORT);
                    951:                                inp->inp_flags |= INP_LOWPORT;
                    952:                                break;
                    953: 
                    954:                        default:
                    955:                                error = EINVAL;
                    956:                                break;
                    957:                        }
                    958:                        break;
                    959: 
                    960:                default:
                    961:                        error = ENOPROTOOPT;
                    962:                        break;
                    963:                }
                    964:                break;
                    965: 
                    966:        case SOPT_GET:
                    967:                switch (sopt->sopt_name) {
                    968:                case IP_OPTIONS:
                    969:                case IP_RETOPTS:
                    970:                        if (inp->inp_options)
                    971:                                error = sooptcopyout(sopt, 
                    972:                                                     mtod(inp->inp_options,
                    973:                                                          char *),
                    974:                                                     inp->inp_options->m_len);
                    975:                        else
                    976:                                sopt->sopt_valsize = 0;
                    977:                        break;
                    978: 
                    979:                case IP_TOS:
                    980:                case IP_TTL:
                    981:                case IP_RECVOPTS:
                    982:                case IP_RECVRETOPTS:
                    983:                case IP_RECVDSTADDR:
                    984:                case IP_RECVIF:
                    985:                case IP_PORTRANGE:
                    986:                        switch (sopt->sopt_name) {
                    987: 
                    988:                        case IP_TOS:
                    989:                                optval = inp->inp_ip_tos;
                    990:                                break;
                    991: 
                    992:                        case IP_TTL:
                    993:                                optval = inp->inp_ip_ttl;
                    994:                                break;
                    995: 
                    996: #define        OPTBIT(bit)     (inp->inp_flags & bit ? 1 : 0)
                    997: 
                    998:                        case IP_RECVOPTS:
                    999:                                optval = OPTBIT(INP_RECVOPTS);
                   1000:                                break;
                   1001: 
                   1002:                        case IP_RECVRETOPTS:
                   1003:                                optval = OPTBIT(INP_RECVRETOPTS);
                   1004:                                break;
                   1005: 
                   1006:                        case IP_RECVDSTADDR:
                   1007:                                optval = OPTBIT(INP_RECVDSTADDR);
                   1008:                                break;
                   1009: 
                   1010:                        case IP_RECVIF:
                   1011:                                optval = OPTBIT(INP_RECVIF);
                   1012:                                break;
                   1013: 
                   1014:                        case IP_PORTRANGE:
                   1015:                                if (inp->inp_flags & INP_HIGHPORT)
                   1016:                                        optval = IP_PORTRANGE_HIGH;
                   1017:                                else if (inp->inp_flags & INP_LOWPORT)
                   1018:                                        optval = IP_PORTRANGE_LOW;
                   1019:                                else
                   1020:                                        optval = 0;
                   1021:                                break;
                   1022:                        }
                   1023:                        error = sooptcopyout(sopt, &optval, sizeof optval);
                   1024:                        break;
                   1025: 
                   1026:                case IP_MULTICAST_IF:
                   1027:                case IP_MULTICAST_VIF:
                   1028:                case IP_MULTICAST_TTL:
                   1029:                case IP_MULTICAST_LOOP:
                   1030:                case IP_ADD_MEMBERSHIP:
                   1031:                case IP_DROP_MEMBERSHIP:
                   1032:                        error = ip_getmoptions(sopt, inp->inp_moptions);
                   1033:                        break;
                   1034: 
                   1035:                default:
                   1036:                        error = ENOPROTOOPT;
                   1037:                        break;
                   1038:                }
                   1039:                break;
                   1040:        }
                   1041:        return (error);
                   1042: }
                   1043: 
                   1044: /*
                   1045:  * Set up IP options in pcb for insertion in output packets.
                   1046:  * Store in mbuf with pointer in pcbopt, adding pseudo-option
                   1047:  * with destination address if source routed.
                   1048:  */
                   1049: static int
                   1050: ip_pcbopts(optname, pcbopt, m)
                   1051:        int optname;
                   1052:        struct mbuf **pcbopt;
                   1053:        register struct mbuf *m;
                   1054: {
                   1055:        register int cnt, optlen;
                   1056:        register u_char *cp;
                   1057:        u_char opt;
                   1058: 
                   1059:        /* turn off any old options */
                   1060:        if (*pcbopt)
                   1061:                (void)m_free(*pcbopt);
                   1062:        *pcbopt = 0;
                   1063:        if (m == (struct mbuf *)0 || m->m_len == 0) {
                   1064:                /*
                   1065:                 * Only turning off any previous options.
                   1066:                 */
                   1067:                if (m)
                   1068:                        (void)m_free(m);
                   1069:                return (0);
                   1070:        }
                   1071: 
                   1072: #ifndef        vax
                   1073:        if (m->m_len % sizeof(int32_t))
                   1074:                goto bad;
                   1075: #endif
                   1076:        /*
                   1077:         * IP first-hop destination address will be stored before
                   1078:         * actual options; move other options back
                   1079:         * and clear it when none present.
                   1080:         */
                   1081:        if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
                   1082:                goto bad;
                   1083:        cnt = m->m_len;
                   1084:        m->m_len += sizeof(struct in_addr);
                   1085:        cp = mtod(m, u_char *) + sizeof(struct in_addr);
                   1086:        ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
                   1087:        bzero(mtod(m, caddr_t), sizeof(struct in_addr));
                   1088: 
                   1089:        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                   1090:                opt = cp[IPOPT_OPTVAL];
                   1091:                if (opt == IPOPT_EOL)
                   1092:                        break;
                   1093:                if (opt == IPOPT_NOP)
                   1094:                        optlen = 1;
                   1095:                else {
                   1096:                        optlen = cp[IPOPT_OLEN];
                   1097:                        if (optlen <= IPOPT_OLEN || optlen > cnt)
                   1098:                                goto bad;
                   1099:                }
                   1100:                switch (opt) {
                   1101: 
                   1102:                default:
                   1103:                        break;
                   1104: 
                   1105:                case IPOPT_LSRR:
                   1106:                case IPOPT_SSRR:
                   1107:                        /*
                   1108:                         * user process specifies route as:
                   1109:                         *      ->A->B->C->D
                   1110:                         * D must be our final destination (but we can't
                   1111:                         * check that since we may not have connected yet).
                   1112:                         * A is first hop destination, which doesn't appear in
                   1113:                         * actual IP option, but is stored before the options.
                   1114:                         */
                   1115:                        if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
                   1116:                                goto bad;
                   1117:                        m->m_len -= sizeof(struct in_addr);
                   1118:                        cnt -= sizeof(struct in_addr);
                   1119:                        optlen -= sizeof(struct in_addr);
                   1120:                        cp[IPOPT_OLEN] = optlen;
                   1121:                        /*
                   1122:                         * Move first hop before start of options.
                   1123:                         */
                   1124:                        bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
                   1125:                            sizeof(struct in_addr));
                   1126:                        /*
                   1127:                         * Then copy rest of options back
                   1128:                         * to close up the deleted entry.
                   1129:                         */
                   1130:                        ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
                   1131:                            sizeof(struct in_addr)),
                   1132:                            (caddr_t)&cp[IPOPT_OFFSET+1],
                   1133:                            (unsigned)cnt + sizeof(struct in_addr));
                   1134:                        break;
                   1135:                }
                   1136:        }
                   1137:        if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
                   1138:                goto bad;
                   1139:        *pcbopt = m;
                   1140:        return (0);
                   1141: 
                   1142: bad:
                   1143:        (void)m_free(m);
                   1144:        return (EINVAL);
                   1145: }
                   1146: 
                   1147: /*
                   1148:  * XXX
                   1149:  * The whole multicast option thing needs to be re-thought.
                   1150:  * Several of these options are equally applicable to non-multicast
                   1151:  * transmission, and one (IP_MULTICAST_TTL) totally duplicates a
                   1152:  * standard option (IP_TTL).
                   1153:  */
                   1154: /*
                   1155:  * Set the IP multicast options in response to user setsockopt().
                   1156:  */
                   1157: static int
                   1158: ip_setmoptions(sopt, imop)
                   1159:        struct sockopt *sopt;
                   1160:        struct ip_moptions **imop;
                   1161: {
                   1162:        int error = 0;
                   1163:        int i;
                   1164:        struct in_addr addr;
                   1165:        struct ip_mreq mreq;
                   1166:        struct ifnet *ifp;
                   1167:        struct ip_moptions *imo = *imop;
                   1168:        struct route ro;
                   1169:        struct sockaddr_in *dst;
                   1170:        int s;
                   1171: 
                   1172:        if (imo == NULL) {
                   1173:                /*
                   1174:                 * No multicast option buffer attached to the pcb;
                   1175:                 * allocate one and initialize to default values.
                   1176:                 */
                   1177:                imo = (struct ip_moptions*) _MALLOC(sizeof(*imo), M_IPMOPTS,
                   1178:                    M_WAITOK);
                   1179: 
                   1180:                if (imo == NULL)
                   1181:                        return (ENOBUFS);
                   1182:                *imop = imo;
                   1183:                imo->imo_multicast_ifp = NULL;
                   1184:                imo->imo_multicast_vif = -1;
                   1185:                imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
                   1186:                imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
                   1187:                imo->imo_num_memberships = 0;
                   1188:        }
                   1189: 
                   1190:        switch (sopt->sopt_name) {
                   1191:        /* store an index number for the vif you wanna use in the send */
                   1192:        case IP_MULTICAST_VIF:
                   1193:                if (legal_vif_num == 0) {
                   1194:                        error = EOPNOTSUPP;
                   1195:                        break;
                   1196:                }
                   1197:                error = sooptcopyin(sopt, &i, sizeof i, sizeof i);
                   1198:                if (error)
                   1199:                        break;
                   1200:                if (!legal_vif_num(i) && (i != -1)) {
                   1201:                        error = EINVAL;
                   1202:                        break;
                   1203:                }
                   1204:                imo->imo_multicast_vif = i;
                   1205:                break;
                   1206: 
                   1207:        case IP_MULTICAST_IF:
                   1208:                /*
                   1209:                 * Select the interface for outgoing multicast packets.
                   1210:                 */
                   1211:                error = sooptcopyin(sopt, &addr, sizeof addr, sizeof addr);
                   1212:                if (error)
                   1213:                        break;
                   1214:                /*
                   1215:                 * INADDR_ANY is used to remove a previous selection.
                   1216:                 * When no interface is selected, a default one is
                   1217:                 * chosen every time a multicast packet is sent.
                   1218:                 */
                   1219:                if (addr.s_addr == INADDR_ANY) {
                   1220:                        imo->imo_multicast_ifp = NULL;
                   1221:                        break;
                   1222:                }
                   1223:                /*
                   1224:                 * The selected interface is identified by its local
                   1225:                 * IP address.  Find the interface and confirm that
                   1226:                 * it supports multicasting.
                   1227:                 */
                   1228:                s = splimp();
                   1229:                INADDR_TO_IFP(addr, ifp);
                   1230:                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
                   1231:                        splx(s);
                   1232:                        error = EADDRNOTAVAIL;
                   1233:                        break;
                   1234:                }
                   1235:                imo->imo_multicast_ifp = ifp;
                   1236:                splx(s);
                   1237:                break;
                   1238: 
                   1239:        case IP_MULTICAST_TTL:
                   1240:                /*
                   1241:                 * Set the IP time-to-live for outgoing multicast packets.
                   1242:                 * The original multicast API required a char argument,
                   1243:                 * which is inconsistent with the rest of the socket API.
                   1244:                 * We allow either a char or an int.
                   1245:                 */
                   1246:                if (sopt->sopt_valsize == 1) {
                   1247:                        u_char ttl;
                   1248:                        error = sooptcopyin(sopt, &ttl, 1, 1);
                   1249:                        if (error)
                   1250:                                break;
                   1251:                        imo->imo_multicast_ttl = ttl;
                   1252:                } else {
                   1253:                        u_int ttl;
                   1254:                        error = sooptcopyin(sopt, &ttl, sizeof ttl, 
                   1255:                                            sizeof ttl);
                   1256:                        if (error)
                   1257:                                break;
                   1258:                        if (ttl > 255)
                   1259:                                error = EINVAL;
                   1260:                        else
                   1261:                                imo->imo_multicast_ttl = ttl;
                   1262:                }
                   1263:                break;
                   1264: 
                   1265:        case IP_MULTICAST_LOOP:
                   1266:                /*
                   1267:                 * Set the loopback flag for outgoing multicast packets.
                   1268:                 * Must be zero or one.  The original multicast API required a
                   1269:                 * char argument, which is inconsistent with the rest
                   1270:                 * of the socket API.  We allow either a char or an int.
                   1271:                 */
                   1272:                if (sopt->sopt_valsize == 1) {
                   1273:                        u_char loop;
                   1274:                        error = sooptcopyin(sopt, &loop, 1, 1);
                   1275:                        if (error)
                   1276:                                break;
                   1277:                        imo->imo_multicast_loop = !!loop;
                   1278:                } else {
                   1279:                        u_int loop;
                   1280:                        error = sooptcopyin(sopt, &loop, sizeof loop,
                   1281:                                            sizeof loop);
                   1282:                        if (error)
                   1283:                                break;
                   1284:                        imo->imo_multicast_loop = !!loop;
                   1285:                }
                   1286:                break;
                   1287: 
                   1288:        case IP_ADD_MEMBERSHIP:
                   1289:                /*
                   1290:                 * Add a multicast group membership.
                   1291:                 * Group must be a valid IP multicast address.
                   1292:                 */
                   1293:                error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
                   1294:                if (error)
                   1295:                        break;
                   1296: 
                   1297:                if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
                   1298:                        error = EINVAL;
                   1299:                        break;
                   1300:                }
                   1301:                s = splimp();
                   1302:                /*
                   1303:                 * If no interface address was provided, use the interface of
                   1304:                 * the route to the given multicast address.
                   1305:                 */
                   1306:                if (mreq.imr_interface.s_addr == INADDR_ANY) {
                   1307:                        bzero((caddr_t)&ro, sizeof(ro));
                   1308:                        dst = (struct sockaddr_in *)&ro.ro_dst;
                   1309:                        dst->sin_len = sizeof(*dst);
                   1310:                        dst->sin_family = AF_INET;
                   1311:                        dst->sin_addr = mreq.imr_multiaddr;
                   1312:                        rtalloc(&ro);
                   1313:                        if (ro.ro_rt == NULL) {
                   1314:                                error = EADDRNOTAVAIL;
                   1315:                                splx(s);
                   1316:                                break;
                   1317:                        }
                   1318:                        ifp = ro.ro_rt->rt_ifp;
                   1319:                        rtfree(ro.ro_rt);
                   1320:                }
                   1321:                else {
                   1322:                        INADDR_TO_IFP(mreq.imr_interface, ifp);
                   1323:                }
                   1324: 
                   1325:                /*
                   1326:                 * See if we found an interface, and confirm that it
                   1327:                 * supports multicast.
                   1328:                 */
                   1329:                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
                   1330:                        error = EADDRNOTAVAIL;
                   1331:                        splx(s);
                   1332:                        break;
                   1333:                }
                   1334:                /*
                   1335:                 * See if the membership already exists or if all the
                   1336:                 * membership slots are full.
                   1337:                 */
                   1338:                for (i = 0; i < imo->imo_num_memberships; ++i) {
                   1339:                        if (imo->imo_membership[i]->inm_ifp == ifp &&
                   1340:                            imo->imo_membership[i]->inm_addr.s_addr
                   1341:                                                == mreq.imr_multiaddr.s_addr)
                   1342:                                break;
                   1343:                }
                   1344:                if (i < imo->imo_num_memberships) {
                   1345:                        error = EADDRINUSE;
                   1346:                        splx(s);
                   1347:                        break;
                   1348:                }
                   1349:                if (i == IP_MAX_MEMBERSHIPS) {
                   1350:                        error = ETOOMANYREFS;
                   1351:                        splx(s);
                   1352:                        break;
                   1353:                }
                   1354:                /*
                   1355:                 * Everything looks good; add a new record to the multicast
                   1356:                 * address list for the given interface.
                   1357:                 */
                   1358:                if ((imo->imo_membership[i] =
                   1359:                    in_addmulti(&mreq.imr_multiaddr, ifp)) == NULL) {
                   1360:                        error = ENOBUFS;
                   1361:                        splx(s);
                   1362:                        break;
                   1363:                }
                   1364:                ++imo->imo_num_memberships;
                   1365:                splx(s);
                   1366:                break;
                   1367: 
                   1368:        case IP_DROP_MEMBERSHIP:
                   1369:                /*
                   1370:                 * Drop a multicast group membership.
                   1371:                 * Group must be a valid IP multicast address.
                   1372:                 */
                   1373:                error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
                   1374:                if (error)
                   1375:                        break;
                   1376: 
                   1377:                if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
                   1378:                        error = EINVAL;
                   1379:                        break;
                   1380:                }
                   1381: 
                   1382:                s = splimp();
                   1383:                /*
                   1384:                 * If an interface address was specified, get a pointer
                   1385:                 * to its ifnet structure.
                   1386:                 */
                   1387:                if (mreq.imr_interface.s_addr == INADDR_ANY)
                   1388:                        ifp = NULL;
                   1389:                else {
                   1390:                        INADDR_TO_IFP(mreq.imr_interface, ifp);
                   1391:                        if (ifp == NULL) {
                   1392:                                error = EADDRNOTAVAIL;
                   1393:                                splx(s);
                   1394:                                break;
                   1395:                        }
                   1396:                }
                   1397:                /*
                   1398:                 * Find the membership in the membership array.
                   1399:                 */
                   1400:                for (i = 0; i < imo->imo_num_memberships; ++i) {
                   1401:                        if ((ifp == NULL ||
                   1402:                             imo->imo_membership[i]->inm_ifp == ifp) &&
                   1403:                             imo->imo_membership[i]->inm_addr.s_addr ==
                   1404:                             mreq.imr_multiaddr.s_addr)
                   1405:                                break;
                   1406:                }
                   1407:                if (i == imo->imo_num_memberships) {
                   1408:                        error = EADDRNOTAVAIL;
                   1409:                        splx(s);
                   1410:                        break;
                   1411:                }
                   1412:                /*
                   1413:                 * Give up the multicast address record to which the
                   1414:                 * membership points.
                   1415:                 */
                   1416:                in_delmulti(imo->imo_membership[i]);
                   1417:                /*
                   1418:                 * Remove the gap in the membership array.
                   1419:                 */
                   1420:                for (++i; i < imo->imo_num_memberships; ++i)
                   1421:                        imo->imo_membership[i-1] = imo->imo_membership[i];
                   1422:                --imo->imo_num_memberships;
                   1423:                splx(s);
                   1424:                break;
                   1425: 
                   1426:        default:
                   1427:                error = EOPNOTSUPP;
                   1428:                break;
                   1429:        }
                   1430: 
                   1431:        /*
                   1432:         * If all options have default values, no need to keep the mbuf.
                   1433:         */
                   1434:        if (imo->imo_multicast_ifp == NULL &&
                   1435:            imo->imo_multicast_vif == -1 &&
                   1436:            imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
                   1437:            imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
                   1438:            imo->imo_num_memberships == 0) {
                   1439:                FREE(*imop, M_IPMOPTS);
                   1440:                *imop = NULL;
                   1441:        }
                   1442: 
                   1443:        return (error);
                   1444: }
                   1445: 
                   1446: /*
                   1447:  * Return the IP multicast options in response to user getsockopt().
                   1448:  */
                   1449: static int
                   1450: ip_getmoptions(sopt, imo)
                   1451:        struct sockopt *sopt;
                   1452:        register struct ip_moptions *imo;
                   1453: {
                   1454:        struct in_addr addr;
                   1455:        struct in_ifaddr *ia;
                   1456:        int error, optval;
                   1457:        u_char coptval;
                   1458: 
                   1459:        error = 0;
                   1460:        switch (sopt->sopt_name) {
                   1461:        case IP_MULTICAST_VIF: 
                   1462:                if (imo != NULL)
                   1463:                        optval = imo->imo_multicast_vif;
                   1464:                else
                   1465:                        optval = -1;
                   1466:                error = sooptcopyout(sopt, &optval, sizeof optval);
                   1467:                break;
                   1468: 
                   1469:        case IP_MULTICAST_IF:
                   1470:                if (imo == NULL || imo->imo_multicast_ifp == NULL)
                   1471:                        addr.s_addr = INADDR_ANY;
                   1472:                else {
                   1473:                        IFP_TO_IA(imo->imo_multicast_ifp, ia);
                   1474:                        addr.s_addr = (ia == NULL) ? INADDR_ANY
                   1475:                                : IA_SIN(ia)->sin_addr.s_addr;
                   1476:                }
                   1477:                error = sooptcopyout(sopt, &addr, sizeof addr);
                   1478:                break;
                   1479: 
                   1480:        case IP_MULTICAST_TTL:
                   1481:                if (imo == 0)
                   1482:                        optval = coptval = IP_DEFAULT_MULTICAST_TTL;
                   1483:                else
                   1484:                        optval = coptval = imo->imo_multicast_ttl;
                   1485:                if (sopt->sopt_valsize == 1)
                   1486:                        error = sooptcopyout(sopt, &coptval, 1);
                   1487:                else
                   1488:                        error = sooptcopyout(sopt, &optval, sizeof optval);
                   1489:                break;
                   1490: 
                   1491:        case IP_MULTICAST_LOOP:
                   1492:                if (imo == 0)
                   1493:                        optval = coptval = IP_DEFAULT_MULTICAST_LOOP;
                   1494:                else
                   1495:                        optval = coptval = imo->imo_multicast_loop;
                   1496:                if (sopt->sopt_valsize == 1)
                   1497:                        error = sooptcopyout(sopt, &coptval, 1);
                   1498:                else
                   1499:                        error = sooptcopyout(sopt, &optval, sizeof optval);
                   1500:                break;
                   1501: 
                   1502:        default:
                   1503:                error = ENOPROTOOPT;
                   1504:                break;
                   1505:        }
                   1506:        return (error);
                   1507: }
                   1508: 
                   1509: /*
                   1510:  * Discard the IP multicast options.
                   1511:  */
                   1512: void
                   1513: ip_freemoptions(imo)
                   1514:        register struct ip_moptions *imo;
                   1515: {
                   1516:        register int i;
                   1517: 
                   1518:        if (imo != NULL) {
                   1519:                for (i = 0; i < imo->imo_num_memberships; ++i)
                   1520:                        in_delmulti(imo->imo_membership[i]);
                   1521:                FREE(imo, M_IPMOPTS);
                   1522:        }
                   1523: }
                   1524: 
                   1525: /*
                   1526:  * Routine called from ip_output() to loop back a copy of an IP multicast
                   1527:  * packet to the input queue of a specified interface.  Note that this
                   1528:  * calls the output routine of the loopback "driver", but with an interface
                   1529:  * pointer that might NOT be a loopback interface -- evil, but easier than
                   1530:  * replicating that code here.
                   1531:  */
                   1532: static void
                   1533: ip_mloopback(ifp, m, dst, hlen)
                   1534:        struct ifnet *ifp;
                   1535:        register struct mbuf *m;
                   1536:        register struct sockaddr_in *dst;
                   1537:        int hlen;
                   1538: {
                   1539:        register struct ip *ip;
                   1540:        struct mbuf *copym;
                   1541: 
                   1542:        copym = m_copy(m, 0, M_COPYALL);
                   1543:        if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen))
                   1544:                copym = m_pullup(copym, hlen);
                   1545:        if (copym != NULL) {
                   1546:                /*
                   1547:                 * We don't bother to fragment if the IP length is greater
                   1548:                 * than the interface's MTU.  Can this possibly matter?
                   1549:                 */
                   1550:                ip = mtod(copym, struct ip *);
                   1551:                ip->ip_len = htons((u_short)ip->ip_len);
                   1552:                ip->ip_off = htons((u_short)ip->ip_off);
                   1553:                ip->ip_sum = 0;
                   1554:                ip->ip_sum = in_cksum(copym, hlen);
                   1555: 
                   1556:                /*
                   1557:                 * NB:
                   1558:                 * It's not clear whether there are any lingering
                   1559:                 * reentrancy problems in other areas which might
                   1560:                 * be exposed by using ip_input directly (in
                   1561:                 * particular, everything which modifies the packet
                   1562:                 * in-place).  Yet another option is using the
                   1563:                 * protosw directly to deliver the looped back
                   1564:                 * packet.  For the moment, we'll err on the side
                   1565:                 * of safety by using if_simloop().
                   1566:                 */
                   1567: #if 1 /* XXX */
                   1568:                if (dst->sin_family != AF_INET) {
                   1569:                        printf("ip_mloopback: bad address family %d\n",
                   1570:                                                dst->sin_family);
                   1571:                        dst->sin_family = AF_INET;
                   1572:                }
                   1573: #endif
                   1574: 
                   1575:                /*
                   1576:                 * TedW: 
                   1577:                 * We need to send all loopback traffic down to dlil in case 
                   1578:                 * a filter has tapped-in.
                   1579:                 */
                   1580: 
                   1581:                if (lo_dl_tag == 0)
                   1582:                    dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET, &lo_dl_tag);
                   1583: 
                   1584:                if (lo_dl_tag)
                   1585:                    dlil_output(lo_dl_tag, copym, 0, (struct sockaddr *) dst, 0);
                   1586:                else {
                   1587:                    printf("Warning: ip_output call to dlil_find_dltag failed!\n");
                   1588:                    m_freem(copym);
                   1589:                }
                   1590: 
                   1591: /*             if_simloop(ifp, copym, (struct sockaddr *)dst, 0);*/
                   1592:        }
                   1593: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.