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

Cache object: 9d4163010459aab302613c96f9d83eb5


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