[BACK]Return to at_control.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netatalk

Annotation of src/sys/netatalk/at_control.c, Revision 1.35

1.35    ! rtr         1: /*     $NetBSD: at_control.c,v 1.34 2011/10/19 01:50:27 dyoung Exp $    */
1.1       christos    2:
                      3: /*
                      4:  * Copyright (c) 1990,1994 Regents of The University of Michigan.
                      5:  * All Rights Reserved.
                      6:  *
                      7:  * Permission to use, copy, modify, and distribute this software and
                      8:  * its documentation for any purpose and without fee is hereby granted,
                      9:  * provided that the above copyright notice appears in all copies and
                     10:  * that both that copyright notice and this permission notice appear
                     11:  * in supporting documentation, and that the name of The University
                     12:  * of Michigan not be used in advertising or publicity pertaining to
                     13:  * distribution of the software without specific, written prior
                     14:  * permission. This software is supplied as is without expressed or
                     15:  * implied warranties of any kind.
                     16:  *
                     17:  * This product includes software developed by the University of
                     18:  * California, Berkeley and its contributors.
                     19:  *
                     20:  *     Research Systems Unix Group
                     21:  *     The University of Michigan
                     22:  *     c/o Wesley Craig
                     23:  *     535 W. William Street
                     24:  *     Ann Arbor, Michigan
                     25:  *     +1-313-764-2278
                     26:  *     netatalk@umich.edu
                     27:  */
1.6       lukem      28:
                     29: #include <sys/cdefs.h>
1.35    ! rtr        30: __KERNEL_RCSID(0, "$NetBSD: at_control.c,v 1.34 2011/10/19 01:50:27 dyoung Exp $");
1.1       christos   31:
                     32: #include <sys/param.h>
                     33: #include <sys/systm.h>
                     34: #include <sys/proc.h>
                     35: #include <sys/errno.h>
                     36: #include <sys/ioctl.h>
                     37: #include <sys/mbuf.h>
                     38: #include <sys/kernel.h>
                     39: #include <sys/socket.h>
                     40: #include <sys/socketvar.h>
1.13      elad       41: #include <sys/kauth.h>
1.1       christos   42: #include <net/if.h>
                     43: #include <net/route.h>
                     44: #include <net/if_ether.h>
                     45: #include <netinet/in.h>
                     46: #undef s_net
                     47:
                     48: #include <netatalk/at.h>
                     49: #include <netatalk/at_var.h>
                     50: #include <netatalk/aarp.h>
                     51: #include <netatalk/phase2.h>
                     52: #include <netatalk/at_extern.h>
                     53:
1.20      dyoung     54: static int aa_dorangeroute(struct ifaddr * ifa,
                     55:     u_int first, u_int last, int cmd);
                     56: static int aa_addsingleroute(struct ifaddr * ifa,
                     57:     struct at_addr * addr, struct at_addr * mask);
                     58: static int aa_delsingleroute(struct ifaddr * ifa,
                     59:     struct at_addr * addr, struct at_addr * mask);
                     60: static int aa_dosingleroute(struct ifaddr * ifa, struct at_addr * addr,
                     61:     struct at_addr * mask, int cmd, int flags);
                     62: static int at_scrub(struct ifnet * ifp, struct at_ifaddr * aa);
                     63: static int at_ifinit(struct ifnet *, struct at_ifaddr *,
                     64:     const struct sockaddr_at *);
1.1       christos   65: #if 0
1.20      dyoung     66: static void aa_clean(void);
1.1       christos   67: #endif
                     68:
                     69: #define sateqaddr(a,b) ((a)->sat_len == (b)->sat_len && \
                     70:                         (a)->sat_family == (b)->sat_family && \
                     71:                         (a)->sat_addr.s_net == (b)->sat_addr.s_net && \
                     72:                         (a)->sat_addr.s_node == (b)->sat_addr.s_node )
                     73:
                     74: int
