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

Cache object: b313f81b0e33b74c980f34c71b54fab8


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