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

Cache object: 16c275b14815efd63a3bee123a278051


[ 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.