1.35    ! rtr        75: at_control(u_long cmd, void *data, struct ifnet *ifp)
1.1       christos   76: {
                     77:        struct ifreq   *ifr = (struct ifreq *) data;
1.20      dyoung     78:        const struct sockaddr_at *csat;
1.1       christos   79:        struct netrange *nr;
1.20      dyoung     80:        const struct netrange *cnr;
1.1       christos   81:        struct at_aliasreq *ifra = (struct at_aliasreq *) data;
                     82:        struct at_ifaddr *aa0;
                     83:        struct at_ifaddr *aa = 0;
                     84:
                     85:        /*
                     86:          * If we have an ifp, then find the matching at_ifaddr if it exists
                     87:          */
                     88:        if (ifp)
                     89:                for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next)
                     90:                        if (aa->aa_ifp == ifp)
                     91:                                break;
                     92:
                     93:        /*
                     94:          * In this first switch table we are basically getting ready for
                     95:          * the second one, by getting the atalk-specific things set up
                     96:          * so that they start to look more similar to other protocols etc.
                     97:          */
                     98:
                     99:        switch (cmd) {
                    100:        case SIOCAIFADDR:
                    101:        case SIOCDIFADDR:
                    102:                /*
                    103:                 * If we have an appletalk sockaddr, scan forward of where
                    104:                 * we are now on the at_ifaddr list to find one with a matching
                    105:                 * address on this interface.
                    106:                 * This may leave aa pointing to the first address on the
                    107:                 * NEXT interface!
                    108:                 */
                    109:                if (ifra->ifra_addr.sat_family == AF_APPLETALK) {
                    110:                        for (; aa; aa = aa->aa_list.tqe_next)
                    111:                                if (aa->aa_ifp == ifp &&
                    112:                                    sateqaddr(&aa->aa_addr, &ifra->ifra_addr))
                    113:                                        break;
                    114:                }
                    115:                /*
                    116:                 * If we a retrying to delete an addres but didn't find such,
                    117:                 * then return with an error
                    118:                 */
                    119:                if (cmd == SIOCDIFADDR && aa == 0)
                    120:                        return (EADDRNOTAVAIL);
                    121:                /* FALLTHROUGH */
                    122:
                    123:        case SIOCSIFADDR:
                    124:                /*
                    125:                 * If we are not superuser, then we don't get to do these
                    126:                 * ops.
                    127:                 */
1.35    ! rtr       128:                if (kauth_authorize_network(curlwp->l_cred,
1.16      elad      129:                    KAUTH_NETWORK_INTERFACE,
                    130:                    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
                    131:                    NULL) != 0)
1.1       christos  132:                        return (EPERM);
                    133:
1.20      dyoung    134:                csat = satocsat(ifreq_getaddr(cmd, ifr));
                    135:                cnr = (const struct netrange *)csat->sat_zero;
                    136:                if (cnr->nr_phase == 1) {
1.1       christos  137:                        /*
                    138:                         * Look for a phase 1 address on this interface.
                    139:                         * This may leave aa pointing to the first address on
                    140:                         * the NEXT interface!
                    141:                         */
                    142:                        for (; aa; aa = aa->aa_list.tqe_next) {
                    143:                                if (aa->aa_ifp == ifp &&
                    144:                                    (aa->aa_flags & AFA_PHASE2) == 0)
                    145:                                        break;
                    146:                        }
                    147:                } else {        /* default to phase 2 */
                    148:                        /*
                    149:                         * Look for a phase 2 address on this interface.
                    150:                         * This may leave aa pointing to the first address on
                    151:                         * the NEXT interface!
                    152:                         */
                    153:                        for (; aa; aa = aa->aa_list.tqe_next) {
                    154:                                if (aa->aa_ifp == ifp &&
                    155:                                    (aa->aa_flags & AFA_PHASE2))
                    156:                                        break;
                    157:                        }
                    158:                }
                    159:
                    160:                if (ifp == 0)
                    161:                        panic("at_control");
                    162:
                    163:                /*
                    164:                 * If we failed to find an existing at_ifaddr entry, then we
                    165:                 * allocate a fresh one.
                    166:                 * XXX change this to use malloc
                    167:                 */
                    168:                if (aa == (struct at_ifaddr *) 0) {
                    169:                        aa = (struct at_ifaddr *)
1.10      perry     170:                            malloc(sizeof(struct at_ifaddr), M_IFADDR,
1.9       matt      171:                            M_WAITOK|M_ZERO);
1.1       christos  172:
                    173:                        if (aa == NULL)
                    174:                                return (ENOBUFS);
                    175:
1.19      ad        176:                        callout_init(&aa->aa_probe_ch, 0);
1.1       christos  177:
                    178:                        if ((aa0 = at_ifaddr.tqh_first) != NULL) {
                    179:                                /*
                    180:                                 * Don't let the loopback be first, since the
                    181:                                 * first address is the machine's default
                    182:                                 * address for binding.
                    183:                                 * If it is, stick ourself in front, otherwise
                    184:                                 * go to the back of the list.
                    185:                                 */
                    186:                                if (aa0->aa_ifp->if_flags & IFF_LOOPBACK) {
                    187:                                        TAILQ_INSERT_HEAD(&at_ifaddr, aa,
                    188:                                            aa_list);
                    189:                                } else {
                    190:                                        TAILQ_INSERT_TAIL(&at_ifaddr, aa,
                    191:                                            aa_list);
                    192:                                }
                    193:                        } else {
                    194:                                TAILQ_INSERT_TAIL(&at_ifaddr, aa, aa_list);
                    195:                        }
1.2       thorpej   196:                        IFAREF(&aa->aa_ifa);
1.1       christos  197:
                    198:                        /*
                    199:                         * Find the end of the interface's addresses
                    200:                         * and link our new one on the end
                    201:                         */
1.24      dyoung    202:                        ifa_insert(ifp, &aa->aa_ifa);
1.1       christos  203:
                    204:                        /*
                    205:                         * As the at_ifaddr contains the actual sockaddrs,
                    206:                         * and the ifaddr itself, link them al together
                    207:                         * correctly.
                    208:                         */
                    209:                        aa->aa_ifa.ifa_addr =
                    210:                            (struct sockaddr *) &aa->aa_addr;
                    211:                        aa->aa_ifa.ifa_dstaddr =
                    212:                            (struct sockaddr *) &aa->aa_addr;
                    213:                        aa->aa_ifa.ifa_netmask =
                    214:                            (struct sockaddr *) &aa->aa_netmask;
                    215:
                    216:                        /*
                    217:                         * Set/clear the phase 2 bit.
                    218:                         */
1.20      dyoung    219:                        if (cnr->nr_phase == 1)
1.1       christos  220:                                aa->aa_flags &= ~AFA_PHASE2;
                    221:                        else
                    222:                                aa->aa_flags |= AFA_PHASE2;
                    223:
                    224:                        /*
                    225:                         * and link it all together
                    226:                         */
                    227:                        aa->aa_ifp = ifp;
                    228:                } else {
                    229:                        /*
                    230:                         * If we DID find one then we clobber any routes
                    231:                         * dependent on it..
                    232:                         */
                    233:                        at_scrub(ifp, aa);
                    234:                }
                    235:                break;
                    236:
                    237:        case SIOCGIFADDR:
1.20      dyoung    238:                csat = satocsat(ifreq_getaddr(cmd, ifr));
                    239:                cnr = (const struct netrange *)csat->sat_zero;
                    240:                if (cnr->nr_phase == 1) {
1.1       christos  241:                        /*
                    242:                         * If the request is specifying phase 1, then
                    243:                         * only look at a phase one address
                    244:                         */
                    245:                        for (; aa; aa = aa->aa_list.tqe_next) {
                    246:                                if (aa->aa_ifp == ifp &&
                    247:                                    (aa->aa_flags & AFA_PHASE2) == 0)
                    248:                                        break;
                    249:                        }
1.20      dyoung    250:                } else if (cnr->nr_phase == 2) {
1.1       christos  251:                        /*
1.8       is        252:                         * If the request is specifying phase 2, then
                    253:                         * only look at a phase two address
1.1       christos  254:                         */
                    255:                        for (; aa; aa = aa->aa_list.tqe_next) {
                    256:                                if (aa->aa_ifp == ifp &&
                    257:                                    (aa->aa_flags & AFA_PHASE2))
1.8       is        258:                                        break;
                    259:                        }
                    260:                } else {
                    261:                        /*
                    262:                         * default to everything
                    263:                         */
                    264:                        for (; aa; aa = aa->aa_list.tqe_next) {
                    265:                                if (aa->aa_ifp == ifp)
1.1       christos  266:                                        break;
                    267:                        }
                    268:                }
                    269:
                    270:                if (aa == (struct at_ifaddr *) 0)
                    271:                        return (EADDRNOTAVAIL);
                    272:                break;
                    273:        }
                    274:
                    275:        /*
                    276:          * By the time this switch is run we should be able to assume that
                    277:          * the "aa" pointer is valid when needed.
                    278:          */
                    279:        switch (cmd) {
1.20      dyoung    280:        case SIOCGIFADDR: {
                    281:                union {
                    282:                        struct sockaddr sa;
                    283:                        struct sockaddr_at sat;
                    284:                } u;
1.1       christos  285:
                    286:                /*
                    287:                 * copy the contents of the sockaddr blindly.
                    288:                 */
1.20      dyoung    289:                sockaddr_copy(&u.sa, sizeof(u),
                    290:                    (const struct sockaddr *)&aa->aa_addr);
1.1       christos  291:                /*
                    292:                 * and do some cleanups
                    293:                 */
1.20      dyoung    294:                nr = (struct netrange *)&u.sat.sat_zero;
                    295:                nr->nr_phase = (aa->aa_flags & AFA_PHASE2) ? 2 : 1;
                    296:                nr->nr_firstnet = aa->aa_firstnet;
                    297:                nr->nr_lastnet = aa->aa_lastnet;
                    298:                ifreq_setaddr(cmd, ifr, &u.sa);
1.1       christos  299:                break;
1.20      dyoung    300:        }
1.1       christos  301:
                    302:        case SIOCSIFADDR:
1.20      dyoung    303:                return at_ifinit(ifp, aa,
                    304:                    (const struct sockaddr_at *)ifreq_getaddr(cmd, ifr));
1.1       christos  305:
                    306:        case SIOCAIFADDR:
                    307:                if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr))
                    308:                        return 0;
