Annotation of src/sys/netinet/in.c, revision 1.26

1.1       dillon      1: /*
                      2:  * Copyright (c) 1982, 1986, 1991, 1993
                      3:  *     The Regents of the University of California.  All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. All advertising materials mentioning features or use of this software
                     14:  *    must display the following acknowledgement:
                     15:  *     This product includes software developed by the University of
                     16:  *     California, Berkeley and its contributors.
                     17:  * 4. Neither the name of the University nor the names of its contributors
                     18:  *    may be used to endorse or promote products derived from this software
                     19:  *    without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  *
                     33:  *     @(#)in.c        8.4 (Berkeley) 1/9/95
                     34:  * $FreeBSD: src/sys/netinet/in.c,v 1.44.2.14 2002/11/08 00:45:50 suz Exp $
1.5       dillon     35:  * $DragonFly$
1.1       dillon     36:  */
                     37: 
                     38: #include "opt_bootp.h"
1.26    ! sephe      39: 
1.1       dillon     40: #include <sys/param.h>
                     41: #include <sys/systm.h>
                     42: #include <sys/sockio.h>
                     43: #include <sys/malloc.h>
                     44: #include <sys/proc.h>
1.26    ! sephe      45: #include <sys/msgport.h>
1.1       dillon     46: #include <sys/socket.h>
1.26    ! sephe      47: 
1.1       dillon     48: #include <sys/kernel.h>
                     49: #include <sys/sysctl.h>
1.15      dillon     50: #include <sys/thread2.h>
1.1       dillon     51: 
                     52: #include <net/if.h>
                     53: #include <net/if_types.h>
                     54: #include <net/route.h>
1.26    ! sephe      55: #include <net/netmsg2.h>
1.1       dillon     56: 
                     57: #include <netinet/in.h>
                     58: #include <netinet/in_var.h>
                     59: #include <netinet/in_pcb.h>
                     60: 
                     61: #include <netinet/igmp_var.h>
                     62: 
1.20      swildner   63: MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
1.1       dillon     64: 
1.7       rob        65: static int in_mask2len (struct in_addr *);
                     66: static void in_len2mask (struct in_addr *, int);
                     67: static int in_lifaddr_ioctl (struct socket *, u_long, caddr_t,
                     68:        struct ifnet *, struct thread *);
1.1       dillon     69: 
1.7       rob        70: static void    in_socktrim (struct sockaddr_in *);
                     71: static int     in_ifinit (struct ifnet *,
                     72:            struct in_ifaddr *, struct sockaddr_in *, int);
1.1       dillon     73: 
1.26    ! sephe      74: static void    in_control_dispatch(struct netmsg *);
        !            75: static int     in_control_internal(u_long, caddr_t, struct ifnet *,
        !            76:                    struct thread *);
        !            77: 
1.1       dillon     78: static int subnetsarelocal = 0;
1.13      hsu        79: SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
1.1       dillon     80:        &subnetsarelocal, 0, "");
                     81: 
                     82: struct in_multihead in_multihead; /* XXX BSS initialization */
                     83: 
                     84: extern struct inpcbinfo ripcbinfo;
                     85: extern struct inpcbinfo udbinfo;
                     86: 
                     87: /*
                     88:  * Return 1 if an internet address is for a ``local'' host
                     89:  * (one to which we have a connection).  If subnetsarelocal
                     90:  * is true, this includes other subnets of the local net.
                     91:  * Otherwise, it includes only the directly-connected (sub)nets.
                     92:  */
                     93: int
1.18      swildner   94: in_localaddr(struct in_addr in)
1.1       dillon     95: {
1.6       rob        96:        u_long i = ntohl(in.s_addr);
                     97:        struct in_ifaddr *ia;
1.1       dillon     98: 
                     99:        if (subnetsarelocal) {
                    100:                TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
                    101:                        if ((i & ia->ia_netmask) == ia->ia_net)
                    102:                                return (1);
                    103:        } else {
                    104:                TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
                    105:                        if ((i & ia->ia_subnetmask) == ia->ia_subnet)
                    106:                                return (1);
                    107:        }
                    108:        return (0);
                    109: }
                    110: 
                    111: /*
                    112:  * Determine whether an IP address is in a reserved set of addresses
                    113:  * that may not be forwarded, or whether datagrams to that destination
                    114:  * may be forwarded.
                    115:  */
                    116: int
1.18      swildner  117: in_canforward(struct in_addr in)
1.1       dillon    118: {
1.6       rob       119:        u_long i = ntohl(in.s_addr);
                    120:        u_long net;
1.1       dillon    121: 
                    122:        if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i))
                    123:                return (0);
                    124:        if (IN_CLASSA(i)) {
                    125:                net = i & IN_CLASSA_NET;
                    126:                if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
                    127:                        return (0);
                    128:        }
                    129:        return (1);
                    130: }
                    131: 
                    132: /*
                    133:  * Trim a mask in a sockaddr
                    134:  */
                    135: static void
1.18      swildner  136: in_socktrim(struct sockaddr_in *ap)
1.1       dillon    137: {
1.6       rob       138:     char *cplim = (char *) &ap->sin_addr;
                    139:     char *cp = (char *) (&ap->sin_addr + 1);
1.1       dillon    140: 
                    141:     ap->sin_len = 0;
                    142:     while (--cp >= cplim)
1.13      hsu       143:        if (*cp) {
1.1       dillon    144:            (ap)->sin_len = cp - (char *) (ap) + 1;
                    145:            break;
                    146:        }
                    147: }
                    148: 
                    149: static int
