Annotation of XNU/bsd/netinet/in.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, 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.