1.20      dyoung    309:                return at_ifinit(ifp, aa,
                    310:                    (const struct sockaddr_at *)ifreq_getaddr(cmd, ifr));
1.1       christos  311:
                    312:        case SIOCDIFADDR:
1.23      dyoung    313:                at_purgeaddr(&aa->aa_ifa);
1.1       christos  314:                break;
                    315:
                    316:        default:
1.27      dyoung    317:                return ENOTTY;
1.1       christos  318:        }
                    319:        return (0);
1.2       thorpej   320: }
                    321:
                    322: void
1.23      dyoung    323: at_purgeaddr(struct ifaddr *ifa)
1.2       thorpej   324: {
1.23      dyoung    325:        struct ifnet *ifp = ifa->ifa_ifp;
1.2       thorpej   326:        struct at_ifaddr *aa = (void *) ifa;
                    327:
                    328:        /*
                    329:         * scrub all routes.. didn't we just DO this? XXX yes, del it
                    330:         * XXX above XXX not necessarily true anymore
                    331:         */
                    332:        at_scrub(ifp, aa);
                    333:
                    334:        /*
                    335:         * remove the ifaddr from the interface
                    336:         */
1.24      dyoung    337:        ifa_remove(ifp, &aa->aa_ifa);
1.2       thorpej   338:        TAILQ_REMOVE(&at_ifaddr, aa, aa_list);
                    339:        IFAFREE(&aa->aa_ifa);
1.3       thorpej   340: }
                    341:
                    342: void