1.18      swildner  150: in_mask2len(struct in_addr *mask)
1.1       dillon    151: {
                    152:        int x, y;
                    153:        u_char *p;
                    154: 
                    155:        p = (u_char *)mask;
1.14      hsu       156:        for (x = 0; x < sizeof *mask; x++) {
1.1       dillon    157:                if (p[x] != 0xff)
                    158:                        break;
                    159:        }
                    160:        y = 0;
1.14      hsu       161:        if (x < sizeof *mask) {
1.1       dillon    162:                for (y = 0; y < 8; y++) {
                    163:                        if ((p[x] & (0x80 >> y)) == 0)
                    164:                                break;
                    165:                }
                    166:        }
                    167:        return x * 8 + y;
                    168: }
                    169: 
                    170: static void
1.18      swildner  171: in_len2mask(struct in_addr *mask, int len)
1.1       dillon    172: {
                    173:        int i;
                    174:        u_char *p;
                    175: 
                    176:        p = (u_char *)mask;
1.14      hsu       177:        bzero(mask, sizeof *mask);
1.1       dillon    178:        for (i = 0; i < len / 8; i++)
                    179:                p[i] = 0xff;
                    180:        if (len % 8)
                    181:                p[i] = (0xff00 >> (len % 8)) & 0xff;
                    182: }
                    183: 
                    184: static int in_interfaces;      /* number of external internet interfaces */
                    185: 
1.26    ! sephe     186: struct in_control_arg {
        !           187:        u_long          cmd;
        !           188:        caddr_t         data;
        !           189:        struct ifnet    *ifp;
        !           190:        struct thread   *td;
        !           191: };
        !           192: 
        !           193: static void
        !           194: in_control_dispatch(struct netmsg *nmsg)
        !           195: {
        !           196:        struct lwkt_msg *msg = &nmsg->nm_lmsg;
        !           197:        const struct in_control_arg *arg = msg->u.ms_resultp;
        !           198:        int error;
        !           199: 
        !           200:        error = in_control_internal(arg->cmd, arg->data, arg->ifp, arg->td);
        !           201:        lwkt_replymsg(msg, error);
        !           202: }
        !           203: 
1.1       dillon    204: /*
                    205:  * Generic internet control operations (ioctl's).
                    206:  * Ifp is 0 if not an interface-specific ioctl.
1.5       dillon    207:  *
                    208:  * NOTE! td might be NULL.
1.1       dillon    209:  */
                    210: /* ARGSUSED */
                    211: int
1.18      swildner  212: in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
                    213:           struct thread *td)
1.1       dillon    214: {
1.26    ! sephe     215:        struct netmsg nmsg;
        !           216:        struct in_control_arg arg;
        !           217:        struct lwkt_msg *msg;
        !           218:        int error;
1.1       dillon    219: 
                    220:        switch (cmd) {
                    221:        case SIOCALIFADDR:
                    222:        case SIOCDLIFADDR:
1.5       dillon    223:                if (td && (error = suser(td)) != 0)
1.1       dillon    224:                        return error;
                    225:                /*fall through*/
                    226:        case SIOCGLIFADDR:
                    227:                if (!ifp)
                    228:                        return EINVAL;
1.4       dillon    229:                return in_lifaddr_ioctl(so, cmd, data, ifp, td);
1.1       dillon    230:        }
                    231: 
1.26    ! sephe     232:        KASSERT(cmd != SIOCALIFADDR && cmd != SIOCDLIFADDR,
        !           233:                ("recursive SIOC%cLIFADDR!\n",
        !           234:                 cmd == SIOCDLIFADDR ? 'D' : 'A'));
        !           235: 
        !           236:        switch (cmd) {
        !           237:        case SIOCSIFDSTADDR:
        !           238:        case SIOCSIFBRDADDR:
        !           239:        case SIOCSIFADDR:
        !           240:        case SIOCSIFNETMASK:
        !           241:        case SIOCAIFADDR:
        !           242:        case SIOCDIFADDR:
        !           243:                bzero(&arg, sizeof(arg));
        !           244:                arg.cmd = cmd;
        !           245:                arg.data = data;
        !           246:                arg.ifp = ifp;
        !           247:                arg.td = td;
        !           248: 
        !           249:                netmsg_init(&nmsg, &curthread->td_msgport, 0,
        !           250:                            in_control_dispatch);
        !           251:                msg = &nmsg.nm_lmsg;
        !           252:                msg->u.ms_resultp = &arg;
        !           253: 
        !           254:                lwkt_domsg(cpu_portfn(0), msg, 0);
        !           255:                return msg->ms_error;
        !           256:        default:
        !           257:                return in_control_internal(cmd, data, ifp, td);
        !           258:        }
        !           259: }
        !           260: 
        !           261: static int
        !           262: in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
        !           263:                    struct thread *td)
        !           264: {
        !           265:        struct ifreq *ifr = (struct ifreq *)data;
        !           266:        struct in_ifaddr *ia = 0, *iap;
        !           267:        struct in_addr dst;
        !           268:        struct in_ifaddr *oia;
        !           269:        struct in_aliasreq *ifra = (struct in_aliasreq *)data;
        !           270:        struct sockaddr_in oldaddr;
        !           271:        int hostIsNew, iaIsNew, maskIsNew;
        !           272:        int error = 0;
        !           273: 
        !           274:        iaIsNew = 0;
        !           275: 
1.1       dillon    276:        /*
                    277:         * Find address for this interface, if it exists.
                    278:         *
                    279:         * If an alias address was specified, find that one instead of
                    280:         * the first one on the interface, if possible
                    281:         */
                    282:        if (ifp) {
                    283:                dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
                    284:                LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash)
                    285:                        if (iap->ia_ifp == ifp &&
                    286:                            iap->ia_addr.sin_addr.s_addr == dst.s_addr) {
                    287:                                ia = iap;
                    288:                                break;
                    289:                        }
1.26    ! sephe     290:                if (ia == NULL) {
        !           291:                        struct ifaddr_container *ifac;
        !           292: 
        !           293:                        TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid],
        !           294:                                      ifa_link) {
        !           295:                                iap = ifatoia(ifac->ifa);
1.1       dillon    296:                                if (iap->ia_addr.sin_family == AF_INET) {
                    297:                                        ia = iap;
                    298:                                        break;
                    299:                                }
                    300:                        }
