[BACK]Return to at_control.c CVS log [TXT][DIR] Up to [local] / sys / netatalk

Annotation of sys/netatalk/at_control.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: at_control.c,v 1.10 2007/04/10 17:47:55 miod Exp $    */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1990,1991 Regents of The University of Michigan.
        !             5:  * All Rights Reserved.
        !             6:  */
        !             7:
        !             8: /*
        !             9:  * The following is the contents of the COPYRIGHT file from the
        !            10:  * netatalk-1.4a2 distribution, from which this file is derived.
        !            11:  */
        !            12: /*
        !            13:  * Copyright (c) 1990,1996 Regents of The University of Michigan.
        !            14:  *
        !            15:  * All Rights Reserved.
        !            16:  *
        !            17:  *    Permission to use, copy, modify, and distribute this software and
        !            18:  *    its documentation for any purpose and without fee is hereby granted,
        !            19:  *    provided that the above copyright notice appears in all copies and
        !            20:  *    that both that copyright notice and this permission notice appear
        !            21:  *    in supporting documentation, and that the name of The University
        !            22:  *    of Michigan not be used in advertising or publicity pertaining to
        !            23:  *    distribution of the software without specific, written prior
        !            24:  *    permission. This software is supplied as is without expressed or
        !            25:  *    implied warranties of any kind.
        !            26:  *
        !            27:  * This product includes software developed by the University of
        !            28:  * California, Berkeley and its contributors.
        !            29:  *
        !            30:  * Solaris code is encumbered by the following:
        !            31:  *
        !            32:  *     Copyright (C) 1996 by Sun Microsystems Computer Co.
        !            33:  *
        !            34:  *     Permission to use, copy, modify, and distribute this software and
        !            35:  *     its documentation for any purpose and without fee is hereby
        !            36:  *     granted, provided that the above copyright notice appear in all
        !            37:  *     copies and that both that copyright notice and this permission
        !            38:  *     notice appear in supporting documentation.  This software is
        !            39:  *     provided "as is" without express or implied warranty.
        !            40:  *
        !            41:  * Research Systems Unix Group
        !            42:  * The University of Michigan
        !            43:  * c/o Wesley Craig
        !            44:  * 535 W. William Street
        !            45:  * Ann Arbor, Michigan
        !            46:  * +1-313-764-2278
        !            47:  * netatalk@umich.edu
        !            48:  */
        !            49: /*
        !            50:  * None of the Solaris code mentioned is included in OpenBSD.
        !            51:  * This code also relies heavily on previous effort in FreeBSD and NetBSD.
        !            52:  */
        !            53:
        !            54: #include <sys/param.h>
        !            55: #include <sys/systm.h>
        !            56: #include <sys/kernel.h>
        !            57: #include <sys/malloc.h>
        !            58: #include <sys/mbuf.h>
        !            59: #include <sys/protosw.h>
        !            60: #include <sys/socket.h>
        !            61: #include <sys/ioctl.h>
        !            62: #include <sys/errno.h>
        !            63: #include <sys/syslog.h>
        !            64: #include <sys/proc.h>
        !            65: #include <sys/timeout.h>
        !            66:
        !            67: #include <net/if.h>
        !            68: #include <net/route.h>
        !            69: #include <netinet/in.h>
        !            70: #undef s_net
        !            71: #include <netinet/if_ether.h>
        !            72: #include <net/if_llc.h>
        !            73:
        !            74: #include <netatalk/at.h>
        !            75: #include <netatalk/at_var.h>
        !            76: #include <netatalk/aarp.h>
        !            77: #include <netatalk/phase2.h>
        !            78: #include <netatalk/at_extern.h>
        !            79:
        !            80: #include <dev/rndvar.h>
        !            81:
        !            82: int    at_control( u_long, caddr_t, struct ifnet *, struct proc * );
        !            83: static int at_scrub( struct ifnet *, struct at_ifaddr * );
        !            84: static int at_ifinit( struct ifnet *, struct at_ifaddr *,
        !            85:                                struct sockaddr_at * );
        !            86: int at_broadcast( struct sockaddr_at * );
        !            87:
        !            88: static int aa_dorangeroute(struct ifaddr *, u_int, u_int, int);
        !            89: static int aa_addsingleroute(struct ifaddr *, struct at_addr *,
        !            90:                                        struct at_addr *);
        !            91: static int aa_delsingleroute(struct ifaddr *, struct at_addr *,
        !            92:                                        struct at_addr *);
        !            93: static int aa_dosingleroute(struct ifaddr *, struct at_addr *,
        !            94:                                        struct at_addr *, int, int );
        !            95:
        !            96: # define sateqaddr(a,b)        ((a)->sat_len == (b)->sat_len && \
        !            97:                    (a)->sat_family == (b)->sat_family && \
        !            98:                    (a)->sat_addr.s_net == (b)->sat_addr.s_net && \
        !            99:                    (a)->sat_addr.s_node == (b)->sat_addr.s_node )
        !           100:
        !           101: extern struct timeout aarpprobe_timeout;
        !           102:
        !           103: int
        !           104: at_control( cmd, data, ifp, p )
        !           105:     u_long             cmd;
        !           106:     caddr_t            data;
        !           107:     struct ifnet       *ifp;
        !           108:     struct proc                *p;
        !           109: {
        !           110:     struct ifreq       *ifr = (struct ifreq *)data;
        !           111:     struct sockaddr_at *sat;
        !           112:     struct netrange    *nr;
        !           113:     struct at_aliasreq *ifra = (struct at_aliasreq *)data;
        !           114:     struct at_ifaddr   *aa0;
        !           115:     struct at_ifaddr   *aa = 0;
        !           116:     struct ifaddr      *ifa, *ifa0;
        !           117:
        !           118:     if ( ifp ) {
        !           119:        for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
        !           120:            if ( aa->aa_ifp == ifp ) break;
        !           121:        }
        !           122:     }
        !           123:
        !           124:     switch ( cmd ) {
        !           125:     case SIOCAIFADDR:
        !           126:     case SIOCDIFADDR:
        !           127:        if ( ifra->ifra_addr.sat_family == AF_APPLETALK ) {
        !           128:            for ( ; aa; aa = aa->aa_next ) {
        !           129:                if ( aa->aa_ifp == ifp &&
        !           130:                        sateqaddr( &aa->aa_addr, &ifra->ifra_addr )) {
        !           131:                    break;
        !           132:                }
        !           133:            }
        !           134:        }
        !           135:        if ( cmd == SIOCDIFADDR && aa == 0 ) {
        !           136:            return( EADDRNOTAVAIL );
        !           137:        }
        !           138:        /*FALLTHROUGH*/
        !           139:
        !           140:     case SIOCSIFADDR:
        !           141:        /*
        !           142:         * What a great idea this is: Let's reverse the meaning of
        !           143:         * the return...
        !           144:         */
        !           145:        if ( suser( p, 0 )) {
        !           146:            return( EPERM );
        !           147:        }
        !           148:
        !           149:        sat = satosat( &ifr->ifr_addr );
        !           150:        nr = (struct netrange *)sat->sat_zero;
        !           151:        if ( nr->nr_phase == 1 ) {
        !           152:            for ( ; aa; aa = aa->aa_next ) {
        !           153:                if ( aa->aa_ifp == ifp &&
        !           154:                        ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
        !           155:                    break;
        !           156:                }
        !           157:            }
        !           158:        } else {                /* default to phase 2 */
        !           159:            for ( ; aa; aa = aa->aa_next ) {
        !           160:                if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
        !           161:                    break;
        !           162:                }
        !           163:            }
        !           164:        }
        !           165:
        !           166:        if ( ifp == 0 )
        !           167:            panic( "at_control" );
        !           168:
        !           169:        if ( aa == (struct at_ifaddr *) 0 ) {
        !           170:            aa0 = malloc(sizeof(struct at_ifaddr), M_IFADDR, M_WAITOK);
        !           171:            bzero(aa0, sizeof(struct at_ifaddr));
        !           172:
        !           173:            if (( aa = at_ifaddr ) != NULL ) {
        !           174:                /*
        !           175:                 * Don't let the loopback be first, since the first
        !           176:                 * address is the machine's default address for
        !           177:                 * binding.
        !           178:                 */
        !           179:                if ( at_ifaddr->aa_ifp->if_flags & IFF_LOOPBACK ) {
        !           180:                    aa = aa0;
        !           181:                    aa->aa_next = at_ifaddr;
        !           182:                    at_ifaddr = aa;
        !           183:                } else {
        !           184:                    for ( ; aa->aa_next; aa = aa->aa_next )
        !           185:                        ;
        !           186:                    aa->aa_next = aa0;
        !           187:                }
        !           188:            } else {
        !           189:                at_ifaddr = aa0;
        !           190:            }
        !           191:
        !           192:            aa = aa0;
        !           193:
        !           194:            if (( ifa = ifp->if_addrlist.tqh_first ) != NULL ) {
        !           195:                for ( ; ifa->ifa_list.tqe_next; ifa = ifa->ifa_list.tqe_next )
        !           196:                    ;
        !           197:                ifa->ifa_list.tqe_next = (struct ifaddr *)aa;
        !           198:            } else {
        !           199:                ifp->if_addrlist.tqh_first = (struct ifaddr *)aa;
        !           200:            }
        !           201:
        !           202:            /* FreeBSD found this. Whew */
        !           203:            aa->aa_ifa.ifa_refcnt++;
        !           204:
        !           205:            aa->aa_ifa.ifa_addr = (struct sockaddr *)&aa->aa_addr;
        !           206:            aa->aa_ifa.ifa_dstaddr = (struct sockaddr *)&aa->aa_addr;
        !           207:            aa->aa_ifa.ifa_netmask = (struct sockaddr *)&aa->aa_netmask;
        !           208:
        !           209:            /*
        !           210:             * Set/clear the phase 2 bit.
        !           211:             */
        !           212:            if ( nr->nr_phase == 1 ) {
        !           213:                aa->aa_flags &= ~AFA_PHASE2;
        !           214:            } else {
        !           215:                aa->aa_flags |= AFA_PHASE2;
        !           216:            }
        !           217:            aa->aa_ifp = ifp;
        !           218:        } else {
        !           219:            at_scrub( ifp, aa );
        !           220:        }
        !           221:        break;
        !           222:
        !           223:     case SIOCGIFADDR :
        !           224:        sat = satosat( &ifr->ifr_addr );
        !           225:        nr = (struct netrange *)sat->sat_zero;
        !           226:        if ( nr->nr_phase == 1 ) {
        !           227:            for ( ; aa; aa = aa->aa_next ) {
        !           228:                if ( aa->aa_ifp == ifp &&
        !           229:                        ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
        !           230:                    break;
        !           231:                }
        !           232:            }
        !           233:        } else {                /* default to phase 2 */
        !           234:            for ( ; aa; aa = aa->aa_next ) {
        !           235:                if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
        !           236:                    break;
        !           237:                }
        !           238:            }
        !           239:        }
        !           240:
        !           241:        if ( aa == (struct at_ifaddr *) 0 )
        !           242:            return( EADDRNOTAVAIL );
        !           243:        break;
        !           244:     }
        !           245:
        !           246:     switch ( cmd ) {
        !           247:     case SIOCGIFADDR:
        !           248:        *(struct sockaddr_at *)&ifr->ifr_addr = aa->aa_addr;
        !           249:
        !           250:        /* from FreeBSD : some cleanups about netranges */
        !           251:        ((struct netrange *)&sat->sat_zero)->nr_phase
        !           252:                = (aa->aa_flags & AFA_PHASE2) ? 2 : 1;
        !           253:        ((struct netrange *)&sat->sat_zero)->nr_firstnet = aa->aa_firstnet;
        !           254:        ((struct netrange *)&sat->sat_zero)->nr_lastnet = aa->aa_lastnet;
        !           255:        break;
        !           256:
        !           257:     case SIOCSIFADDR:
        !           258:        return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));
        !           259:
        !           260:     case SIOCAIFADDR:
        !           261:        if ( sateqaddr( &ifra->ifra_addr, &aa->aa_addr )) {
        !           262:            return( 0 );
        !           263:        }
        !           264:        return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));
        !           265:
        !           266:     case SIOCDIFADDR:
        !           267:        at_scrub( ifp, aa );
        !           268:        ifa0 = (struct ifaddr *)aa;
        !           269:        if (( ifa = ifp->if_addrlist.tqh_first ) == ifa0 ) {
        !           270:            ifp->if_addrlist.tqh_first = ifa->ifa_list.tqe_next;
        !           271:        } else {
        !           272:            while ( ifa->ifa_list.tqe_next &&
        !           273:                        ( ifa->ifa_list.tqe_next != ifa0 )) {
        !           274:                ifa = ifa->ifa_list.tqe_next;
        !           275:            }
        !           276:            if ( ifa->ifa_list.tqe_next ) {
        !           277:                ifa->ifa_list.tqe_next = ifa0->ifa_list.tqe_next;
        !           278:            } else {
        !           279:                panic( "at_control" );
        !           280:            }
        !           281:        }
        !           282:
        !           283:        /* FreeBSD */
        !           284:        IFAFREE(ifa0);
        !           285:
        !           286:        aa0 = aa;
        !           287:        if ( aa0 == ( aa = at_ifaddr )) {
        !           288:            at_ifaddr = aa->aa_next;
        !           289:        } else {
        !           290:            while ( aa->aa_next && ( aa->aa_next != aa0 )) {
        !           291:                aa = aa->aa_next;
        !           292:            }
        !           293:            if ( aa->aa_next ) {
        !           294:                aa->aa_next = aa0->aa_next;
        !           295:            } else {
        !           296:                panic( "at_control" );
        !           297:            }
        !           298:        }
        !           299:
        !           300:        /* FreeBSD */
        !           301:        IFAFREE(ifa0);
        !           302:        break;
        !           303:
        !           304:     default:
        !           305:        if ( ifp == 0 || ifp->if_ioctl == 0 )
        !           306:            return( EOPNOTSUPP );
        !           307:        return( (*ifp->if_ioctl)( ifp, cmd, data ));
        !           308:     }
        !           309:     return( 0 );
        !           310: }
        !           311:
        !           312: /* replaced this routine with the one from FreeBSD */
        !           313: static int
        !           314: at_scrub( ifp, aa )
        !           315:     struct ifnet       *ifp;
        !           316:     struct at_ifaddr   *aa;
        !           317: {
        !           318:     int                        error;
        !           319:
        !           320:     if ( aa->aa_flags & AFA_ROUTE ) {
        !           321:        if (ifp->if_flags & IFF_LOOPBACK) {
        !           322:                if ((error = aa_delsingleroute(&aa->aa_ifa,
        !           323:                                        &aa->aa_addr.sat_addr,
        !           324:                                        &aa->aa_netmask.sat_addr))) {
        !           325:                        return( error );
        !           326:                }
        !           327:        } else if (ifp->if_flags & IFF_POINTOPOINT) {
        !           328:                if ((error = rtinit( &aa->aa_ifa, RTM_DELETE, RTF_HOST)) != 0)
        !           329:                        return( error );
        !           330:        } else if (ifp->if_flags & IFF_BROADCAST) {
        !           331:                error = aa_dorangeroute(&aa->aa_ifa,
        !           332:                                ntohs(aa->aa_firstnet),
        !           333:                                ntohs(aa->aa_lastnet),
        !           334:                                RTM_DELETE );
        !           335:        }
        !           336:        aa->aa_ifa.ifa_flags &= ~IFA_ROUTE;
        !           337:        aa->aa_flags &= ~AFA_ROUTE;
        !           338:     }
        !           339:     return( 0 );
        !           340: }
        !           341:
        !           342: static int
        !           343: at_ifinit( ifp, aa, sat )
        !           344:     struct ifnet       *ifp;
        !           345:     struct at_ifaddr   *aa;
        !           346:     struct sockaddr_at *sat;
        !           347: {
        !           348:     struct netrange    nr, onr;
        !           349:     struct sockaddr_at oldaddr;
        !           350:     int                        s = splnet(), error = 0, i, j, netinc, nodeinc, nnets;
        !           351:     u_int16_t          net;
        !           352:
        !           353:     oldaddr = aa->aa_addr;
        !           354:     bzero( AA_SAT( aa ), sizeof( struct sockaddr_at ));
        !           355:     bcopy( sat->sat_zero, &nr, sizeof( struct netrange ));
        !           356:     bcopy( sat->sat_zero, AA_SAT( aa )->sat_zero, sizeof( struct netrange ));
        !           357:     nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1;
        !           358:
        !           359:     onr.nr_firstnet = aa->aa_firstnet;
        !           360:     onr.nr_lastnet = aa->aa_lastnet;
        !           361:     aa->aa_firstnet = nr.nr_firstnet;
        !           362:     aa->aa_lastnet = nr.nr_lastnet;
        !           363:
        !           364:     /*
        !           365:      * We could eliminate the need for a second phase 1 probe (post
        !           366:      * autoconf) if we check whether we're resetting the node. Note
        !           367:      * that phase 1 probes use only nodes, not net.node pairs.  Under
        !           368:      * phase 2, both the net and node must be the same.
        !           369:      */
        !           370:     if ( ifp->if_flags & IFF_LOOPBACK ) {
        !           371:        AA_SAT( aa )->sat_len = sat->sat_len;
        !           372:        AA_SAT( aa )->sat_family = AF_APPLETALK;
        !           373:        AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net;
        !           374:        AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node;
        !           375:     } else {
        !           376:        aa->aa_flags |= AFA_PROBING;
        !           377:        AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at);
        !           378:        AA_SAT( aa )->sat_family = AF_APPLETALK;
        !           379:        if ( aa->aa_flags & AFA_PHASE2 ) {
        !           380:            if ( sat->sat_addr.s_net == ATADDR_ANYNET ) {
        !           381:                if ( nnets != 1 ) {
        !           382:                    net = ntohs( nr.nr_firstnet ) +
        !           383:                        arc4random() % ( nnets - 1 );
        !           384:                } else {
        !           385:                    net = ntohs( nr.nr_firstnet );
        !           386:                }
        !           387:            } else {
        !           388:                if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) ||
        !           389:                        ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) {
        !           390:                    aa->aa_addr = oldaddr;
        !           391:                    aa->aa_firstnet = onr.nr_firstnet;
        !           392:                    aa->aa_lastnet = onr.nr_lastnet;
        !           393:                    splx(s);
        !           394:                    return( EINVAL );
        !           395:                }
        !           396:                net = ntohs( sat->sat_addr.s_net );
        !           397:            }
        !           398:        } else {
        !           399:            net = ntohs( sat->sat_addr.s_net );
        !           400:        }
        !           401:
        !           402:        if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) {
        !           403:            AA_SAT( aa )->sat_addr.s_node = arc4random();
        !           404:        } else {
        !           405:            AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node;
        !           406:        }
        !           407:
        !           408:        for ( i = nnets, netinc = 1; i > 0; net = ntohs( nr.nr_firstnet ) +
        !           409:                (( net - ntohs( nr.nr_firstnet ) + netinc ) % nnets ), i-- ) {
        !           410:            AA_SAT( aa )->sat_addr.s_net = htons( net );
        !           411:
        !           412:            for ( j = 0, nodeinc = arc4random() | 1; j < 256;
        !           413:                    j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) {
        !           414:                if ( AA_SAT( aa )->sat_addr.s_node > 253 ||
        !           415:                        AA_SAT( aa )->sat_addr.s_node < 1 ) {
        !           416:                    continue;
        !           417:                }
        !           418:                aa->aa_probcnt = 10;
        !           419:                timeout_set(&aarpprobe_timeout, aarpprobe, ifp);
        !           420:                /* XXX don't use hz so badly */
        !           421:                timeout_add(&aarpprobe_timeout, hz / 5);
        !           422:                if ( tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 )) {
        !           423:                    printf( "at_ifinit why did this happen?!\n" );
        !           424:                    aa->aa_addr = oldaddr;
        !           425:                    aa->aa_firstnet = onr.nr_firstnet;
        !           426:                    aa->aa_lastnet = onr.nr_lastnet;
        !           427:                    splx( s );
        !           428:                    return( EINTR );
        !           429:                }
        !           430:                if (( aa->aa_flags & AFA_PROBING ) == 0 ) {
        !           431:                    break;
        !           432:                }
        !           433:            }
        !           434:            if (( aa->aa_flags & AFA_PROBING ) == 0 ) {
        !           435:                break;
        !           436:            }
        !           437:            /* reset node for next network */
        !           438:            AA_SAT( aa )->sat_addr.s_node = arc4random();
        !           439:        }
        !           440:
        !           441:        if ( aa->aa_flags & AFA_PROBING ) {
        !           442:            aa->aa_addr = oldaddr;
        !           443:            aa->aa_firstnet = onr.nr_firstnet;
        !           444:            aa->aa_lastnet = onr.nr_lastnet;
        !           445:            splx( s );
        !           446:            return( EADDRINUSE );
        !           447:        }
        !           448:     }
        !           449:
        !           450:     if ( ifp->if_ioctl &&
        !           451:            ( error = (*ifp->if_ioctl)( ifp, SIOCSIFADDR, (caddr_t) aa ))) {
        !           452:        aa->aa_addr = oldaddr;
        !           453:        aa->aa_firstnet = onr.nr_firstnet;
        !           454:        aa->aa_lastnet = onr.nr_lastnet;
        !           455:        splx( s );
        !           456:        return( error );
        !           457:     }
        !           458:
        !           459:     bzero(&aa->aa_netmask, sizeof(aa->aa_netmask));
        !           460:     aa->aa_netmask.sat_len = sizeof(struct sockaddr_at);
        !           461:     aa->aa_netmask.sat_family = AF_APPLETALK;
        !           462:     aa->aa_netmask.sat_addr.s_net = 0xffff;
        !           463:     aa->aa_netmask.sat_addr.s_node = 0;
        !           464:     /* XXX From FreeBSD. Why does it do this? */
        !           465:     aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask);
        !           466:
        !           467:     /* This block came from FreeBSD too */
        !           468:     /*
        !           469:      * Initialize broadcast (or remote p2p) address
        !           470:      */
        !           471:     bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr));
        !           472:     aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at);
        !           473:     aa->aa_broadaddr.sat_family = AF_APPLETALK;
        !           474:
        !           475:     aa->aa_ifa.ifa_metric = ifp->if_metric;
        !           476:     if (ifp->if_flags & IFF_BROADCAST) {
        !           477:        aa->aa_broadaddr.sat_addr.s_net = htons(0);
        !           478:        aa->aa_broadaddr.sat_addr.s_node = 0xff;
        !           479:        aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr;
        !           480:        /* add the range of routes needed */
        !           481:        error = aa_dorangeroute(&aa->aa_ifa,
        !           482:                ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD );
        !           483:     }
        !           484:     else if (ifp->if_flags & IFF_POINTOPOINT) {
        !           485:        struct at_addr  rtaddr, rtmask;
        !           486:
        !           487:        bzero(&rtaddr, sizeof(rtaddr));
        !           488:        bzero(&rtmask, sizeof(rtmask));
        !           489:        /* fill in the far end if we know it here XXX */
        !           490:        aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_broadaddr;
        !           491:        error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
        !           492:     }
        !           493:     else if ( ifp->if_flags & IFF_LOOPBACK ) {
        !           494:        struct at_addr  rtaddr, rtmask;
        !           495:
        !           496:        bzero(&rtaddr, sizeof(rtaddr));
        !           497:        bzero(&rtmask, sizeof(rtmask));
        !           498:        rtaddr.s_net = AA_SAT( aa )->sat_addr.s_net;
        !           499:        rtaddr.s_node = AA_SAT( aa )->sat_addr.s_node;
        !           500:        rtmask.s_net = 0xffff;
        !           501:        rtmask.s_node = 0x0; /* XXX should not be so.. should be HOST route */
        !           502:        error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
        !           503:     }
        !           504:
        !           505:     if ( error ) {
        !           506:        at_scrub( ifp, aa );
        !           507:        aa->aa_addr = oldaddr;
        !           508:        aa->aa_firstnet = onr.nr_firstnet;
        !           509:        aa->aa_lastnet = onr.nr_lastnet;
        !           510:        splx( s );
        !           511:        return( error );
        !           512:     }
        !           513:
        !           514:     aa->aa_ifa.ifa_flags |= IFA_ROUTE;
        !           515:     aa->aa_flags |= AFA_ROUTE;
        !           516:     splx( s );
        !           517:     return( 0 );
        !           518: }
        !           519:
        !           520: int
        !           521: at_broadcast( sat )
        !           522:     struct sockaddr_at *sat;
        !           523: {
        !           524:     struct at_ifaddr   *aa;
        !           525:
        !           526:     if ( sat->sat_addr.s_node != ATADDR_BCAST ) {
        !           527:        return( 0 );
        !           528:     }
        !           529:     if ( sat->sat_addr.s_net == ATADDR_ANYNET ) {
        !           530:        return( 1 );
        !           531:     } else {
        !           532:        for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
        !           533:            if (( aa->aa_ifp->if_flags & IFF_BROADCAST ) &&
        !           534:                 ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) &&
        !           535:                 ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet ))) {
        !           536:                return( 1 );
        !           537:            }
        !           538:        }
        !           539:     }
        !           540:     return( 0 );
        !           541: }
        !           542:
        !           543: /* Yet another bunch of routines from FreeBSD. Those guys are good */
        !           544: /*
        !           545:  * aa_dorangeroute()
        !           546:  *
        !           547:  * Add a route for a range of networks from bot to top - 1.
        !           548:  * Algorithm:
        !           549:  *
        !           550:  * Split the range into two subranges such that the middle
        !           551:  * of the two ranges is the point where the highest bit of difference
        !           552:  * between the two addresses, makes its transition
        !           553:  * Each of the upper and lower ranges might not exist, or might be
        !           554:  * representable by 1 or more netmasks. In addition, if both
        !           555:  * ranges can be represented by the same netmask, then they can be merged
        !           556:  * by using the next higher netmask..
        !           557:  */
        !           558:
        !           559: static int
        !           560: aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd)
        !           561: {
        !           562:        u_int mask1;
        !           563:        struct at_addr addr;
        !           564:        struct at_addr mask;
        !           565:        int error;
        !           566:
        !           567:        /*
        !           568:         * slight sanity check
        !           569:         */
        !           570:        if (bot > top) return (EINVAL);
        !           571:
        !           572:        addr.s_node = 0;
        !           573:        mask.s_node = 0;
        !           574:        /*
        !           575:         * just start out with the lowest boundary
        !           576:         * and keep extending the mask till it's too big.
        !           577:         */
        !           578:
        !           579:         while (bot <= top) {
        !           580:                mask1 = 1;
        !           581:                while ((( bot & ~mask1) >= bot)
        !           582:                   && (( bot | mask1) <= top)) {
        !           583:                        mask1 <<= 1;
        !           584:                        mask1 |= 1;
        !           585:                }
        !           586:                mask1 >>= 1;
        !           587:                mask.s_net = htons(~mask1);
        !           588:                addr.s_net = htons(bot);
        !           589:                if(cmd == RTM_ADD) {
        !           590:                error =  aa_addsingleroute(ifa,&addr,&mask);
        !           591:                        if (error) {
        !           592:                                /* XXX clean up? */
        !           593:                                return (error);
        !           594:                        }
        !           595:                } else {
        !           596:                        error =  aa_delsingleroute(ifa,&addr,&mask);
        !           597:                }
        !           598:                bot = (bot | mask1) + 1;
        !           599:        }
        !           600:        return 0;
        !           601: }
        !           602:
        !           603: static int
        !           604: aa_addsingleroute(struct ifaddr *ifa,
        !           605:        struct at_addr *addr, struct at_addr *mask)
        !           606: {
        !           607:   int  error;
        !           608:
        !           609: #if 0
        !           610:   printf("aa_addsingleroute: %x.%x mask %x.%x ...\n",
        !           611:     ntohs(addr->s_net), addr->s_node,
        !           612:     ntohs(mask->s_net), mask->s_node);
        !           613: #endif
        !           614:
        !           615:   error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP);
        !           616:   if (error)
        !           617:     printf("aa_addsingleroute: error %d\n", error);
        !           618:   return(error);
        !           619: }
        !           620:
        !           621: static int
        !           622: aa_delsingleroute(struct ifaddr *ifa,
        !           623:        struct at_addr *addr, struct at_addr *mask)
        !           624: {
        !           625:   int  error;
        !           626:
        !           627:   error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0);
        !           628:   if (error)
        !           629:        printf("aa_delsingleroute: error %d\n", error);
        !           630:   return(error);
        !           631: }
        !           632:
        !           633: static int
        !           634: aa_dosingleroute(struct ifaddr *ifa,
        !           635:        struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags)
        !           636: {
        !           637:   struct sockaddr_at   addr, mask;
        !           638:
        !           639:   bzero(&addr, sizeof(addr));
        !           640:   bzero(&mask, sizeof(mask));
        !           641:   addr.sat_family = AF_APPLETALK;
        !           642:   addr.sat_len = sizeof(struct sockaddr_at);
        !           643:   addr.sat_addr.s_net = at_addr->s_net;
        !           644:   addr.sat_addr.s_node = at_addr->s_node;
        !           645:   mask.sat_family = AF_APPLETALK;
        !           646:   mask.sat_len = sizeof(struct sockaddr_at);
        !           647:   mask.sat_addr.s_net = at_mask->s_net;
        !           648:   mask.sat_addr.s_node = at_mask->s_node;
        !           649:   if (at_mask->s_node)
        !           650:     flags |= RTF_HOST;
        !           651:   return(rtrequest(cmd, (struct sockaddr *) &addr,
        !           652:        (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr),
        !           653:        (struct sockaddr *) &mask, flags, NULL, 0));
        !           654: }

CVSweb