1.23      dyoung    343: at_purgeif(struct ifnet *ifp)
1.3       thorpej   344: {
1.23      dyoung    345:        if_purgeaddrs(ifp, AF_APPLETALK, at_purgeaddr);
1.1       christos  346: }
                    347:
                    348: /*
                    349:  * Given an interface and an at_ifaddr (supposedly on that interface) remove
                    350:  * any routes that depend on this. Why ifp is needed I'm not sure, as
                    351:  * aa->at_ifaddr.ifa_ifp should be the same.
                    352:  */
                    353: static int
1.28      dsl       354: at_scrub(struct ifnet *ifp, struct at_ifaddr *aa)
1.1       christos  355: {
                    356:        int error = 0;
                    357:
                    358:        if (aa->aa_flags & AFA_ROUTE) {
                    359:                if (ifp->if_flags & IFF_LOOPBACK)
                    360:                        error = aa_delsingleroute(&aa->aa_ifa,
                    361:                            &aa->aa_addr.sat_addr, &aa->aa_netmask.sat_addr);
                    362:                else if (ifp->if_flags & IFF_POINTOPOINT)
                    363:                        error = rtinit(&aa->aa_ifa, RTM_DELETE, RTF_HOST);
                    364:                else if (ifp->if_flags & IFF_BROADCAST)
                    365:                        error = aa_dorangeroute(&aa->aa_ifa,
                    366:                            ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet),
                    367:                            RTM_DELETE);
                    368:
                    369:                aa->aa_ifa.ifa_flags &= ~IFA_ROUTE;
                    370:                aa->aa_flags &= ~AFA_ROUTE;
                    371:        }
                    372:        return error;
                    373: }
                    374:
                    375: /*
                    376:  * given an at_ifaddr,a sockaddr_at and an ifp,
                    377:  * bang them all together at high speed and see what happens
                    378:  */
                    379: static int
