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-2005 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         if (addr != NULL) {
  108                 sat = (struct sockaddr_at *)addr;
  109                 if (sat->sat_family != AF_APPLETALK)
  110                         return (EAFNOSUPPORT);
  111 
  112                 if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
  113                     sat->sat_addr.s_net != ATADDR_ANYNET) {
  114                         for (aa = at_ifaddr_list; aa != NULL;
  115                             aa = aa->aa_next) {
  116                                 if ((sat->sat_addr.s_net ==
  117                                     AA_SAT(aa)->sat_addr.s_net) &&
  118                                     (sat->sat_addr.s_node ==
  119                                     AA_SAT(aa)->sat_addr.s_node))
  120                                         break;
  121                         }
  122                         if (aa == NULL)
  123                                 return (EADDRNOTAVAIL);
  124                 }
  125 
  126                 if (sat->sat_port != ATADDR_ANYPORT) {
  127                         if (sat->sat_port < ATPORT_FIRST ||
  128                             sat->sat_port >= ATPORT_LAST)
  129                                 return (EINVAL);
  130                         if (sat->sat_port < ATPORT_RESERVED &&
  131                             priv_check(td, PRIV_NETATALK_RESERVEDPORT))
  132                                 return (EACCES);
  133                 }
  134         } else {
  135                 bzero((caddr_t)&lsat, sizeof(struct sockaddr_at));
  136                 lsat.sat_len = sizeof(struct sockaddr_at);
  137                 lsat.sat_addr.s_node = ATADDR_ANYNODE;
  138                 lsat.sat_addr.s_net = ATADDR_ANYNET;
  139                 lsat.sat_family = AF_APPLETALK;
  140                 sat = &lsat;
  141         }
  142 
  143         if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
  144             sat->sat_addr.s_net == ATADDR_ANYNET) {
  145                 if (at_ifaddr_list == NULL)
  146                         return (EADDRNOTAVAIL);
  147                 sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr;
  148         }
  149         ddp->ddp_lsat = *sat;
  150 
  151         /*
  152          * Choose port.
  153          */
  154         if (sat->sat_port == ATADDR_ANYPORT) {
  155                 for (sat->sat_port = ATPORT_RESERVED;
  156                     sat->sat_port < ATPORT_LAST; sat->sat_port++) {
  157                         if (ddp_ports[sat->sat_port - 1] == NULL)
  158                                 break;
  159                 }
  160                 if (sat->sat_port == ATPORT_LAST)
  161                         return (EADDRNOTAVAIL);
  162                 ddp->ddp_lsat.sat_port = sat->sat_port;
  163                 ddp_ports[sat->sat_port - 1] = ddp;
  164         } else {
  165                 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp;
  166                     ddpp = ddpp->ddp_pnext) {
  167                         if (ddpp->ddp_lsat.sat_addr.s_net ==
  168                             sat->sat_addr.s_net &&
  169                             ddpp->ddp_lsat.sat_addr.s_node ==
  170                             sat->sat_addr.s_node)
  171                                 break;
  172                 }
  173                 if (ddpp != NULL)
  174                         return (EADDRINUSE);
  175                 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1];
  176                 ddp_ports[sat->sat_port - 1] = ddp;
  177                 if (ddp->ddp_pnext != NULL)
  178                         ddp->ddp_pnext->ddp_pprev = ddp;
  179         }
  180 
  181         return (0);
  182 }
  183 
  184 int
  185 at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
  186 {
  187         struct sockaddr_at      *sat = (struct sockaddr_at *)addr;
  188         struct route    *ro;
  189         struct at_ifaddr        *aa = NULL;
  190         struct ifnet    *ifp;
  191         u_short         hintnet = 0, net;
  192 
  193         DDP_LIST_XLOCK_ASSERT();
  194         DDP_LOCK_ASSERT(ddp);
  195 
  196         if (sat->sat_family != AF_APPLETALK)
  197                 return (EAFNOSUPPORT);
  198 
  199         /*
  200          * Under phase 2, network 0 means "the network".  We take "the
  201          * network" to mean the network the control block is bound to.  If
  202          * the control block is not bound, there is an error.
  203          */
  204         if (sat->sat_addr.s_net == ATADDR_ANYNET &&
  205             sat->sat_addr.s_node != ATADDR_ANYNODE) {
  206                 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT)
  207                         return (EADDRNOTAVAIL);
  208                 hintnet = ddp->ddp_lsat.sat_addr.s_net;
  209         }
  210 
  211         ro = &ddp->ddp_route;
  212         /*
  213          * If we've got an old route for this pcb, check that it is valid.
  214          * If we've changed our address, we may have an old "good looking"
  215          * route here.  Attempt to detect it.
  216          */
  217         if (ro->ro_rt) {
  218                 if (hintnet)
  219                         net = hintnet;
  220                 else
  221                         net = sat->sat_addr.s_net;
  222                 aa = NULL;
  223                 if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
  224                         for (aa = at_ifaddr_list; aa != NULL;
  225                             aa = aa->aa_next) {
  226                                 if (aa->aa_ifp == ifp &&
  227                                     ntohs(net) >= ntohs(aa->aa_firstnet) &&
  228                                     ntohs(net) <= ntohs(aa->aa_lastnet))
  229                                         break;
  230                         }
  231                 }
  232                 if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net !=
  233                     (hintnet ? hintnet : sat->sat_addr.s_net) ||
  234                     satosat(&ro->ro_dst)->sat_addr.s_node !=
  235                     sat->sat_addr.s_node)) {
  236                         RTFREE(ro->ro_rt);
  237                         ro->ro_rt = NULL;
  238                 }
  239         }
  240 
  241         /*
  242          * If we've got no route for this interface, try to find one.
  243          */
  244         if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
  245                 ro->ro_dst.sa_len = sizeof(struct sockaddr_at);
  246                 ro->ro_dst.sa_family = AF_APPLETALK;
  247                 if (hintnet)
  248                         satosat(&ro->ro_dst)->sat_addr.s_net = hintnet;
  249                 else
  250                         satosat(&ro->ro_dst)->sat_addr.s_net =
  251                             sat->sat_addr.s_net;
  252                 satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node;
  253                 rtalloc(ro);
  254         }
  255 
  256         /*
  257          * Make sure any route that we have has a valid interface.
  258          */
  259         aa = NULL;
  260         if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
  261                 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
  262                         if (aa->aa_ifp == ifp)
  263                                 break;
  264                 }
  265         }
  266         if (aa == NULL)
  267                 return (ENETUNREACH);
  268 
  269         ddp->ddp_fsat = *sat;
  270         if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT)
  271                 return (at_pcbsetaddr(ddp, NULL, td));
  272         return (0);
  273 }
  274 
  275 void 
  276 at_pcbdisconnect(struct ddpcb   *ddp)
  277 {
  278 
  279         DDP_LOCK_ASSERT(ddp);
  280 
  281         ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
  282         ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
  283         ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
  284 }
  285 
  286 int
  287 at_pcballoc(struct socket *so)
  288 {
  289         struct ddpcb *ddp;
  290 
  291         DDP_LIST_XLOCK_ASSERT();
  292 
  293         MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO);
  294         if (ddp == NULL)
  295                 return (ENOBUFS);
  296         DDP_LOCK_INIT(ddp);
  297         ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
  298 
  299         ddp->ddp_socket = so;
  300         so->so_pcb = (caddr_t)ddp;
  301 
  302         ddp->ddp_next = ddpcb_list;
  303         ddp->ddp_prev = NULL;
  304         ddp->ddp_pprev = NULL;
  305         ddp->ddp_pnext = NULL;
  306         if (ddpcb_list != NULL)
  307                 ddpcb_list->ddp_prev = ddp;
  308         ddpcb_list = ddp;
  309         return(0);
  310 }
  311 
  312 void
  313 at_pcbdetach(struct socket *so, struct ddpcb *ddp)
  314 {
  315 
  316         /*
  317          * We modify ddp, ddp_ports, and the global list.
  318          */
  319         DDP_LIST_XLOCK_ASSERT();
  320         DDP_LOCK_ASSERT(ddp);
  321         KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL"));
  322 
  323         so->so_pcb = NULL;
  324 
  325         /* Remove ddp from ddp_ports list. */
  326         if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
  327             ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) {
  328                 if (ddp->ddp_pprev != NULL)
  329                         ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
  330                 else
  331                         ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext;
  332                 if (ddp->ddp_pnext != NULL)
  333                         ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
  334         }
  335 
  336         if (ddp->ddp_route.ro_rt)
  337                 RTFREE(ddp->ddp_route.ro_rt);
  338 
  339         if (ddp->ddp_prev)
  340                 ddp->ddp_prev->ddp_next = ddp->ddp_next;
  341         else
  342                 ddpcb_list = ddp->ddp_next;
  343         if (ddp->ddp_next)
  344                 ddp->ddp_next->ddp_prev = ddp->ddp_prev;
  345         DDP_UNLOCK(ddp);
  346         DDP_LOCK_DESTROY(ddp);
  347         FREE(ddp, M_PCB);
  348 }
  349 
  350 /*
  351  * For the moment, this just find the pcb with the correct local address.  In
  352  * the future, this will actually do some real searching, so we can use the
  353  * sender's address to do de-multiplexing on a single port to many sockets
  354  * (pcbs).
  355  */
  356 struct ddpcb *
  357 ddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
  358     struct at_ifaddr *aa)
  359 {
  360         struct ddpcb *ddp;
  361 
  362         DDP_LIST_SLOCK_ASSERT();
  363 
  364         /*
  365          * Check for bad ports.
  366          */
  367         if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST)
  368                 return (NULL);
  369 
  370         /*
  371          * Make sure the local address matches the sent address.  What about
  372          * the interface?
  373          */
  374         for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) {
  375                 DDP_LOCK(ddp);
  376                 /* XXX should we handle 0.YY? */
  377                 /* XXXX.YY to socket on destination interface */
  378                 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
  379                     to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
  380                         DDP_UNLOCK(ddp);
  381                         break;
  382                 }
  383 
  384                 /* 0.255 to socket on receiving interface */
  385                 if (to->sat_addr.s_node == ATADDR_BCAST &&
  386                     (to->sat_addr.s_net == 0 ||
  387                     to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
  388                     ddp->ddp_lsat.sat_addr.s_net ==
  389                     AA_SAT(aa)->sat_addr.s_net) {
  390                         DDP_UNLOCK(ddp);
  391                         break;
  392                 }
  393 
  394                 /* XXXX.0 to socket on destination interface */
  395                 if (to->sat_addr.s_net == aa->aa_firstnet &&
  396                     to->sat_addr.s_node == 0 &&
  397                     ntohs(ddp->ddp_lsat.sat_addr.s_net) >=
  398                     ntohs(aa->aa_firstnet) &&
  399                     ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
  400                     ntohs(aa->aa_lastnet)) {
  401                         DDP_UNLOCK(ddp);
  402                         break;
  403                 }
  404                 DDP_UNLOCK(ddp);
  405         }
  406         return (ddp);
  407 }

Cache object: 8c2188f90c4a1df6d795bdd83e3bc3d5


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