1.26    ! sephe     301:                }
1.1       dillon    302:        }
                    303: 
                    304:        switch (cmd) {
                    305: 
                    306:        case SIOCAIFADDR:
                    307:        case SIOCDIFADDR:
1.25      sephe     308:                if (ifp == NULL)
1.1       dillon    309:                        return (EADDRNOTAVAIL);
                    310:                if (ifra->ifra_addr.sin_family == AF_INET) {
                    311:                        for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) {
                    312:                                if (ia->ia_ifp == ifp  &&
                    313:                                    ia->ia_addr.sin_addr.s_addr ==
                    314:                                    ifra->ifra_addr.sin_addr.s_addr)
                    315:                                        break;
                    316:                        }
                    317:                        if ((ifp->if_flags & IFF_POINTOPOINT)
                    318:                            && (cmd == SIOCAIFADDR)
                    319:                            && (ifra->ifra_dstaddr.sin_addr.s_addr
                    320:                                == INADDR_ANY)) {
                    321:                                return EDESTADDRREQ;
                    322:                        }
                    323:                }
1.25      sephe     324:                if (cmd == SIOCDIFADDR && ia == NULL)
1.1       dillon    325:                        return (EADDRNOTAVAIL);
                    326:                /* FALLTHROUGH */
                    327:        case SIOCSIFADDR:
                    328:        case SIOCSIFNETMASK:
                    329:        case SIOCSIFDSTADDR:
1.5       dillon    330:                if (td && (error = suser(td)) != 0)
1.1       dillon    331:                        return error;
                    332: 
1.25      sephe     333:                if (ifp == NULL)
1.1       dillon    334:                        return (EADDRNOTAVAIL);
1.23      sephe     335:                if (ia == NULL) {
1.26    ! sephe     336:                        struct ifaddr *ifa;
        !           337: 
        !           338:                        ia = ifa_create(sizeof(*ia), M_WAITOK);
1.24      sephe     339: 
1.1       dillon    340:                        /*
1.21      sephe     341:                         * Protect from NETISR_IP traversing address list
1.1       dillon    342:                         * while we're modifying it.
                    343:                         */
1.15      dillon    344:                        crit_enter();
1.1       dillon    345:                        
                    346:                        TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link);
                    347:                        ifa = &ia->ia_ifa;
1.26    ! sephe     348:                        ifa_iflink(ifa, ifp, 1);
1.1       dillon    349: 
                    350:                        ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
                    351:                        ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
                    352:                        ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
                    353:                        ia->ia_sockmask.sin_len = 8;
                    354:                        ia->ia_sockmask.sin_family = AF_INET;
                    355:                        if (ifp->if_flags & IFF_BROADCAST) {
1.14      hsu       356:                                ia->ia_broadaddr.sin_len = sizeof ia->ia_addr;
1.1       dillon    357:                                ia->ia_broadaddr.sin_family = AF_INET;
                    358:                        }
                    359:                        ia->ia_ifp = ifp;
                    360:                        if (!(ifp->if_flags & IFF_LOOPBACK))
                    361:                                in_interfaces++;
                    362:                        iaIsNew = 1;
1.15      dillon    363:                        crit_exit();
1.1       dillon    364:                }
                    365:                break;
                    366: 
                    367:        case SIOCSIFBRDADDR:
1.5       dillon    368:                if (td && (error = suser(td)) != 0)
1.1       dillon    369:                        return error;
                    370:                /* FALLTHROUGH */
                    371: 
                    372:        case SIOCGIFADDR:
                    373:        case SIOCGIFNETMASK:
                    374:        case SIOCGIFDSTADDR:
                    375:        case SIOCGIFBRDADDR:
1.25      sephe     376:                if (ia == NULL)
1.1       dillon    377:                        return (EADDRNOTAVAIL);
                    378:                break;
                    379:        }
                    380:        switch (cmd) {
                    381: 
                    382:        case SIOCGIFADDR:
                    383:                *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
                    384:                return (0);
                    385: 
                    386:        case SIOCGIFBRDADDR:
                    387:                if ((ifp->if_flags & IFF_BROADCAST) == 0)
                    388:                        return (EINVAL);
                    389:                *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
                    390:                return (0);
                    391: 
                    392:        case SIOCGIFDSTADDR:
                    393:                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                    394:                        return (EINVAL);
                    395:                *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
                    396:                return (0);
                    397: 
                    398:        case SIOCGIFNETMASK:
                    399:                *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
                    400:                return (0);
                    401: 
                    402:        case SIOCSIFDSTADDR:
                    403:                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                    404:                        return (EINVAL);
                    405:                oldaddr = ia->ia_dstaddr;
                    406:                ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
1.17      dillon    407:                lwkt_serialize_enter(ifp->if_serializer);
1.9       hsu       408:                if (ifp->if_ioctl &&
1.17      dillon    409:                    (error = ifp->if_ioctl(ifp, SIOCSIFDSTADDR, (caddr_t)ia,
1.9       hsu       410:                                              td->td_proc->p_ucred))) {
1.1       dillon    411:                        ia->ia_dstaddr = oldaddr;
1.17      dillon    412:                        lwkt_serialize_exit(ifp->if_serializer);
1.1       dillon    413:                        return (error);
                    414:                }
                    415:                if (ia->ia_flags & IFA_ROUTE) {
                    416:                        ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
1.13      hsu       417:                        rtinit(&ia->ia_ifa, RTM_DELETE, RTF_HOST);
1.1       dillon    418:                        ia->ia_ifa.ifa_dstaddr =
                    419:                                        (struct sockaddr *)&ia->ia_dstaddr;
1.13      hsu       420:                        rtinit(&ia->ia_ifa, RTM_ADD, RTF_HOST | RTF_UP);
1.1       dillon    421:                }
1.17      dillon    422:                lwkt_serialize_exit(ifp->if_serializer);
1.1       dillon    423:                return (0);
                    424: 
                    425:        case SIOCSIFBRDADDR:
                    426:                if ((ifp->if_flags & IFF_BROADCAST) == 0)
                    427:                        return (EINVAL);
                    428:                ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
                    429:                return (0);
                    430: 
                    431:        case SIOCSIFADDR:
                    432:                error = in_ifinit(ifp, ia,
                    433:                    (struct sockaddr_in *) &ifr->ifr_addr, 1);
                    434:                if (error != 0 && iaIsNew)
                    435:                        break;
1.12      joerg     436:                if (error == 0)
                    437:                        EVENTHANDLER_INVOKE(ifaddr_event, ifp);
1.1       dillon    438:                return (0);
                    439: 
                    440:        case SIOCSIFNETMASK:
                    441:                ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr;
                    442:                ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
                    443:                return (0);
                    444: 
                    445:        case SIOCAIFADDR:
                    446:                maskIsNew = 0;
                    447:                hostIsNew = 1;
                    448:                error = 0;
                    449:                if (ia->ia_addr.sin_family == AF_INET) {
                    450:                        if (ifra->ifra_addr.sin_len == 0) {
                    451:                                ifra->ifra_addr = ia->ia_addr;
                    452:                                hostIsNew = 0;
                    453:                        } else if (ifra->ifra_addr.sin_addr.s_addr ==
                    454:                                               ia->ia_addr.sin_addr.s_addr)
                    455:                                hostIsNew = 0;
                    456:                }
                    457:                if (ifra->ifra_mask.sin_len) {
                    458:                        in_ifscrub(ifp, ia);
                    459:                        ia->ia_sockmask = ifra->ifra_mask;
                    460:                        ia->ia_sockmask.sin_family = AF_INET;
                    461:                        ia->ia_subnetmask =
                    462:                             ntohl(ia->ia_sockmask.sin_addr.s_addr);
                    463:                        maskIsNew = 1;
                    464:                }
                    465:                if ((ifp->if_flags & IFF_POINTOPOINT) &&
                    466:                    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
                    467:                        in_ifscrub(ifp, ia);
                    468:                        ia->ia_dstaddr = ifra->ifra_dstaddr;
                    469:                        maskIsNew  = 1; /* We lie; but the effect's the same */
                    470:                }
                    471:                if (ifra->ifra_addr.sin_family == AF_INET &&
                    472:                    (hostIsNew || maskIsNew))
                    473:                        error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
                    474: 
                    475:                if (error != 0 && iaIsNew)
                    476:                        break;
                    477: 
                    478:                if ((ifp->if_flags & IFF_BROADCAST) &&
                    479:                    (ifra->ifra_broadaddr.sin_family == AF_INET))
                    480:                        ia->ia_broadaddr = ifra->ifra_broadaddr;
1.12      joerg     481:                if (error == 0)
                    482:                        EVENTHANDLER_INVOKE(ifaddr_event, ifp);
1.1       dillon    483:                return (error);
                    484: 
                    485:        case SIOCDIFADDR:
                    486:                /*
                    487:                 * in_ifscrub kills the interface route.
                    488:                 */
                    489:                in_ifscrub(ifp, ia);
                    490:                /*
                    491:                 * in_ifadown gets rid of all the rest of
                    492:                 * the routes.  This is not quite the right
                    493:                 * thing to do, but at least if we are running
                    494:                 * a routing process they will come back.
                    495:                 */
                    496:                in_ifadown(&ia->ia_ifa, 1);
1.12      joerg     497:                EVENTHANDLER_INVOKE(ifaddr_event, ifp);
1.1       dillon    498:                error = 0;
                    499:                break;
                    500: 
                    501:        default:
1.9       hsu       502:                if (ifp == NULL || ifp->if_ioctl == NULL)
1.1       dillon    503:                        return (EOPNOTSUPP);
1.17      dillon    504:                lwkt_serialize_enter(ifp->if_serializer);
                    505:                error = ifp->if_ioctl(ifp, cmd, data, td->td_proc->p_ucred);
                    506:                lwkt_serialize_exit(ifp->if_serializer);
                    507:                return (error);
1.1       dillon    508:        }
                    509: 