1.28      dsl       380: at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, const struct sockaddr_at *sat)
1.1       christos  381: {
                    382:        struct netrange nr, onr;
                    383:        struct sockaddr_at oldaddr;
1.5       thorpej   384:        int             s = splnet(), error = 0, i, j;
1.1       christos  385:        int             netinc, nodeinc, nnets;
                    386:        u_short         net;
                    387:
                    388:        /*
                    389:         * save the old addresses in the at_ifaddr just in case we need them.
                    390:         */
                    391:        oldaddr = aa->aa_addr;
                    392:        onr.nr_firstnet = aa->aa_firstnet;
                    393:        onr.nr_lastnet = aa->aa_lastnet;
                    394:
                    395:        /*
                    396:          * take the address supplied as an argument, and add it to the
                    397:          * at_ifnet (also given). Remember ing to update
                    398:          * those parts of the at_ifaddr that need special processing
                    399:          */
1.30      cegger    400:        memset(AA_SAT(aa), 0, sizeof(struct sockaddr_at));
1.32      tsutsui   401:        memcpy(&nr, sat->sat_zero, sizeof(struct netrange));
                    402:        memcpy(AA_SAT(aa)->sat_zero, sat->sat_zero, sizeof(struct netrange));
1.1       christos  403:        nnets = ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet) + 1;
                    404:        aa->aa_firstnet = nr.nr_firstnet;
                    405:        aa->aa_lastnet = nr.nr_lastnet;
                    406:
                    407: #ifdef NETATALKDEBUG
                    408:        printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n",
                    409:            ifp->if_xname,
                    410:            ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
                    411:            ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet),
                    412:            (aa->aa_flags & AFA_PHASE2) ? 2 : 1);
                    413: #endif
                    414:
                    415:        /*
                    416:          * We could eliminate the need for a second phase 1 probe (post
                    417:          * autoconf) if we check whether we're resetting the node. Note
                    418:          * that phase 1 probes use only nodes, not net.node pairs.  Under
                    419:          * phase 2, both the net and node must be the same.
                    420:          */
                    421:        AA_SAT(aa)->sat_len = sat->sat_len;
                    422:        AA_SAT(aa)->sat_family = AF_APPLETALK;
                    423:        if (ifp->if_flags & IFF_LOOPBACK) {
                    424:                AA_SAT(aa)->sat_addr.s_net = sat->sat_addr.s_net;
                    425:                AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node;
                    426: #if 0
                    427:        } else if (fp->if_flags & IFF_POINTOPOINT) {
                    428:                /* unimplemented */
                    429:                /*
                    430:                 * we'd have to copy the dstaddr field over from the sat
                    431:                 * but it's not clear that it would contain the right info..
                    432:                 */
                    433: #endif
                    434:        } else {
                    435:                /*
                    436:                 * We are a normal (probably ethernet) interface.
                    437:                 * apply the new address to the interface structures etc.
                    438:                 * We will probe this address on the net first, before
                    439:                 * applying it to ensure that it is free.. If it is not, then
                    440:                 * we will try a number of other randomly generated addresses
                    441:                 * in this net and then increment the net.  etc.etc. until
                    442:                 * we find an unused address.
                    443:                 */
                    444:                aa->aa_flags |= AFA_PROBING;    /* if not loopback we Must
                    445:                                                 * probe? */
                    446:                if (aa->aa_flags & AFA_PHASE2) {
                    447:                        if (sat->sat_addr.s_net == ATADDR_ANYNET) {
                    448:                                /*
                    449:                                 * If we are phase 2, and the net was not
                    450:                                 * specified * then we select a random net
                    451:                                 * within the supplied netrange.
                    452:                                 * XXX use /dev/random?
                    453:                                 */
                    454:                                if (nnets != 1) {
                    455:                                        net = ntohs(nr.nr_firstnet) +
1.14      kardel    456:                                            time_second % (nnets - 1);
1.1       christos  457:                                } else {
                    458:                                        net = ntohs(nr.nr_firstnet);
                    459:                                }
                    460:                        } else {
                    461:                                /*
                    462:                                 * if a net was supplied, then check that it
                    463:                                 * is within the netrange. If it is not then
                    464:                                 * replace the old values and return an error
                    465:                                 */
                    466:                                if (ntohs(sat->sat_addr.s_net) <
                    467:                                    ntohs(nr.nr_firstnet) ||
                    468:                                    ntohs(sat->sat_addr.s_net) >
                    469:                                    ntohs(nr.nr_lastnet)) {
                    470:                                        aa->aa_addr = oldaddr;
                    471:                                        aa->aa_firstnet = onr.nr_firstnet;
                    472:                                        aa->aa_lastnet = onr.nr_lastnet;
                    473:                                        splx(s);
                    474:                                        return (EINVAL);
                    475:                                }
                    476:                                /*
                    477:                                 * otherwise just use the new net number..
                    478:                                 */
                    479:                                net = ntohs(sat->sat_addr.s_net);
                    480:                        }
                    481:                } else {
                    482:                        /*
                    483:                         * we must be phase one, so just use whatever we were
                    484:                         * given. I guess it really isn't going to be used...
                    485:                         * RIGHT?
                    486:                         */
                    487:                        net = ntohs(sat->sat_addr.s_net);
                    488:                }
                    489:
                    490:                /*
                    491:                 * set the node part of the address into the ifaddr. If it's
                    492:                 * not specified, be random about it... XXX use /dev/random?
                    493:                 */
                    494:                if (sat->sat_addr.s_node == ATADDR_ANYNODE) {
1.14      kardel    495:                        AA_SAT(aa)->sat_addr.s_node = time_second;
1.1       christos  496:                } else {
                    497:                        AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node;
                    498:                }
                    499:
                    500:                /*
                    501:                 * step through the nets in the range starting at the
                    502:                 * (possibly random) start point.
                    503:                 */
                    504:                for (i = nnets, netinc = 1; i > 0; net = ntohs(nr.nr_firstnet) +
                    505:                     ((net - ntohs(nr.nr_firstnet) + netinc) % nnets), i--) {
                    506:                        AA_SAT(aa)->sat_addr.s_net = htons(net);
                    507:
                    508:                        /*
                    509:                         * using a rather strange stepping method,
                    510:                         * stagger through the possible node addresses
                    511:                         * Once again, starting at the (possibly random)
                    512:                         * initial node address.
                    513:                         */
1.14      kardel    514:                        for (j = 0, nodeinc = time_second | 1; j < 256;
1.1       christos  515:                             j++, AA_SAT(aa)->sat_addr.s_node += nodeinc) {
                    516:                                if (AA_SAT(aa)->sat_addr.s_node > 253 ||
                    517:                                    AA_SAT(aa)->sat_addr.s_node < 1) {
                    518:                                        continue;
                    519:                                }
                    520:                                aa->aa_probcnt = 10;
                    521:
                    522:                                /*
                    523:                                 * start off the probes as an asynchronous
                    524:                                 * activity. though why wait 200mSec?
                    525:                                 */
1.4       thorpej   526:                                callout_reset(&aa->aa_probe_ch, hz / 5,
                    527:                                    aarpprobe, ifp);
1.26      ad        528:                                if (tsleep(aa, PPAUSE | PCATCH, "at_ifinit",
                    529:                                    0)) {
1.1       christos  530:                                        /*
                    531:                                         * theoretically we shouldn't time out
                    532:                                         * here so if we returned with an error.
                    533:                                         */
                    534:                                        printf("at_ifinit: timeout?!\n");
                    535:                                        aa->aa_addr = oldaddr;
                    536:                                        aa->aa_firstnet = onr.nr_firstnet;
                    537:                                        aa->aa_lastnet = onr.nr_lastnet;
                    538:                                        splx(s);
                    539:                                        return (EINTR);
                    540:                                }
                    541:                                /*
                    542:                                 * The async activity should have woken us
                    543:                                 * up. We need to see if it was successful in
                    544:                                 * finding a free spot, or if we need to
                    545:                                 * iterate to the next address to try.
                    546:                                 */
                    547:                                if ((aa->aa_flags & AFA_PROBING) == 0)
                    548:                                        break;
                    549:                        }
                    550:
                    551:                        /*
                    552:                         * of course we need to break out through two loops...
                    553:                         */
                    554:                        if ((aa->aa_flags & AFA_PROBING) == 0)
                    555:                                break;
                    556:
                    557:                        /* reset node for next network */
1.14      kardel    558:                        AA_SAT(aa)->sat_addr.s_node = time_second;
1.1       christos  559:                }
                    560:
                    561:                /*
                    562:                 * if we are still trying to probe, then we have finished all
                    563:                 * the possible addresses, so we need to give up
                    564:                 */
                    565:                if (aa->aa_flags & AFA_PROBING) {
                    566:                        aa->aa_addr = oldaddr;
                    567:                        aa->aa_firstnet = onr.nr_firstnet;
                    568:                        aa->aa_lastnet = onr.nr_lastnet;
                    569:                        splx(s);
                    570:                        return (EADDRINUSE);
                    571:                }
                    572:        }
                    573:
                    574:        /*
                    575:         * Now that we have selected an address, we need to tell the
                    576:         * interface about it, just in case it needs to adjust something.
                    577:         */
