root/netatalk/at_control.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. at_control
  2. at_scrub
  3. at_ifinit
  4. at_broadcast
  5. aa_dorangeroute
  6. aa_addsingleroute
  7. aa_delsingleroute
  8. aa_dosingleroute

    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 }

/* [<][>][^][v][top][bottom][index][help] */