Annotation of XNU/bsd/netinet/in.c, revision 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, 1991, 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:  *     @(#)in.c        8.4 (Berkeley) 1/9/95
        !            55:  */
        !            56: 
        !            57: #include <sys/param.h>
        !            58: #include <sys/systm.h>
        !            59: #include <sys/sockio.h>
        !            60: #include <sys/socketvar.h>
        !            61: #include <sys/malloc.h>
        !            62: #include <sys/proc.h>
        !            63: #include <sys/socket.h>
        !            64: #include <sys/kernel.h>
        !            65: #include <sys/sysctl.h>
        !            66: 
        !            67: #include <net/if.h>
        !            68: #include <net/route.h>
        !            69: 
        !            70: #include <netinet/in.h>
        !            71: #include <netinet/in_var.h>
        !            72: #include <netinet/in_pcb.h>
        !            73: 
        !            74: #include <netinet/igmp_var.h>
        !            75: #include <net/dlil.h>
        !            76: 
        !            77: #include <netinet/ip_var.h>
        !            78: 
        !            79: #include <netinet/tcp.h>
        !            80: #include <netinet/tcp_timer.h>
        !            81: #include <netinet/tcp_var.h>
        !            82: 
        !            83: #include <sys/file.h>
        !            84: 
        !            85: 
        !            86: /*
        !            87: static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
        !            88: */
        !            89: 
        !            90: static void    in_socktrim __P((struct sockaddr_in *));
        !            91: static int     in_ifinit __P((struct ifnet *,
        !            92:            struct in_ifaddr *, struct sockaddr_in *, int));
        !            93: 
        !            94: static int subnetsarelocal = 0;
        !            95: SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, 
        !            96:        &subnetsarelocal, 0, "");
        !            97: 
        !            98: struct in_multihead in_multihead; /* XXX BSS initialization */
        !            99: 
        !           100: extern void arp_rtrequest();
        !           101: 
        !           102: 
        !           103: /*
        !           104:  * Return 1 if an internet address is for a ``local'' host
        !           105:  * (one to which we have a connection).  If subnetsarelocal
        !           106:  * is true, this includes other subnets of the local net.
        !           107:  * Otherwise, it includes only the directly-connected (sub)nets.
        !           108:  */
        !           109: int
        !           110: in_localaddr(in)
        !           111:        struct in_addr in;
        !           112: {
        !           113:        register u_long i = ntohl(in.s_addr);
        !           114:        register struct in_ifaddr *ia;
        !           115: 
        !           116:        if (subnetsarelocal) {
        !           117:                for (ia = in_ifaddrhead.tqh_first; ia; 
        !           118:                     ia = ia->ia_link.tqe_next)
        !           119:                        if ((i & ia->ia_netmask) == ia->ia_net)
        !           120:                                return (1);
        !           121:        } else {
        !           122:                for (ia = in_ifaddrhead.tqh_first; ia;
        !           123:                     ia = ia->ia_link.tqe_next)
        !           124:                        if ((i & ia->ia_subnetmask) == ia->ia_subnet)
        !           125:                                return (1);
        !           126:        }
        !           127:        return (0);
        !           128: }
        !           129: 
        !           130: /*
        !           131:  * Determine whether an IP address is in a reserved set of addresses
        !           132:  * that may not be forwarded, or whether datagrams to that destination
        !           133:  * may be forwarded.
        !           134:  */
        !           135: int
        !           136: in_canforward(in)
        !           137:        struct in_addr in;
        !           138: {
        !           139:        register u_long i = ntohl(in.s_addr);
        !           140:        register u_long net;
        !           141: 
        !           142:        if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i))
        !           143:                return (0);
        !           144:        if (IN_CLASSA(i)) {
        !           145:                net = i & IN_CLASSA_NET;
        !           146:                if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
        !           147:                        return (0);
        !           148:        }
        !           149:        return (1);
        !           150: }
        !           151: 
        !           152: /*
        !           153:  * Trim a mask in a sockaddr
        !           154:  */
        !           155: static void
        !           156: in_socktrim(ap)
        !           157: struct sockaddr_in *ap;
        !           158: {
        !           159:     register char *cplim = (char *) &ap->sin_addr;
        !           160:     register char *cp = (char *) (&ap->sin_addr + 1);
        !           161: 
        !           162:     ap->sin_len = 0;
        !           163:     while (--cp >= cplim)
        !           164:         if (*cp) {
        !           165:            (ap)->sin_len = cp - (char *) (ap) + 1;
        !           166:            break;
        !           167:        }
        !           168: }
        !           169: 
        !           170: static int in_interfaces;      /* number of external internet interfaces */
        !           171: 
        !           172: /*
        !           173:  * Generic internet control operations (ioctl's).
        !           174:  * Ifp is 0 if not an interface-specific ioctl.
        !           175:  */
        !           176: /* ARGSUSED */
        !           177: int
        !           178: in_control(so, cmd, data, ifp, p)
        !           179:        struct socket *so;
        !           180:        u_long cmd;
        !           181:        caddr_t data;
        !           182:        register struct ifnet *ifp;
        !           183:        struct proc *p;
        !           184: {
        !           185:        register struct ifreq *ifr = (struct ifreq *)data;
        !           186:        register struct in_ifaddr *ia = 0, *iap;
        !           187:        register struct ifaddr *ifa;
        !           188:        struct in_ifaddr *oia;
        !           189:        struct in_aliasreq *ifra = (struct in_aliasreq *)data;
        !           190:        struct sockaddr_in oldaddr;
        !           191:        int error, hostIsNew, maskIsNew, s;
        !           192:        u_long i, dl_tag;
        !           193: 
        !           194:        /*
        !           195:         * Find address for this interface, if it exists.
        !           196:         *
        !           197:         * If an alias address was specified, find that one instead of
        !           198:         * the first one on the interface.
        !           199:         */
        !           200:        if (ifp)
        !           201:                for (iap = in_ifaddrhead.tqh_first; iap; 
        !           202:                     iap = iap->ia_link.tqe_next)
        !           203:                        if (iap->ia_ifp == ifp) {
        !           204:                                if (((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr ==
        !           205:                                    iap->ia_addr.sin_addr.s_addr) {
        !           206:                                        ia = iap;
        !           207:                                        break;
        !           208:                                } else if (ia == NULL) {
        !           209:                                        ia = iap;
        !           210:                                        if (ifr->ifr_addr.sa_family != AF_INET)
        !           211:                                                break;
        !           212:                                }
        !           213:                        }
        !           214: 
        !           215:        switch (cmd) {
        !           216: 
        !           217:        case SIOCAIFADDR:
        !           218:        case SIOCDIFADDR:
        !           219:                if (ifp == 0)
        !           220:                        return (EADDRNOTAVAIL);
        !           221:                if (ifra->ifra_addr.sin_family == AF_INET) {
        !           222:                        for (oia = ia; ia; ia = ia->ia_link.tqe_next) {
        !           223:                                if (ia->ia_ifp == ifp  &&
        !           224:                                    ia->ia_addr.sin_addr.s_addr ==
        !           225:                                    ifra->ifra_addr.sin_addr.s_addr)
        !           226:                                        break;
        !           227:                        }
        !           228:                        if ((ifp->if_flags & IFF_POINTOPOINT)
        !           229:                            && (cmd == SIOCAIFADDR)
        !           230:                            && (ifra->ifra_dstaddr.sin_addr.s_addr
        !           231:                                == INADDR_ANY)) {
        !           232:                                return EDESTADDRREQ;
        !           233:                        }
        !           234:                }
        !           235:                if (cmd == SIOCDIFADDR && ia == 0)
        !           236:                        return (EADDRNOTAVAIL);
        !           237:                /* FALLTHROUGH */
        !           238:        case SIOCSIFADDR:
        !           239:        case SIOCSIFNETMASK:
        !           240:        case SIOCSIFDSTADDR:
        !           241: 
        !           242: #if ISFB31
        !           243:                if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
        !           244:                        return error;
        !           245: #else
        !           246:                if ((so->so_state & SS_PRIV) == 0)
        !           247:                        return (EPERM);
        !           248: #endif
        !           249: 
        !           250:                if (ifp == 0)
        !           251:                        return (EADDRNOTAVAIL);
        !           252:                if (ia == (struct in_ifaddr *)0) {
        !           253:                        ia = (struct in_ifaddr *)
        !           254:                                _MALLOC(sizeof *ia, M_IFADDR, M_WAITOK);
        !           255:                        if (ia == (struct in_ifaddr *)NULL)
        !           256:                                return (ENOBUFS);
        !           257:                        bzero((caddr_t)ia, sizeof *ia);
        !           258:                        /*
        !           259:                         * Protect from ipintr() traversing address list
        !           260:                         * while we're modifying it.
        !           261:                         */
        !           262:                        s = splnet();
        !           263:                        
        !           264:                        TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link);
        !           265:                        ifa = &ia->ia_ifa;
        !           266:                        TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
        !           267: 
        !           268: /*
        !           269:  * Temorary code for protocol attachment XXX
        !           270:  */
        !           271:                        
        !           272:                        if (strcmp(ifp->if_name, "en") == 0)
        !           273:                            dl_tag = ether_attach_inet(ifp);
        !           274:                        
        !           275:                        if (strcmp(ifp->if_name, "lo") == 0)
        !           276:                            dl_tag = lo_attach_inet(ifp);
        !           277: /* End of temp code */
        !           278: 
        !           279:                        ifa->ifa_dlt = dl_tag;
        !           280:                        ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
        !           281:                        ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
        !           282:                        ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
        !           283:                        ia->ia_sockmask.sin_len = 8;
        !           284:                        if (ifp->if_flags & IFF_BROADCAST) {
        !           285:                                ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
        !           286:                                ia->ia_broadaddr.sin_family = AF_INET;
        !           287:                        }
        !           288:                        ia->ia_ifp = ifp;
        !           289:                        if (!(ifp->if_flags & IFF_LOOPBACK))
        !           290:                                in_interfaces++;
        !           291:                        splx(s);
        !           292:                }
        !           293:                break;
        !           294: 
        !           295:        case SIOCSIFBRDADDR:
        !           296: #if ISFB31
        !           297:                if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
        !           298:                        return error;
        !           299: #else
        !           300:                if ((so->so_state & SS_PRIV) == 0)
        !           301:                        return (EPERM);
        !           302: #endif
        !           303:                /* FALLTHROUGH */
        !           304: 
        !           305:        case SIOCGIFADDR:
        !           306:        case SIOCGIFNETMASK:
        !           307:        case SIOCGIFDSTADDR:
        !           308:        case SIOCGIFBRDADDR:
        !           309:                if (ia == (struct in_ifaddr *)0)
        !           310:                        return (EADDRNOTAVAIL);
        !           311:                break;
        !           312:        }
        !           313:        switch (cmd) {
        !           314: 
        !           315:        case SIOCGIFADDR:
        !           316:                *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
        !           317:                break;
        !           318: 
        !           319:        case SIOCGIFBRDADDR:
        !           320:                if ((ifp->if_flags & IFF_BROADCAST) == 0)
        !           321:                        return (EINVAL);
        !           322:                *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
        !           323:                break;
        !           324: 
        !           325:        case SIOCGIFDSTADDR:
        !           326:                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
        !           327:                        return (EINVAL);
        !           328:                *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
        !           329:                break;
        !           330: 
        !           331:        case SIOCGIFNETMASK:
        !           332:                *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
        !           333:                break;
        !           334: 
        !           335:        case SIOCSIFDSTADDR:
        !           336:                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
        !           337:                        return (EINVAL);
        !           338:                oldaddr = ia->ia_dstaddr;
        !           339:                ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
        !           340:                if (ifp->if_ioctl && 
        !           341:                    (error = dlil_ioctl(0, ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
        !           342:                        ia->ia_dstaddr = oldaddr;
        !           343:                        return (error);
        !           344:                }
        !           345:                if (ia->ia_flags & IFA_ROUTE) {
        !           346:                        ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
        !           347:                        rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
        !           348:                        ia->ia_ifa.ifa_dstaddr =
        !           349:                                        (struct sockaddr *)&ia->ia_dstaddr;
        !           350:                        rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
        !           351:                }
        !           352:                break;
        !           353: 
        !           354:        case SIOCSIFBRDADDR:
        !           355:                if ((ifp->if_flags & IFF_BROADCAST) == 0)
        !           356:                        return (EINVAL);
        !           357:                ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
        !           358:                break;
        !           359: 
        !           360:        case SIOCSIFADDR:
        !           361:                return (in_ifinit(ifp, ia,
        !           362:                    (struct sockaddr_in *) &ifr->ifr_addr, 1));
        !           363: 
        !           364:        case SIOCSIFNETMASK:
        !           365:                i = ifra->ifra_addr.sin_addr.s_addr;
        !           366:                ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
        !           367:                break;
        !           368: 
        !           369:        case SIOCAIFADDR:
        !           370:                maskIsNew = 0;
        !           371:                hostIsNew = 1;
        !           372:                error = 0;
        !           373:                if (ia->ia_addr.sin_family == AF_INET) {
        !           374:                        if (ifra->ifra_addr.sin_len == 0) {
        !           375:                                ifra->ifra_addr = ia->ia_addr;
        !           376:                                hostIsNew = 0;
        !           377:                        } else if (ifra->ifra_addr.sin_addr.s_addr ==
        !           378:                                               ia->ia_addr.sin_addr.s_addr)
        !           379:                                hostIsNew = 0;
        !           380:                }
        !           381:                if (ifra->ifra_mask.sin_len) {
        !           382:                        in_ifscrub(ifp, ia);
        !           383:                        ia->ia_sockmask = ifra->ifra_mask;
        !           384:                        ia->ia_subnetmask =
        !           385:                             ntohl(ia->ia_sockmask.sin_addr.s_addr);
        !           386:                        maskIsNew = 1;
        !           387:                }
        !           388:                if ((ifp->if_flags & IFF_POINTOPOINT) &&
        !           389:                    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
        !           390:                        in_ifscrub(ifp, ia);
        !           391:                        ia->ia_dstaddr = ifra->ifra_dstaddr;
        !           392:                        maskIsNew  = 1; /* We lie; but the effect's the same */
        !           393:                }
        !           394:                if (ifra->ifra_addr.sin_family == AF_INET &&
        !           395:                    (hostIsNew || maskIsNew)) {
        !           396:                        error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
        !           397:                }
        !           398:                if ((ifp->if_flags & IFF_BROADCAST) &&
        !           399:                    (ifra->ifra_broadaddr.sin_family == AF_INET))
        !           400:                        ia->ia_broadaddr = ifra->ifra_broadaddr;
        !           401:                return (error);
        !           402: 
        !           403:        case SIOCDIFADDR:
        !           404:                in_ifscrub(ifp, ia);
        !           405:                /*
        !           406:                 * Protect from ipintr() traversing address list
        !           407:                 * while we're modifying it.
        !           408:                 */
        !           409:                s = splnet();
        !           410: 
        !           411:                ifa = &ia->ia_ifa;
        !           412:                TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
        !           413:                oia = ia;
        !           414:                TAILQ_REMOVE(&in_ifaddrhead, oia, ia_link);
        !           415:                IFAFREE(&oia->ia_ifa);
        !           416:                splx(s);
        !           417:                break;
        !           418: 
        !           419:     case SIOCSETOT: {
        !           420:         /*
        !           421:          * Inspiration from tcp_ctloutput() and ip_ctloutput()
        !           422:          */
        !           423:         struct inpcb   *inp, *cloned_inp;
        !           424:         int                    error = 0;
        !           425:         int                    cloned_fd = *(int *)data;
        !           426: 
        !           427:         s = splnet();          /* XXX */
        !           428:         inp = sotoinpcb(so);
        !           429:         if (inp == NULL) {
        !           430:             splx(s);
        !           431:             break;
        !           432:         }
        !           433: 
        !           434:         /* let's make sure it's either -1 or a valid file descriptor */
        !           435:         if (cloned_fd != -1) {
        !           436:             struct socket      *cloned_so;
        !           437:             struct file     *cloned_fp;
        !           438:             error = getsock(p->p_fd, cloned_fd, &cloned_fp);
        !           439:             if (error){
        !           440:                 splx(s);
        !           441:                 break;
        !           442:             }
        !           443:             cloned_so = (struct socket *)cloned_fp->f_data;
        !           444:             cloned_inp = sotoinpcb(cloned_so);
        !           445:         } else {
        !           446:             cloned_inp = NULL;
        !           447:         }
        !           448: 
        !           449:          if (cloned_inp == NULL) {
        !           450:             /* OT always uses IP_PORTRANGE_HIGH */
        !           451:             inp->inp_flags &= ~(INP_LOWPORT);
        !           452:             inp->inp_flags |= INP_HIGHPORT;
        !           453:         } else {
        !           454:             inp->inp_ip_tos = cloned_inp->inp_ip_tos;
        !           455:             inp->inp_ip_ttl = cloned_inp->inp_ip_ttl;
        !           456:             inp->inp_flags = cloned_inp->inp_flags;
        !           457: 
        !           458:             /* Multicast options */
        !           459:             if (cloned_inp->inp_moptions != NULL) {
        !           460:                 int                                    i;
        !           461:                 struct ip_moptions     *cloned_imo = cloned_inp->inp_moptions;
        !           462:                 struct ip_moptions     *imo = inp->inp_moptions;
        !           463: 
        !           464:                 if (imo == NULL) {
        !           465:                     /*
        !           466:                      * No multicast option buffer attached to the pcb;
        !           467:                      * allocate one.
        !           468:                      */
        !           469:                     splx();
        !           470:                     imo = (struct ip_moptions*)
        !           471:                         _MALLOC(sizeof(*imo), M_IPMOPTS, M_WAITOK);
        !           472:                     if (imo == NULL) {
        !           473:                         error = ENOBUFS;
        !           474:                         break;
        !           475:                     }
        !           476:                     s = splnet();              /* XXX */
        !           477:                     inp->inp_moptions = imo;
        !           478:                 }
        !           479:                 imo->imo_multicast_ifp = cloned_imo->imo_multicast_ifp;
        !           480:                 imo->imo_multicast_vif = cloned_imo->imo_multicast_vif;
        !           481:                 imo->imo_multicast_ttl = cloned_imo->imo_multicast_ttl;
        !           482:                 imo->imo_multicast_loop = cloned_imo->imo_multicast_loop;
        !           483:                 imo->imo_num_memberships = cloned_imo->imo_num_memberships;
        !           484:                 for (i = 0; i < cloned_imo->imo_num_memberships; i++) {
        !           485:                     imo->imo_membership[i] =
        !           486:                         in_addmulti(&cloned_imo->imo_membership[i]->inm_addr,
        !           487:                                     cloned_imo->imo_membership[i]->inm_ifp);
        !           488:                 }
        !           489:             }
        !           490:         }
        !           491:         splx(s);
        !           492:         break;
        !           493:     }
        !           494: 
        !           495:     default:
        !           496:                if (ifp == 0 || ifp->if_ioctl == 0)
        !           497:                        return (EOPNOTSUPP);
        !           498:                return dlil_ioctl(0, ifp, cmd, (caddr_t) data);
        !           499:        }
        !           500:        return (0);
        !           501: }
        !           502: 
        !           503: /*
        !           504:  * Delete any existing route for an interface.
        !           505:  */
        !           506: void
        !           507: in_ifscrub(ifp, ia)
        !           508:        register struct ifnet *ifp;
        !           509:        register struct in_ifaddr *ia;
        !           510: {
        !           511: 
        !           512:        if ((ia->ia_flags & IFA_ROUTE) == 0)
        !           513:                return;
        !           514:        if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
        !           515:                rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
        !           516:        else
        !           517:                rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
        !           518:        ia->ia_flags &= ~IFA_ROUTE;
        !           519: }
        !           520: 
        !           521: /*
        !           522:  * Initialize an interface's internet address
        !           523:  * and routing table entry.
        !           524:  */
        !           525: static int
        !           526: in_ifinit(ifp, ia, sin, scrub)
        !           527:        register struct ifnet *ifp;
        !           528:        register struct in_ifaddr *ia;
        !           529:        struct sockaddr_in *sin;
        !           530:        int scrub;
        !           531: {
        !           532:        register u_long i = ntohl(sin->sin_addr.s_addr);
        !           533:        struct sockaddr_in oldaddr;
        !           534:        int s = splimp(), flags = RTF_UP, error;
        !           535:        u_long      dl_tag;
        !           536: 
        !           537: 
        !           538: 
        !           539:        oldaddr = ia->ia_addr;
        !           540:        ia->ia_addr = *sin;
        !           541:        /*
        !           542:         * Give the interface a chance to initialize
        !           543:         * if this is its first address,
        !           544:         * and to validate the address if necessary.
        !           545:         */
        !           546:        if (ifp->if_ioctl &&
        !           547:            (error = dlil_ioctl(0, ifp, SIOCSIFADDR, (caddr_t)ia))) {
        !           548:                splx(s);
        !           549:                ia->ia_addr = oldaddr;
        !           550:                return (error);
        !           551:        }
        !           552: 
        !           553:        dlil_ioctl(ia->ia_ifa.ifa_dlt, 0, SIOCSIFADDR, (caddr_t) ia); 
        !           554: 
        !           555:        splx(s);
        !           556:        if (scrub) {
        !           557:                ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
        !           558:                in_ifscrub(ifp, ia);
        !           559:                ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
        !           560:        }
        !           561:        if (IN_CLASSA(i))
        !           562:                ia->ia_netmask = IN_CLASSA_NET;
        !           563:        else if (IN_CLASSB(i))
        !           564:                ia->ia_netmask = IN_CLASSB_NET;
        !           565:        else
        !           566:                ia->ia_netmask = IN_CLASSC_NET;
        !           567:        /*
        !           568:         * The subnet mask usually includes at least the standard network part,
        !           569:         * but may may be smaller in the case of supernetting.
        !           570:         * If it is set, we believe it.
        !           571:         */
        !           572:        if (ia->ia_subnetmask == 0) {
        !           573:                ia->ia_subnetmask = ia->ia_netmask;
        !           574:                ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
        !           575:        } else
        !           576:                ia->ia_netmask &= ia->ia_subnetmask;
        !           577:        ia->ia_net = i & ia->ia_netmask;
        !           578:        ia->ia_subnet = i & ia->ia_subnetmask;
        !           579:        in_socktrim(&ia->ia_sockmask);
        !           580:        /*
        !           581:         * Add route for the network.
        !           582:         */
        !           583:        ia->ia_ifa.ifa_metric = ifp->if_metric;
        !           584:        if (ifp->if_flags & IFF_BROADCAST) {
        !           585:                ia->ia_broadaddr.sin_addr.s_addr =
        !           586:                        htonl(ia->ia_subnet | ~ia->ia_subnetmask);
        !           587:                ia->ia_netbroadcast.s_addr =
        !           588:                        htonl(ia->ia_net | ~ ia->ia_netmask);
        !           589:        } else if (ifp->if_flags & IFF_LOOPBACK) {
        !           590:                ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
        !           591:                flags |= RTF_HOST;
        !           592:        } else if (ifp->if_flags & IFF_POINTOPOINT) {
        !           593:                if (ia->ia_dstaddr.sin_family != AF_INET)
        !           594:                        return (0);
        !           595:                flags |= RTF_HOST;
        !           596:        }
        !           597:        if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
        !           598:                ia->ia_flags |= IFA_ROUTE;
        !           599: 
        !           600:        /*
        !           601:         * If the interface supports multicast, join the "all hosts"
        !           602:         * multicast group on that interface.
        !           603:         */
        !           604:        if (ifp->if_flags & IFF_MULTICAST) {
        !           605:                struct in_addr addr;
        !           606: 
        !           607:                addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
        !           608:                in_addmulti(&addr, ifp);
        !           609:        }
        !           610:        return (error);
        !           611: }
        !           612: 
        !           613: 
        !           614: /*
        !           615:  * Return 1 if the address might be a local broadcast address.
        !           616:  */
        !           617: int
        !           618: in_broadcast(in, ifp)
        !           619:        struct in_addr in;
        !           620:         struct ifnet *ifp;
        !           621: {
        !           622:        register struct ifaddr *ifa;
        !           623:        u_long t;
        !           624: 
        !           625:        if (in.s_addr == INADDR_BROADCAST ||
        !           626:            in.s_addr == INADDR_ANY)
        !           627:                return 1;
        !           628:        if ((ifp->if_flags & IFF_BROADCAST) == 0)
        !           629:                return 0;
        !           630:        t = ntohl(in.s_addr);
        !           631:        /*
        !           632:         * Look through the list of addresses for a match
        !           633:         * with a broadcast address.
        !           634:         */
        !           635: #define ia ((struct in_ifaddr *)ifa)
        !           636:        for (ifa = ifp->if_addrhead.tqh_first; ifa; 
        !           637:             ifa = ifa->ifa_link.tqe_next)
        !           638:                if (ifa->ifa_addr->sa_family == AF_INET &&
        !           639:                    (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
        !           640:                     in.s_addr == ia->ia_netbroadcast.s_addr ||
        !           641:                     /*
        !           642:                      * Check for old-style (host 0) broadcast.
        !           643:                      */
        !           644:                     t == ia->ia_subnet || t == ia->ia_net) &&
        !           645:                     /*
        !           646:                      * Check for an all one subnetmask. These
        !           647:                      * only exist when an interface gets a secondary
        !           648:                      * address.
        !           649:                      */
        !           650:                     ia->ia_subnetmask != (u_long)0xffffffff)
        !           651:                            return 1;
        !           652:        return (0);
        !           653: #undef ia
        !           654: }
        !           655: /*
        !           656:  * Add an address to the list of IP multicast addresses for a given interface.
        !           657:  */
        !           658: struct in_multi *
        !           659: in_addmulti(ap, ifp)
        !           660:        register struct in_addr *ap;
        !           661:        register struct ifnet *ifp;
        !           662: {
        !           663:        register struct in_multi *inm;
        !           664:        int error;
        !           665:        struct sockaddr_in sin;
        !           666:        struct ifmultiaddr *ifma;
        !           667:        int s = splnet();
        !           668: 
        !           669:        /*
        !           670:         * Call generic routine to add membership or increment
        !           671:         * refcount.  It wants addresses in the form of a sockaddr,
        !           672:         * so we build one here (being careful to zero the unused bytes).
        !           673:         */
        !           674:        bzero(&sin, sizeof sin);
        !           675:        sin.sin_family = AF_INET;
        !           676:        sin.sin_len = sizeof sin;
        !           677:        sin.sin_addr = *ap;
        !           678:        error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma);
        !           679:        if (error) {
        !           680:                splx(s);
        !           681:                return 0;
        !           682:        }
        !           683: 
        !           684:        /*
        !           685:         * If ifma->ifma_protospec is null, then if_addmulti() created
        !           686:         * a new record.  Otherwise, we are done.
        !           687:         */
        !           688:        if (ifma->ifma_protospec != 0)
        !           689:                return ifma->ifma_protospec;
        !           690: 
        !           691:        /* XXX - if_addmulti uses M_WAITOK.  Can this really be called
        !           692:           at interrupt time?  If so, need to fix if_addmulti. XXX */
        !           693:        inm = (struct in_multi *) _MALLOC(sizeof(*inm), M_IPMADDR, M_NOWAIT);
        !           694:        if (inm == NULL) {
        !           695:                splx(s);
        !           696:                return (NULL);
        !           697:        }
        !           698: 
        !           699:        bzero(inm, sizeof *inm);
        !           700:        inm->inm_addr = *ap;
        !           701:        inm->inm_ifp = ifp;
        !           702:        inm->inm_ifma = ifma;
        !           703:        ifma->ifma_protospec = inm;
        !           704:        LIST_INSERT_HEAD(&in_multihead, inm, inm_link);
        !           705: 
        !           706:        /*
        !           707:         * Let IGMP know that we have joined a new IP multicast group.
        !           708:         */
        !           709:        igmp_joingroup(inm);
        !           710:        splx(s);
        !           711:        return (inm);
        !           712: }
        !           713: 
        !           714: /*
        !           715:  * Delete a multicast address record.
        !           716:  */
        !           717: void
        !           718: in_delmulti(inm)
        !           719:        register struct in_multi *inm;
        !           720: {
        !           721:        struct ifmultiaddr *ifma = inm->inm_ifma;
        !           722:        int s = splnet();
        !           723: 
        !           724:        if (ifma->ifma_refcount == 1) {
        !           725:                /*
        !           726:                 * No remaining claims to this record; let IGMP know that
        !           727:                 * we are leaving the multicast group.
        !           728:                 */
        !           729:                igmp_leavegroup(inm);
        !           730:                ifma->ifma_protospec = 0;
        !           731:                LIST_REMOVE(inm, inm_link);
        !           732:                FREE(inm, M_IPMADDR);
        !           733:        }
        !           734:        /* XXX - should be separate API for when we have an ifma? */
        !           735:        if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
        !           736:        splx(s);
        !           737: }

unix.superglobalmegacorp.com

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