1.34      dyoung    578:        if ((error = if_addr_init(ifp, &aa->aa_ifa, true)) != 0) {
1.1       christos  579:                /*
                    580:                 * of course this could mean that it objects violently
                    581:                 * so if it does, we back out again..
                    582:                 */
                    583:                aa->aa_addr = oldaddr;
                    584:                aa->aa_firstnet = onr.nr_firstnet;
                    585:                aa->aa_lastnet = onr.nr_lastnet;
                    586:                splx(s);
                    587:                return (error);
                    588:        }
                    589:        /*
                    590:         * set up the netmask part of the at_ifaddr and point the appropriate
                    591:         * pointer in the ifaddr to it. probably pointless, but what the
                    592:         * heck.. XXX
                    593:         */
1.30      cegger    594:        memset(&aa->aa_netmask, 0, sizeof(aa->aa_netmask));
1.1       christos  595:        aa->aa_netmask.sat_len = sizeof(struct sockaddr_at);
                    596:        aa->aa_netmask.sat_family = AF_APPLETALK;
                    597:        aa->aa_netmask.sat_addr.s_net = 0xffff;
                    598:        aa->aa_netmask.sat_addr.s_node = 0;
                    599: #if 0
                    600:        aa->aa_ifa.ifa_netmask = (struct sockaddr *) &(aa->aa_netmask);/* XXX */
                    601: #endif
                    602:
                    603:        /*
                    604:          * Initialize broadcast (or remote p2p) address
                    605:          */