1.26    ! sephe     510:        ifa_ifunlink(&ia->ia_ifa, ifp);
        !           511: 
1.1       dillon    512:        /*
1.21      sephe     513:         * Protect from NETISR_IP traversing address list while we're modifying
1.1       dillon    514:         * it.
                    515:         */
1.26    ! sephe     516:        crit_enter();   /* XXX MP */
1.1       dillon    517:        TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
                    518:        LIST_REMOVE(ia, ia_hash);
1.26    ! sephe     519:        crit_exit();    /* XXX MP */
        !           520: 
        !           521:        ifa_destroy(&ia->ia_ifa);
1.1       dillon    522: 
                    523:        return (error);
                    524: }
                    525: 
                    526: /*
                    527:  * SIOC[GAD]LIFADDR.
                    528:  *     SIOCGLIFADDR: get first address. (?!?)
                    529:  *     SIOCGLIFADDR with IFLR_PREFIX:
                    530:  *             get first address that matches the specified prefix.
                    531:  *     SIOCALIFADDR: add the specified address.
                    532:  *     SIOCALIFADDR with IFLR_PREFIX:
                    533:  *             EINVAL since we can't deduce hostid part of the address.
                    534:  *     SIOCDLIFADDR: delete the specified address.
                    535:  *     SIOCDLIFADDR with IFLR_PREFIX:
                    536:  *             delete the first address that matches the specified prefix.
                    537:  * return values:
                    538:  *     EINVAL on invalid parameters
                    539:  *     EADDRNOTAVAIL on prefix match failed/specified address not found
                    540:  *     other values may be returned from in_ioctl()
1.5       dillon    541:  *
                    542:  * NOTE! td might be NULL.
1.1       dillon    543:  */
                    544: static int
1.18      swildner  545: in_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
                    546:                 struct thread *td)
1.1       dillon    547: {
                    548:        struct if_laddrreq *iflr = (struct if_laddrreq *)data;
                    549: 
                    550:        /* sanity checks */
                    551:        if (!data || !ifp) {
                    552:                panic("invalid argument to in_lifaddr_ioctl");
                    553:                /*NOTRECHED*/
                    554:        }
                    555: 
                    556:        switch (cmd) {
                    557:        case SIOCGLIFADDR:
                    558:                /* address must be specified on GET with IFLR_PREFIX */
                    559:                if ((iflr->flags & IFLR_PREFIX) == 0)
                    560:                        break;
                    561:                /*FALLTHROUGH*/
                    562:        case SIOCALIFADDR:
                    563:        case SIOCDLIFADDR:
                    564:                /* address must be specified on ADD and DELETE */
                    565:                if (iflr->addr.ss_family != AF_INET)
                    566:                        return EINVAL;
                    567:                if (iflr->addr.ss_len != sizeof(struct sockaddr_in))
                    568:                        return EINVAL;
                    569:                /* XXX need improvement */
                    570:                if (iflr->dstaddr.ss_family
                    571:                 && iflr->dstaddr.ss_family != AF_INET)
                    572:                        return EINVAL;
                    573:                if (iflr->dstaddr.ss_family
                    574:                 && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in))
                    575:                        return EINVAL;
                    576:                break;
                    577:        default: /*shouldn't happen*/
                    578:                return EOPNOTSUPP;
                    579:        }
                    580:        if (sizeof(struct in_addr) * 8 < iflr->prefixlen)
                    581:                return EINVAL;
                    582: 
                    583:        switch (cmd) {
                    584:        case SIOCALIFADDR:
                    585:            {
                    586:                struct in_aliasreq ifra;
                    587: 
                    588:                if (iflr->flags & IFLR_PREFIX)
                    589:                        return EINVAL;
                    590: 
                    591:                /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
1.14      hsu       592:                bzero(&ifra, sizeof ifra);
                    593:                bcopy(iflr->iflr_name, ifra.ifra_name, sizeof ifra.ifra_name);
1.1       dillon    594: 
                    595:                bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len);
                    596: 
                    597:                if (iflr->dstaddr.ss_family) {  /*XXX*/
                    598:                        bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
                    599:                                iflr->dstaddr.ss_len);
                    600:                }
                    601: 
                    602:                ifra.ifra_mask.sin_family = AF_INET;
                    603:                ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
                    604:                in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
                    605: 
