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

Cache object: 40587fbe77d48e2ae3260ebf84a4c975


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