1.30      cegger    606:        memset(&aa->aa_broadaddr, 0, sizeof(aa->aa_broadaddr));
1.1       christos  607:        aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at);
                    608:        aa->aa_broadaddr.sat_family = AF_APPLETALK;
                    609:
                    610:        aa->aa_ifa.ifa_metric = ifp->if_metric;
                    611:        if (ifp->if_flags & IFF_BROADCAST) {
1.33      is        612:                aa->aa_broadaddr.sat_addr.s_net = htons(ATADDR_ANYNET);
                    613:                aa->aa_broadaddr.sat_addr.s_node = ATADDR_BCAST;
1.1       christos  614:                aa->aa_ifa.ifa_broadaddr =
                    615:                    (struct sockaddr *) &aa->aa_broadaddr;
                    616:                /* add the range of routes needed */
                    617:                error = aa_dorangeroute(&aa->aa_ifa,
                    618:                    ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD);
                    619:        } else if (ifp->if_flags & IFF_POINTOPOINT) {
                    620:                struct at_addr  rtaddr, rtmask;
                    621:
1.30      cegger    622:                memset(&rtaddr, 0, sizeof(rtaddr));
                    623:                memset(&rtmask, 0, sizeof(rtmask));
1.1       christos  624:                /* fill in the far end if we know it here XXX */
                    625:                aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) & aa->aa_dstaddr;
                    626:                error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
                    627:        } else if (ifp->if_flags & IFF_LOOPBACK) {
                    628:                struct at_addr  rtaddr, rtmask;
                    629:
1.30      cegger    630:                memset(&rtaddr, 0, sizeof(rtaddr));
                    631:                memset(&rtmask, 0, sizeof(rtmask));
1.1       christos  632:                rtaddr.s_net = AA_SAT(aa)->sat_addr.s_net;
                    633:                rtaddr.s_node = AA_SAT(aa)->sat_addr.s_node;
                    634:                rtmask.s_net = 0xffff;
                    635:                rtmask.s_node = 0x0;
                    636:                error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
                    637:        }
                    638:        /*
                    639:          * of course if we can't add these routes we back out, but it's getting
                    640:          * risky by now XXX
                    641:          */
                    642:        if (error) {
                    643:                at_scrub(ifp, aa);
                    644:                aa->aa_addr = oldaddr;
                    645:                aa->aa_firstnet = onr.nr_firstnet;
                    646:                aa->aa_lastnet = onr.nr_lastnet;
                    647:                splx(s);
                    648:                return (error);
                    649:        }
                    650:        /*
                    651:          * note that the address has a route associated with it....
                    652:          */
                    653:        aa->aa_ifa.ifa_flags |= IFA_ROUTE;
                    654:        aa->aa_flags |= AFA_ROUTE;
                    655:        splx(s);
                    656:        return (0);
                    657: }
                    658:
                    659: /*
                    660:  * check whether a given address is a broadcast address for us..
                    661:  */
                    662: int
1.17      dyoung    663: at_broadcast(const struct sockaddr_at *sat)
1.1       christos  664: {
                    665:        struct at_ifaddr *aa;
                    666:
                    667:        /*
                    668:          * If the node is not right, it can't be a broadcast
                    669:          */
                    670:        if (sat->sat_addr.s_node != ATADDR_BCAST)
                    671:                return 0;
                    672:
                    673:        /*
                    674:          * If the node was right then if the net is right, it's a broadcast
                    675:          */
                    676:        if (sat->sat_addr.s_net == ATADDR_ANYNET)
                    677:                return 1;
                    678:
                    679:        /*
                    680:          * failing that, if the net is one we have, it's a broadcast as well.
                    681:          */
                    682:        for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) {
                    683:                if ((aa->aa_ifp->if_flags & IFF_BROADCAST)
                    684:                    && (ntohs(sat->sat_addr.s_net) >= ntohs(aa->aa_firstnet)
                    685:                  && ntohs(sat->sat_addr.s_net) <= ntohs(aa->aa_lastnet)))
                    686:                        return 1;
                    687:        }
                    688:        return 0;
                    689: }
                    690:
                    691:
                    692: /*
                    693:  * aa_dorangeroute()
                    694:  *
                    695:  * Add a route for a range of networks from bot to top - 1.
                    696:  * Algorithm:
                    697:  *
                    698:  * Split the range into two subranges such that the middle
                    699:  * of the two ranges is the point where the highest bit of difference
                    700:  * between the two addresses, makes it's transition
                    701:  * Each of the upper and lower ranges might not exist, or might be
                    702:  * representable by 1 or more netmasks. In addition, if both
                    703:  * ranges can be represented by the same netmask, then teh can be merged
                    704:  * by using the next higher netmask..
                    705:  */
                    706:
                    707: static int