1.4       dillon    606:                return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, td);
1.1       dillon    607:            }
                    608:        case SIOCGLIFADDR:
                    609:        case SIOCDLIFADDR:
                    610:            {
1.26    ! sephe     611:                struct ifaddr_container *ifac;
1.1       dillon    612:                struct in_ifaddr *ia;
                    613:                struct in_addr mask, candidate, match;
                    614:                struct sockaddr_in *sin;
                    615:                int cmp;
                    616: 
1.14      hsu       617:                bzero(&mask, sizeof mask);
1.1       dillon    618:                if (iflr->flags & IFLR_PREFIX) {
                    619:                        /* lookup a prefix rather than address. */
                    620:                        in_len2mask(&mask, iflr->prefixlen);
                    621: 
                    622:                        sin = (struct sockaddr_in *)&iflr->addr;
                    623:                        match.s_addr = sin->sin_addr.s_addr;
                    624:                        match.s_addr &= mask.s_addr;
                    625: 
                    626:                        /* if you set extra bits, that's wrong */
                    627:                        if (match.s_addr != sin->sin_addr.s_addr)
                    628:                                return EINVAL;
                    629: 
                    630:                        cmp = 1;
                    631:                } else {
                    632:                        if (cmd == SIOCGLIFADDR) {
                    633:                                /* on getting an address, take the 1st match */
1.23      sephe     634:                                match.s_addr = 0; /* gcc4 warning */
1.1       dillon    635:                                cmp = 0;        /*XXX*/
                    636:                        } else {
                    637:                                /* on deleting an address, do exact match */
                    638:                                in_len2mask(&mask, 32);
                    639:                                sin = (struct sockaddr_in *)&iflr->addr;
                    640:                                match.s_addr = sin->sin_addr.s_addr;
                    641: 
                    642:                                cmp = 1;
                    643:                        }
                    644:                }
                    645: 
1.26    ! sephe     646:                TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
        !           647:                        struct ifaddr *ifa = ifac->ifa;
        !           648: 
1.1       dillon    649:                        if (ifa->ifa_addr->sa_family != AF_INET6)
                    650:                                continue;
                    651:                        if (!cmp)
                    652:                                break;
1.26    ! sephe     653:                        candidate.s_addr =
        !           654:                        ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr;
1.1       dillon    655:                        candidate.s_addr &= mask.s_addr;
                    656:                        if (candidate.s_addr == match.s_addr)
                    657:                                break;
                    658:                }
1.26    ! sephe     659:                if (ifac == NULL)
1.1       dillon    660:                        return EADDRNOTAVAIL;
1.26    ! sephe     661:                ia = (struct in_ifaddr *)(ifac->ifa);
1.1       dillon    662: 
                    663:                if (cmd == SIOCGLIFADDR) {
                    664:                        /* fill in the if_laddrreq structure */
                    665:                        bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len);
                    666: 
                    667:                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
                    668:                                bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
                    669:                                        ia->ia_dstaddr.sin_len);
                    670:                        } else
1.14      hsu       671:                                bzero(&iflr->dstaddr, sizeof iflr->dstaddr);
1.1       dillon    672: 
                    673:                        iflr->prefixlen =
                    674:                                in_mask2len(&ia->ia_sockmask.sin_addr);
                    675: 
                    676:                        iflr->flags = 0;        /*XXX*/
                    677: 
                    678:                        return 0;
                    679:                } else {
                    680:                        struct in_aliasreq ifra;
                    681: 
                    682:                        /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
1.14      hsu       683:                        bzero(&ifra, sizeof ifra);
1.1       dillon    684:                        bcopy(iflr->iflr_name, ifra.ifra_name,
1.14      hsu       685:                                sizeof ifra.ifra_name);
1.1       dillon    686: 
                    687:                        bcopy(&ia->ia_addr, &ifra.ifra_addr,
                    688:                                ia->ia_addr.sin_len);
                    689:                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
                    690:                                bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
                    691:                                        ia->ia_dstaddr.sin_len);
                    692:                        }
                    693:                        bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr,
                    694:                                ia->ia_sockmask.sin_len);
                    695: 
                    696:                        return in_control(so, SIOCDIFADDR, (caddr_t)&ifra,
1.4       dillon    697:                                          ifp, td);
1.1       dillon    698:                }
                    699:            }
                    700:        }
                    701: 
                    702:        return EOPNOTSUPP;      /*just for safety*/
                    703: }
                    704: 
                    705: /*
                    706:  * Delete any existing route for an interface.
                    707:  */
                    708: void
1.18      swildner  709: in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
1.1       dillon    710: {
                    711: 
                    712:        if ((ia->ia_flags & IFA_ROUTE) == 0)
                    713:                return;
                    714:        if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
1.13      hsu       715:                rtinit(&ia->ia_ifa, RTM_DELETE, RTF_HOST);
1.1       dillon    716:        else
1.13      hsu       717:                rtinit(&ia->ia_ifa, RTM_DELETE, 0);
1.1       dillon    718:        ia->ia_flags &= ~IFA_ROUTE;
                    719: }
                    720: 
                    721: /*
                    722:  * Initialize an interface's internet address
                    723:  * and routing table entry.
                    724:  */
                    725: static int
