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/ddp_pcb.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) 2004-2009 Robert N. M. Watson
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * Copyright (c) 1990, 1994 Regents of The University of Michigan.
   27  * All Rights Reserved.
   28  *
   29  * Permission to use, copy, modify, and distribute this software and
   30  * its documentation for any purpose and without fee is hereby granted,
   31  * provided that the above copyright notice appears in all copies and
   32  * that both that copyright notice and this permission notice appear
   33  * in supporting documentation, and that the name of The University
   34  * of Michigan not be used in advertising or publicity pertaining to
   35  * distribution of the software without specific, written prior
   36  * permission. This software is supplied as is without expressed or
   37  * implied warranties of any kind.
   38  *
   39  * This product includes software developed by the University of
   40  * California, Berkeley and its contributors.
   41  *
   42  *      Research Systems Unix Group
   43  *      The University of Michigan
   44  *      c/o Wesley Craig
   45  *      535 W. William Street
   46  *      Ann Arbor, Michigan
   47  *      +1-313-764-2278
   48  *      netatalk@umich.edu
   49  * $FreeBSD$
   50  */
   51 
   52 #include <sys/param.h>
   53 #include <sys/systm.h>
   54 #include <sys/malloc.h>
   55 #include <sys/mbuf.h>
   56 #include <sys/priv.h>
   57 #include <sys/socket.h>
   58 #include <sys/socketvar.h>
   59 #include <sys/protosw.h>
   60 #include <net/if.h>
   61 #include <net/route.h>
   62 #include <net/netisr.h>
   63 
   64 #include <netatalk/at.h>
   65 #include <netatalk/at_var.h>
   66 #include <netatalk/ddp_var.h>
   67 #include <netatalk/ddp_pcb.h>
   68 #include <netatalk/at_extern.h>
   69 
   70 struct mtx               ddp_list_mtx;
   71 static struct ddpcb     *ddp_ports[ATPORT_LAST];
   72 struct ddpcb            *ddpcb_list = NULL;
   73 
   74 void
   75 at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr)
   76 {
   77 
   78         /*
   79          * Prevent modification of ddp during copy of addr.
   80          */
   81         DDP_LOCK_ASSERT(ddp);
   82         *addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT);
   83 }
   84 
   85 int 
   86 at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
   87 {
   88         struct sockaddr_at lsat, *sat;
   89         struct at_ifaddr *aa;
   90         struct ddpcb *ddpp;
   91 
   92         /*
   93          * We read and write both the ddp passed in, and also ddp_ports.
   94          */
   95         DDP_LIST_XLOCK_ASSERT();
   96         DDP_LOCK_ASSERT(ddp);
   97 
   98         /*
   99          * Shouldn't be bound.
  100          */
  101         if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT)
  102                 return (EINVAL);
  103 
  104         /*
  105          * Validate passed address.
  106          */
  107         aa = NULL;
  108         if (addr != NULL) {
  109                 sat = (struct sockaddr_at *)addr;
  110                 if (sat->sat_family != AF_APPLETALK)
  111                         return (EAFNOSUPPORT);
  112 
  113                 if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
  114                     sat->sat_addr.s_net != ATADDR_ANYNET) {
  115                         AT_IFADDR_RLOCK();
  116                         TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) {
  117                                 if ((sat->sat_addr.s_net ==
  118                                     AA_SAT(aa)->sat_addr.s_net) &&
  119                                     (sat->sat_addr.s_node ==
  120                                     AA_SAT(aa)->sat_addr.s_node))
  121                                         break;
  122                         }
  123                         AT_IFADDR_RUNLOCK();
  124                         if (aa == NULL)
  125                                 return (EADDRNOTAVAIL);
  126                 }
  127 
  128                 if (sat->sat_port != ATADDR_ANYPORT) {
  129                         if (sat->sat_port < ATPORT_FIRST ||
  130                             sat->sat_port >= ATPORT_LAST)
  131                                 return (EINVAL);
  132                         if (sat->sat_port < ATPORT_RESERVED &&
  133                             priv_check(td, PRIV_NETATALK_RESERVEDPORT))
  134                                 return (EACCES);
  135                 }
  136         } else {
  137                 bzero((caddr_t)&lsat, sizeof(struct sockaddr_at));
  138                 lsat.sat_len = sizeof(struct sockaddr_at);
  139                 lsat.sat_addr.s_node = ATADDR_ANYNODE;
  140                 lsat.sat_addr.s_net = ATADDR_ANYNET;
  141                 lsat.sat_family = AF_APPLETALK;
  142                 sat = &lsat;
  143         }
  144 
  145         if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
  146             sat->sat_addr.s_net == ATADDR_ANYNET) {
  147                 AT_IFADDR_RLOCK();
  148                 if (TAILQ_EMPTY(&at_ifaddrhead)) {
  149                         AT_IFADDR_RUNLOCK();
  150                         return (EADDRNOTAVAIL);
  151                 }
  152                 sat->sat_addr = AA_SAT(TAILQ_FIRST(&at_ifaddrhead))->sat_addr;
  153                 AT_IFADDR_RUNLOCK();
  154         }
  155         ddp->ddp_lsat = *sat;
  156 
  157         /*
  158          * Choose port.
  159          */
  160         if (sat->sat_port == ATADDR_ANYPORT) {
  161                 for (sat->sat_port = ATPORT_RESERVED;
  162                     sat->sat_port < ATPORT_LAST; sat->sat_port++) {
  163                         if (ddp_ports[sat->sat_port - 1] == NULL)
  164                                 break;
  165                 }
  166                 if (sat->sat_port == ATPORT_LAST)
  167                         return (EADDRNOTAVAIL);
  168                 ddp->ddp_lsat.sat_port = sat->sat_port;
  169                 ddp_ports[sat->sat_port - 1] = ddp;
  170         } else {
  171                 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp;
  172                     ddpp = ddpp->ddp_pnext) {
  173                         if (ddpp->ddp_lsat.sat_addr.s_net ==
  174                             sat->sat_addr.s_net &&
  175                             ddpp->ddp_lsat.sat_addr.s_node ==
  176                             sat->sat_addr.s_node)
  177                                 break;
  178                 }
  179                 if (ddpp != NULL)
  180                         return (EADDRINUSE);
  181                 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1];
  182                 ddp_ports[sat->sat_port - 1] = ddp;
  183                 if (ddp->ddp_pnext != NULL)
  184                         ddp->ddp_pnext->ddp_pprev = ddp;
  185         }
  186 
  187         return (0);
  188 }
  189 
  190 int
  191 at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
  192 {
  193         struct sockaddr_at      *sat = (struct sockaddr_at *)addr;
  194         struct route    *ro;
  195         struct at_ifaddr        *aa = NULL;
  196         struct ifnet    *ifp;
  197         u_short         hintnet = 0, net;
  198 
  199         DDP_LIST_XLOCK_ASSERT();
  200         DDP_LOCK_ASSERT(ddp);
  201 
  202         if (sat->sat_family != AF_APPLETALK)
  203                 return (EAFNOSUPPORT);
  204 
  205         /*
  206          * Under phase 2, network 0 means "the network".  We take "the
  207          * network" to mean the network the control block is bound to.  If
  208          * the control block is not bound, there is an error.
  209          */
  210         if (sat->sat_addr.s_net == ATADDR_ANYNET &&
  211             sat->sat_addr.s_node != ATADDR_ANYNODE) {
  212                 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT)
  213                         return (EADDRNOTAVAIL);
  214                 hintnet = ddp->ddp_lsat.sat_addr.s_net;
  215         }
  216 
  217         ro = &ddp->ddp_route;
  218         /*
  219          * If we've got an old route for this pcb, check that it is valid.
  220          * If we've changed our address, we may have an old "good looking"
  221          * route here.  Attempt to detect it.
  222          */
  223         if (ro->ro_rt) {
  224                 if (hintnet)
  225                         net = hintnet;
  226                 else
  227                         net = sat->sat_addr.s_net;
  228                 aa = NULL;
  229                 AT_IFADDR_RLOCK();
  230                 if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
  231                         TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) {
  232                                 if (aa->aa_ifp == ifp &&
  233                                     ntohs(net) >= ntohs(aa->aa_firstnet) &&
  234                                     ntohs(net) <= ntohs(aa->aa_lastnet))
  235                                         break;
  236                         }
  237                 }
  238                 if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net !=
  239                     (hintnet ? hintnet : sat->sat_addr.s_net) ||
  240                     satosat(&ro->ro_dst)->sat_addr.s_node !=
  241                     sat->sat_addr.s_node)) {
  242                         RTFREE(ro->ro_rt);
  243                         ro->ro_rt = NULL;
  244                 }
  245                 AT_IFADDR_RUNLOCK();
  246         }
  247 
  248         /*
  249          * If we've got no route for this interface, try to find one.
  250          */
  251         if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
  252                 ro->ro_dst.sa_len = sizeof(struct sockaddr_at);
  253                 ro->ro_dst.sa_family = AF_APPLETALK;
  254                 if (hintnet)
  255                         satosat(&ro->ro_dst)->sat_addr.s_net = hintnet;
  256                 else
  257                         satosat(&ro->ro_dst)->sat_addr.s_net =
  258                             sat->sat_addr.s_net;
  259                 satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node;
  260                 rtalloc(ro);
  261         }
  262 
  263         /*
  264          * Make sure any route that we have has a valid interface.
  265          */
  266         aa = NULL;
  267         if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
  268                 AT_IFADDR_RLOCK();
  269                 TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) {
  270                         if (aa->aa_ifp == ifp)
  271                                 break;
  272                 }
  273                 AT_IFADDR_RUNLOCK();
  274         }
  275         if (aa == NULL)
  276                 return (ENETUNREACH);
  277 
  278         ddp->ddp_fsat = *sat;
  279         if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT)
  280                 return (at_pcbsetaddr(ddp, NULL, td));
  281         return (0);
  282 }
  283 
  284 void 
  285 at_pcbdisconnect(struct ddpcb   *ddp)
  286 {
  287 
  288         DDP_LOCK_ASSERT(ddp);
  289 
  290         ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
  291         ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
  292         ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
  293 }
  294 
  295 int
  296 at_pcballoc(struct socket *so)
  297 {
  298         struct ddpcb *ddp;
  299 
  300         DDP_LIST_XLOCK_ASSERT();
  301 
  302         ddp = malloc(sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO);
  303         if (ddp == NULL)
  304                 return (ENOBUFS);
  305         DDP_LOCK_INIT(ddp);
  306         ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
  307 
  308         ddp->ddp_socket = so;
  309         so->so_pcb = (caddr_t)ddp;
  310 
  311         ddp->ddp_next = ddpcb_list;
  312         ddp->ddp_prev = NULL;
  313         ddp->ddp_pprev = NULL;
  314         ddp->ddp_pnext = NULL;
  315         if (ddpcb_list != NULL)
  316                 ddpcb_list->ddp_prev = ddp;
  317         ddpcb_list = ddp;
  318         return(0);
  319 }
  320 
  321 void
  322 at_pcbdetach(struct socket *so, struct ddpcb *ddp)
  323 {
  324 
  325         /*
  326          * We modify ddp, ddp_ports, and the global list.
  327          */
  328         DDP_LIST_XLOCK_ASSERT();
  329         DDP_LOCK_ASSERT(ddp);
  330         KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL"));
  331 
  332         so->so_pcb = NULL;
  333 
  334         /* Remove ddp from ddp_ports list. */
  335         if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
  336             ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) {
  337                 if (ddp->ddp_pprev != NULL)
  338                         ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
  339                 else
  340                         ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext;
  341                 if (ddp->ddp_pnext != NULL)
  342                         ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
  343         }
  344 
  345         if (ddp->ddp_route.ro_rt)
  346                 RTFREE(ddp->ddp_route.ro_rt);
  347 
  348         if (ddp->ddp_prev)
  349                 ddp->ddp_prev->ddp_next = ddp->ddp_next;
  350         else
  351                 ddpcb_list = ddp->ddp_next;
  352         if (ddp->ddp_next)
  353                 ddp->ddp_next->ddp_prev = ddp->ddp_prev;
  354         DDP_UNLOCK(ddp);
  355         DDP_LOCK_DESTROY(ddp);
  356         free(ddp, M_PCB);
  357 }
  358 
  359 /*
  360  * For the moment, this just find the pcb with the correct local address.  In
  361  * the future, this will actually do some real searching, so we can use the
  362  * sender's address to do de-multiplexing on a single port to many sockets
  363  * (pcbs).
  364  */
  365 struct ddpcb *
  366 ddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
  367     struct at_ifaddr *aa)
  368 {
  369         struct ddpcb *ddp;
  370 
  371         DDP_LIST_SLOCK_ASSERT();
  372 
  373         /*
  374          * Check for bad ports.
  375          */
  376         if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST)
  377                 return (NULL);
  378 
  379         /*
  380          * Make sure the local address matches the sent address.  What about
  381          * the interface?
  382          */
  383         for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) {
  384                 DDP_LOCK(ddp);
  385                 /* XXX should we handle 0.YY? */
  386                 /* XXXX.YY to socket on destination interface */
  387                 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
  388                     to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
  389                         DDP_UNLOCK(ddp);
  390                         break;
  391                 }
  392 
  393                 /* 0.255 to socket on receiving interface */
  394                 if (to->sat_addr.s_node == ATADDR_BCAST &&
  395                     (to->sat_addr.s_net == 0 ||
  396                     to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
  397                     ddp->ddp_lsat.sat_addr.s_net ==
  398                     AA_SAT(aa)->sat_addr.s_net) {
  399                         DDP_UNLOCK(ddp);
  400                         break;
  401                 }
  402 
  403                 /* XXXX.0 to socket on destination interface */
  404                 if (to->sat_addr.s_net == aa->aa_firstnet &&
  405                     to->sat_addr.s_node == 0 &&
  406                     ntohs(ddp->ddp_lsat.sat_addr.s_net) >=
  407                     ntohs(aa->aa_firstnet) &&
  408                     ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
  409                     ntohs(aa->aa_lastnet)) {
  410                         DDP_UNLOCK(ddp);
  411                         break;
  412                 }
  413                 DDP_UNLOCK(ddp);
  414         }
  415         return (ddp);
  416 }

Cache object: 42af84865c1598b86799979ead682b3d


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