1.28      dsl       708: aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd)
1.1       christos  709: {
                    710:        u_int           mask1;
                    711:        struct at_addr  addr;
                    712:        struct at_addr  mask;
                    713:        int             error;
                    714:
                    715:        /*
                    716:         * slight sanity check
                    717:         */
                    718:        if (bot > top)
                    719:                return (EINVAL);
                    720:
                    721:        addr.s_node = 0;
                    722:        mask.s_node = 0;
                    723:        /*
                    724:         * just start out with the lowest boundary
                    725:         * and keep extending the mask till it's too big.
                    726:         */
                    727:
                    728:        while (bot <= top) {
                    729:                mask1 = 1;
                    730:                while (((bot & ~mask1) >= bot)
                    731:                       && ((bot | mask1) <= top)) {
                    732:                        mask1 <<= 1;
                    733:                        mask1 |= 1;
                    734:                }
                    735:                mask1 >>= 1;
                    736:                mask.s_net = htons(~mask1);
                    737:                addr.s_net = htons(bot);
                    738:                if (cmd == RTM_ADD) {
                    739:                        error = aa_addsingleroute(ifa, &addr, &mask);
                    740:                        if (error) {
                    741:                                /* XXX clean up? */
                    742:                                return (error);
                    743:                        }
                    744:                } else {
                    745:                        error = aa_delsingleroute(ifa, &addr, &mask);
                    746:                }
                    747:                bot = (bot | mask1) + 1;
                    748:        }
                    749:        return 0;
                    750: }
                    751:
                    752: static int
1.28      dsl       753: aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask)
1.1       christos  754: {
                    755:        int error;
                    756:
                    757: #ifdef NETATALKDEBUG
                    758:        printf("aa_addsingleroute: %x.%x mask %x.%x ...",
                    759:               ntohs(addr->s_net), addr->s_node,
                    760:               ntohs(mask->s_net), mask->s_node);
                    761: #endif
                    762:
                    763:        error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP);
                    764: #ifdef NETATALKDEBUG
                    765:        if (error)
                    766:                printf("aa_addsingleroute: error %d\n", error);
                    767: #endif
                    768:        return (error);
                    769: }
                    770:
                    771: static int
1.28      dsl       772: aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask)
1.1       christos  773: {
                    774:        int error;
                    775:
                    776: #ifdef NETATALKDEBUG
                    777:        printf("aa_delsingleroute: %x.%x mask %x.%x ...",
                    778:               ntohs(addr->s_net), addr->s_node,
                    779:               ntohs(mask->s_net), mask->s_node);
                    780: #endif
                    781:
                    782:        error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0);
                    783: #ifdef NETATALKDEBUG
                    784:        if (error)
                    785:                printf("aa_delsingleroute: error %d\n", error);
                    786: #endif
                    787:        return (error);
                    788: }
                    789:
                    790: static int
1.28      dsl       791: aa_dosingleroute(struct ifaddr *ifa, struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags)
1.1       christos  792: {
                    793:        struct sockaddr_at addr, mask, *gate;
                    794:
1.30      cegger    795:        memset(&addr, 0, sizeof(addr));
                    796:        memset(&mask, 0, sizeof(mask));
1.1       christos  797:        addr.sat_family = AF_APPLETALK;
                    798:        addr.sat_len = sizeof(struct sockaddr_at);
                    799:        addr.sat_addr.s_net = at_addr->s_net;
                    800:        addr.sat_addr.s_node = at_addr->s_node;
                    801:        mask.sat_family = AF_APPLETALK;
                    802:        mask.sat_len = sizeof(struct sockaddr_at);
                    803:        mask.sat_addr.s_net = at_mask->s_net;
                    804:        mask.sat_addr.s_node = at_mask->s_node;
                    805:
                    806:        if (at_mask->s_node) {
                    807:                gate = satosat(ifa->ifa_dstaddr);
                    808:                flags |= RTF_HOST;
                    809:        } else {
                    810:                gate = satosat(ifa->ifa_addr);
                    811:        }
                    812:
                    813: #ifdef NETATALKDEBUG
                    814:        printf("on %s %x.%x\n", (flags & RTF_HOST) ? "host" : "net",
                    815:               ntohs(gate->sat_addr.s_net), gate->sat_addr.s_node);
                    816: #endif
                    817:        return (rtrequest(cmd, (struct sockaddr *) &addr,
                    818:            (struct sockaddr *) gate, (struct sockaddr *) &mask, flags, NULL));
                    819: }
                    820:
                    821: #if 0
                    822: static void
1.29      cegger    823: aa_clean(void)
1.1       christos  824: {
                    825:        struct at_ifaddr *aa;
                    826:        struct ifaddr  *ifa;
                    827:        struct ifnet   *ifp;
                    828:
1.21      dyoung    829:        while ((aa = TAILQ_FIRST(&at_ifaddr)) != NULL) {
                    830:                TAILQ_REMOVE(&at_ifaddr, aa, aa_list);
1.1       christos  831:                ifp = aa->aa_ifp;
                    832:                at_scrub(ifp, aa);
1.21      dyoung    833:                IFADDR_FOREACH(ifa, ifp) {
                    834:                        if (ifa == &aa->aa_ifa)
                    835:                                break;
1.1       christos  836:                }
1.21      dyoung    837:                if (ifa == NULL)
                    838:                        panic("aa not present");
1.24      dyoung    839:                ifa_remove(ifp, ifa);
1.1       christos  840:        }
                    841: }
                    842: #endif

CVSweb <webmaster@jp.NetBSD.org>