1.18      swildner  726: in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin, int scrub)
1.1       dillon    727: {
1.6       rob       728:        u_long i = ntohl(sin->sin_addr.s_addr);
1.1       dillon    729:        struct sockaddr_in oldaddr;
1.15      dillon    730:        int flags = RTF_UP, error = 0;
                    731: 
1.17      dillon    732:        lwkt_serialize_enter(ifp->if_serializer);
1.1       dillon    733: 
                    734:        oldaddr = ia->ia_addr;
                    735:        if (oldaddr.sin_family == AF_INET)
                    736:                LIST_REMOVE(ia, ia_hash);
                    737:        ia->ia_addr = *sin;
                    738:        if (ia->ia_addr.sin_family == AF_INET)
                    739:                LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
                    740:                    ia, ia_hash);
                    741:        /*
                    742:         * Give the interface a chance to initialize
                    743:         * if this is its first address,
                    744:         * and to validate the address if necessary.
                    745:         */
                    746:        if (ifp->if_ioctl &&
1.17      dillon    747:            (error = ifp->if_ioctl(ifp, SIOCSIFADDR, (caddr_t)ia, NULL))) {
                    748:                lwkt_serialize_exit(ifp->if_serializer);
1.1       dillon    749:                /* LIST_REMOVE(ia, ia_hash) is done in in_control */
                    750:                ia->ia_addr = oldaddr;
                    751:                if (ia->ia_addr.sin_family == AF_INET)
                    752:                        LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
                    753:                            ia, ia_hash);
                    754:                return (error);
                    755:        }
1.17      dillon    756:        lwkt_serialize_exit(ifp->if_serializer);
1.1       dillon    757:        if (scrub) {
                    758:                ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
                    759:                in_ifscrub(ifp, ia);
                    760:                ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
                    761:        }
                    762:        if (IN_CLASSA(i))
                    763:                ia->ia_netmask = IN_CLASSA_NET;
                    764:        else if (IN_CLASSB(i))
                    765:                ia->ia_netmask = IN_CLASSB_NET;
                    766:        else
                    767:                ia->ia_netmask = IN_CLASSC_NET;
                    768:        /*
                    769:         * The subnet mask usually includes at least the standard network part,
                    770:         * but may may be smaller in the case of supernetting.
                    771:         * If it is set, we believe it.
                    772:         */
                    773:        if (ia->ia_subnetmask == 0) {
                    774:                ia->ia_subnetmask = ia->ia_netmask;
                    775:                ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
                    776:        } else
                    777:                ia->ia_netmask &= ia->ia_subnetmask;
                    778:        ia->ia_net = i & ia->ia_netmask;
                    779:        ia->ia_subnet = i & ia->ia_subnetmask;
                    780:        in_socktrim(&ia->ia_sockmask);
                    781:        /*
                    782:         * Add route for the network.
                    783:         */
                    784:        ia->ia_ifa.ifa_metric = ifp->if_metric;
                    785:        if (ifp->if_flags & IFF_BROADCAST) {
                    786:                ia->ia_broadaddr.sin_addr.s_addr =
                    787:                        htonl(ia->ia_subnet | ~ia->ia_subnetmask);
                    788:                ia->ia_netbroadcast.s_addr =
                    789:                        htonl(ia->ia_net | ~ ia->ia_netmask);
                    790:        } else if (ifp->if_flags & IFF_LOOPBACK) {
                    791:                ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
                    792:                flags |= RTF_HOST;
                    793:        } else if (ifp->if_flags & IFF_POINTOPOINT) {
                    794:                if (ia->ia_dstaddr.sin_family != AF_INET)
                    795:                        return (0);
                    796:                flags |= RTF_HOST;
                    797:        }
                    798: 
                    799:        /*-
                    800:         * Don't add host routes for interface addresses of
                    801:         * 0.0.0.0 --> 0.255.255.255 netmask 255.0.0.0.  This makes it
                    802:         * possible to assign several such address pairs with consistent
                    803:         * results (no host route) and is required by BOOTP.
                    804:         *
                    805:         * XXX: This is ugly !  There should be a way for the caller to
                    806:         *      say that they don't want a host route.
                    807:         */
                    808:        if (ia->ia_addr.sin_addr.s_addr != INADDR_ANY ||
                    809:            ia->ia_netmask != IN_CLASSA_NET ||
                    810:            ia->ia_dstaddr.sin_addr.s_addr != htonl(IN_CLASSA_HOST)) {
                    811:                if ((error = rtinit(&ia->ia_ifa, (int)RTM_ADD, flags)) != 0) {
                    812:                        ia->ia_addr = oldaddr;
                    813:                        return (error);
                    814:                }
                    815:                ia->ia_flags |= IFA_ROUTE;
                    816:        }
                    817: 
                    818:        /*
                    819:         * If the interface supports multicast, join the "all hosts"
                    820:         * multicast group on that interface.
                    821:         */
                    822:        if (ifp->if_flags & IFF_MULTICAST) {
                    823:                struct in_addr addr;
                    824: 
                    825:                addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
                    826:                in_addmulti(&addr, ifp);
                    827:        }
                    828:        return (error);
                    829: }
                    830: 
                    831: 
                    832: /*
                    833:  * Return 1 if the address might be a local broadcast address.
                    834:  */
                    835: int
