The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netatalk/at_control.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: fd6d500bbe03f5b2a05153591c1b4dd6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.