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

Cache object: 0f7c0b000b861f4a407abe1a354434f5


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