1.13      hsu       836: in_broadcast(struct in_addr in, struct ifnet *ifp)
1.1       dillon    837: {
1.26    ! sephe     838:        struct ifaddr_container *ifac;
1.1       dillon    839:        u_long t;
                    840: 
                    841:        if (in.s_addr == INADDR_BROADCAST ||
                    842:            in.s_addr == INADDR_ANY)
                    843:                return 1;
                    844:        if ((ifp->if_flags & IFF_BROADCAST) == 0)
                    845:                return 0;
                    846:        t = ntohl(in.s_addr);
                    847:        /*
                    848:         * Look through the list of addresses for a match
                    849:         * with a broadcast address.
                    850:         */
                    851: #define ia ((struct in_ifaddr *)ifa)
1.26    ! sephe     852:        TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
        !           853:                struct ifaddr *ifa = ifac->ifa;
        !           854: 
1.1       dillon    855:                if (ifa->ifa_addr->sa_family == AF_INET &&
                    856:                    (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
                    857:                     in.s_addr == ia->ia_netbroadcast.s_addr ||
                    858:                     /*
                    859:                      * Check for old-style (host 0) broadcast.
                    860:                      */
                    861:                     t == ia->ia_subnet || t == ia->ia_net) &&
                    862:                     /*
                    863:                      * Check for an all one subnetmask. These
                    864:                      * only exist when an interface gets a secondary
                    865:                      * address.
                    866:                      */
                    867:                     ia->ia_subnetmask != (u_long)0xffffffff)
                    868:                            return 1;
1.26    ! sephe     869:        }
1.1       dillon    870:        return (0);
                    871: #undef ia
                    872: }
                    873: /*
                    874:  * Add an address to the list of IP multicast addresses for a given interface.
                    875:  */
                    876: struct in_multi *
1.18      swildner  877: in_addmulti(struct in_addr *ap, struct ifnet *ifp)
1.1       dillon    878: {
1.6       rob       879:        struct in_multi *inm;
1.1       dillon    880:        int error;
                    881:        struct sockaddr_in sin;
                    882:        struct ifmultiaddr *ifma;
                    883: 
                    884:        /*
                    885:         * Call generic routine to add membership or increment
                    886:         * refcount.  It wants addresses in the form of a sockaddr,
                    887:         * so we build one here (being careful to zero the unused bytes).
                    888:         */
                    889:        bzero(&sin, sizeof sin);
                    890:        sin.sin_family = AF_INET;
                    891:        sin.sin_len = sizeof sin;
                    892:        sin.sin_addr = *ap;
1.15      dillon    893:        crit_enter();
1.1       dillon    894:        error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma);
                    895:        if (error) {
1.15      dillon    896:                crit_exit();
1.1       dillon    897:                return 0;
                    898:        }
                    899: 
                    900:        /*
                    901:         * If ifma->ifma_protospec is null, then if_addmulti() created
                    902:         * a new record.  Otherwise, we are done.
                    903:         */
                    904:        if (ifma->ifma_protospec != 0) {
1.15      dillon    905:                crit_exit();
1.1       dillon    906:                return ifma->ifma_protospec;
                    907:        }
                    908: 
                    909:        /* XXX - if_addmulti uses M_WAITOK.  Can this really be called
                    910:           at interrupt time?  If so, need to fix if_addmulti. XXX */
1.19      dillon    911:        inm = kmalloc(sizeof *inm, M_IPMADDR, M_WAITOK | M_ZERO);
1.1       dillon    912:        inm->inm_addr = *ap;
                    913:        inm->inm_ifp = ifp;
                    914:        inm->inm_ifma = ifma;
                    915:        ifma->ifma_protospec = inm;
                    916:        LIST_INSERT_HEAD(&in_multihead, inm, inm_link);
                    917: 
                    918:        /*
                    919:         * Let IGMP know that we have joined a new IP multicast group.
                    920:         */
                    921:        igmp_joingroup(inm);
1.15      dillon    922:        crit_exit();
1.1       dillon    923:        return (inm);
                    924: }
                    925: 
                    926: /*
                    927:  * Delete a multicast address record.
                    928:  */
                    929: void
1.18      swildner  930: in_delmulti(struct in_multi *inm)
1.1       dillon    931: {
1.15      dillon    932:        struct ifmultiaddr *ifma;
1.1       dillon    933:        struct in_multi my_inm;
                    934: 
1.15      dillon    935:        crit_enter();
                    936:        ifma = inm->inm_ifma;
1.1       dillon    937:        my_inm.inm_ifp = NULL ; /* don't send the leave msg */
                    938:        if (ifma->ifma_refcount == 1) {
                    939:                /*
                    940:                 * No remaining claims to this record; let IGMP know that
                    941:                 * we are leaving the multicast group.
                    942:                 * But do it after the if_delmulti() which might reset
                    943:                 * the interface and nuke the packet.
                    944:                 */
                    945:                my_inm = *inm ;
                    946:                ifma->ifma_protospec = 0;
                    947:                LIST_REMOVE(inm, inm_link);
1.19      dillon    948:                kfree(inm, M_IPMADDR);
1.1       dillon    949:        }
                    950:        /* XXX - should be separate API for when we have an ifma? */
                    951:        if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
                    952:        if (my_inm.inm_ifp != NULL)
                    953:                igmp_leavegroup(&my_inm);
1.15      dillon    954:        crit_exit();
1.1       dillon    955: }
1.16      joerg     956: 
                    957: void
                    958: in_ifdetach(struct ifnet *ifp)
                    959: {
                    960:        in_pcbpurgeif0(LIST_FIRST(&ripcbinfo.pcblisthead), ifp);
                    961:        in_pcbpurgeif0(LIST_FIRST(&udbinfo.pcblisthead), ifp);
                    962: }