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_usrreq.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: ddp_usrreq.c,v 1.20 2006/11/16 01:33:44 christos Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1990,1991 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: ddp_usrreq.c,v 1.20 2006/11/16 01:33:44 christos Exp $");
   31 
   32 #include "opt_mbuftrace.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/errno.h>
   36 #include <sys/systm.h>
   37 #include <sys/proc.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/ioctl.h>
   40 #include <sys/socket.h>
   41 #include <sys/socketvar.h>
   42 #include <sys/protosw.h>
   43 #include <sys/kauth.h>
   44 #include <net/if.h>
   45 #include <net/route.h>
   46 #include <net/if_ether.h>
   47 #include <netinet/in.h>
   48 
   49 #include <netatalk/at.h>
   50 #include <netatalk/at_var.h>
   51 #include <netatalk/ddp_var.h>
   52 #include <netatalk/aarp.h>
   53 #include <netatalk/at_extern.h>
   54 
   55 static void at_pcbdisconnect __P((struct ddpcb *));
   56 static void at_sockaddr __P((struct ddpcb *, struct mbuf *));
   57 static int at_pcbsetaddr __P((struct ddpcb *, struct mbuf *, struct lwp *));
   58 static int at_pcbconnect __P((struct ddpcb *, struct mbuf *, struct lwp *));
   59 static void at_pcbdetach __P((struct socket *, struct ddpcb *));
   60 static int at_pcballoc __P((struct socket *));
   61 
   62 struct ifqueue atintrq1, atintrq2;
   63 struct ddpcb   *ddp_ports[ATPORT_LAST];
   64 struct ddpcb   *ddpcb = NULL;
   65 struct ddpstat  ddpstat;
   66 struct at_ifaddrhead at_ifaddr;         /* Here as inited in this file */
   67 u_long ddp_sendspace = DDP_MAXSZ;       /* Max ddp size + 1 (ddp_type) */
   68 u_long ddp_recvspace = 25 * (587 + sizeof(struct sockaddr_at));
   69 
   70 #ifdef MBUFTRACE
   71 struct mowner atalk_rx_mowner = MOWNER_INIT("atalk", "rx");
   72 struct mowner atalk_tx_mowner = MOWNER_INIT("atalk", "tx");
   73 #endif
   74 
   75 /* ARGSUSED */
   76 int
   77 ddp_usrreq(so, req, m, addr, rights, l)
   78         struct socket  *so;
   79         int             req;
   80         struct mbuf    *m;
   81         struct mbuf    *addr;
   82         struct mbuf    *rights;
   83         struct lwp *l;
   84 {
   85         struct ddpcb   *ddp;
   86         int             error = 0;
   87 
   88         ddp = sotoddpcb(so);
   89 
   90         if (req == PRU_CONTROL) {
   91                 return (at_control((long) m, (caddr_t) addr,
   92                     (struct ifnet *) rights, l));
   93         }
   94         if (req == PRU_PURGEIF) {
   95                 at_purgeif((struct ifnet *) rights);
   96                 return (0);
   97         }
   98         if (rights && rights->m_len) {
   99                 error = EINVAL;
  100                 goto release;
  101         }
  102         if (ddp == NULL && req != PRU_ATTACH) {
  103                 error = EINVAL;
  104                 goto release;
  105         }
  106         switch (req) {
  107         case PRU_ATTACH:
  108                 if (ddp != NULL) {
  109                         error = EINVAL;
  110                         break;
  111                 }
  112                 if ((error = at_pcballoc(so)) != 0) {
  113                         break;
  114                 }
  115                 error = soreserve(so, ddp_sendspace, ddp_recvspace);
  116                 break;
  117 
  118         case PRU_DETACH:
  119                 at_pcbdetach(so, ddp);
  120                 break;
  121 
  122         case PRU_BIND:
  123                 error = at_pcbsetaddr(ddp, addr, l);
  124                 break;
  125 
  126         case PRU_SOCKADDR:
  127                 at_sockaddr(ddp, addr);
  128                 break;
  129 
  130         case PRU_CONNECT:
  131                 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
  132                         error = EISCONN;
  133                         break;
  134                 }
  135                 error = at_pcbconnect(ddp, addr, l);
  136                 if (error == 0)
  137                         soisconnected(so);
  138                 break;
  139 
  140         case PRU_DISCONNECT:
  141                 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) {
  142                         error = ENOTCONN;
  143                         break;
  144                 }
  145                 at_pcbdisconnect(ddp);
  146                 soisdisconnected(so);
  147                 break;
  148 
  149         case PRU_SHUTDOWN:
  150                 socantsendmore(so);
  151                 break;
  152 
  153         case PRU_SEND:{
  154                         int s = 0;
  155 
  156                         if (addr) {
  157                                 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
  158                                         error = EISCONN;
  159                                         break;
  160                                 }
  161                                 s = splnet();
  162                                 error = at_pcbconnect(ddp, addr, l);
  163                                 if (error) {
  164                                         splx(s);
  165                                         break;
  166                                 }
  167                         } else {
  168                                 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) {
  169                                         error = ENOTCONN;
  170                                         break;
  171                                 }
  172                         }
  173 
  174                         error = ddp_output(m, ddp);
  175                         m = NULL;
  176                         if (addr) {
  177                                 at_pcbdisconnect(ddp);
  178                                 splx(s);
  179                         }
  180                 }
  181                 break;
  182 
  183         case PRU_ABORT:
  184                 soisdisconnected(so);
  185                 at_pcbdetach(so, ddp);
  186                 break;
  187 
  188         case PRU_LISTEN:
  189         case PRU_CONNECT2:
  190         case PRU_ACCEPT:
  191         case PRU_SENDOOB:
  192         case PRU_FASTTIMO:
  193         case PRU_SLOWTIMO:
  194         case PRU_PROTORCV:
  195         case PRU_PROTOSEND:
  196                 error = EOPNOTSUPP;
  197                 break;
  198 
  199         case PRU_RCVD:
  200         case PRU_RCVOOB:
  201                 /*
  202                  * Don't mfree. Good architecture...
  203                  */
  204                 return (EOPNOTSUPP);
  205 
  206         case PRU_SENSE:
  207                 /*
  208                  * 1. Don't return block size.
  209                  * 2. Don't mfree.
  210                  */
  211                 return (0);
  212 
  213         default:
  214                 error = EOPNOTSUPP;
  215         }
  216 
  217 release:
  218         if (m != NULL) {
  219                 m_freem(m);
  220         }
  221         return (error);
  222 }
  223 
  224 static void
  225 at_sockaddr(ddp, addr)
  226         struct ddpcb   *ddp;
  227         struct mbuf    *addr;
  228 {
  229         struct sockaddr_at *sat;
  230 
  231         addr->m_len = sizeof(struct sockaddr_at);
  232         sat = mtod(addr, struct sockaddr_at *);
  233         *sat = ddp->ddp_lsat;
  234 }
  235 
  236 static int
  237 at_pcbsetaddr(ddp, addr, l)
  238         struct ddpcb   *ddp;
  239         struct mbuf    *addr;
  240         struct lwp      *l;
  241 {
  242         struct sockaddr_at lsat, *sat;
  243         struct at_ifaddr *aa;
  244         struct ddpcb   *ddpp;
  245 
  246         if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) { /* shouldn't be bound */
  247                 return (EINVAL);
  248         }
  249         if (addr != 0) {        /* validate passed address */
  250                 sat = mtod(addr, struct sockaddr_at *);
  251                 if (addr->m_len != sizeof(*sat))
  252                         return (EINVAL);
  253 
  254                 if (sat->sat_family != AF_APPLETALK)
  255                         return (EAFNOSUPPORT);
  256 
  257                 if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
  258                     sat->sat_addr.s_net != ATADDR_ANYNET) {
  259                         for (aa = at_ifaddr.tqh_first; aa;
  260                             aa = aa->aa_list.tqe_next) {
  261                                 if ((sat->sat_addr.s_net ==
  262                                     AA_SAT(aa)->sat_addr.s_net) &&
  263                                     (sat->sat_addr.s_node ==
  264                                     AA_SAT(aa)->sat_addr.s_node))
  265                                         break;
  266                         }
  267                         if (!aa)
  268                                 return (EADDRNOTAVAIL);
  269                 }
  270                 if (sat->sat_port != ATADDR_ANYPORT) {
  271                         if (sat->sat_port < ATPORT_FIRST ||
  272                             sat->sat_port >= ATPORT_LAST)
  273                                 return (EINVAL);
  274 
  275                         if (sat->sat_port < ATPORT_RESERVED && l &&
  276                             kauth_authorize_generic(l->l_cred,
  277                             KAUTH_GENERIC_ISSUSER,
  278                             &l->l_acflag))
  279                                 return (EACCES);
  280                 }
  281         } else {
  282                 bzero((caddr_t) & lsat, sizeof(struct sockaddr_at));
  283                 lsat.sat_len = sizeof(struct sockaddr_at);
  284                 lsat.sat_addr.s_node = ATADDR_ANYNODE;
  285                 lsat.sat_addr.s_net = ATADDR_ANYNET;
  286                 lsat.sat_family = AF_APPLETALK;
  287                 sat = &lsat;
  288         }
  289 
  290         if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
  291             sat->sat_addr.s_net == ATADDR_ANYNET) {
  292                 if (at_ifaddr.tqh_first == NULL)
  293                         return (EADDRNOTAVAIL);
  294                 sat->sat_addr = AA_SAT(at_ifaddr.tqh_first)->sat_addr;
  295         }
  296         ddp->ddp_lsat = *sat;
  297 
  298         /*
  299          * Choose port.
  300          */
  301         if (sat->sat_port == ATADDR_ANYPORT) {
  302                 for (sat->sat_port = ATPORT_RESERVED;
  303                      sat->sat_port < ATPORT_LAST; sat->sat_port++) {
  304                         if (ddp_ports[sat->sat_port - 1] == 0)
  305                                 break;
  306                 }
  307                 if (sat->sat_port == ATPORT_LAST) {
  308                         return (EADDRNOTAVAIL);
  309                 }
  310                 ddp->ddp_lsat.sat_port = sat->sat_port;
  311                 ddp_ports[sat->sat_port - 1] = ddp;
  312         } else {
  313                 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp;
  314                      ddpp = ddpp->ddp_pnext) {
  315                         if (ddpp->ddp_lsat.sat_addr.s_net ==
  316                             sat->sat_addr.s_net &&
  317                             ddpp->ddp_lsat.sat_addr.s_node ==
  318                             sat->sat_addr.s_node)
  319                                 break;
  320                 }
  321                 if (ddpp != NULL)
  322                         return (EADDRINUSE);
  323 
  324                 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1];
  325                 ddp_ports[sat->sat_port - 1] = ddp;
  326                 if (ddp->ddp_pnext)
  327                         ddp->ddp_pnext->ddp_pprev = ddp;
  328         }
  329 
  330         return 0;
  331 }
  332 
  333 static int
  334 at_pcbconnect(ddp, addr, l)
  335         struct ddpcb   *ddp;
  336         struct mbuf    *addr;
  337         struct lwp     *l;
  338 {
  339         struct sockaddr_at *sat = mtod(addr, struct sockaddr_at *);
  340         struct route   *ro;
  341         struct at_ifaddr *aa = 0;
  342         struct ifnet   *ifp;
  343         u_short         hintnet = 0, net;
  344 
  345         if (addr->m_len != sizeof(*sat))
  346                 return (EINVAL);
  347         if (sat->sat_family != AF_APPLETALK) {
  348                 return (EAFNOSUPPORT);
  349         }
  350         /*
  351          * Under phase 2, network 0 means "the network".  We take "the
  352          * network" to mean the network the control block is bound to.
  353          * If the control block is not bound, there is an error.
  354          */
  355         if (sat->sat_addr.s_net == ATADDR_ANYNET
  356             && sat->sat_addr.s_node != ATADDR_ANYNODE) {
  357                 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
  358                         return (EADDRNOTAVAIL);
  359                 }
  360                 hintnet = ddp->ddp_lsat.sat_addr.s_net;
  361         }
  362         ro = &ddp->ddp_route;
  363         /*
  364          * If we've got an old route for this pcb, check that it is valid.
  365          * If we've changed our address, we may have an old "good looking"
  366          * route here.  Attempt to detect it.
  367          */
  368         if (ro->ro_rt) {
  369                 if (hintnet) {
  370                         net = hintnet;
  371                 } else {
  372                         net = sat->sat_addr.s_net;
  373                 }
  374                 aa = 0;
  375                 if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
  376                         for (aa = at_ifaddr.tqh_first; aa;
  377                             aa = aa->aa_list.tqe_next) {
  378                                 if (aa->aa_ifp == ifp &&
  379                                     ntohs(net) >= ntohs(aa->aa_firstnet) &&
  380                                     ntohs(net) <= ntohs(aa->aa_lastnet)) {
  381                                         break;
  382                                 }
  383                         }
  384                 }
  385                 if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net !=
  386                     (hintnet ? hintnet : sat->sat_addr.s_net) ||
  387                     satosat(&ro->ro_dst)->sat_addr.s_node !=
  388                     sat->sat_addr.s_node)) {
  389                         RTFREE(ro->ro_rt);
  390                         ro->ro_rt = (struct rtentry *) 0;
  391                 }
  392         }
  393         /*
  394          * If we've got no route for this interface, try to find one.
  395          */
  396         if (ro->ro_rt == (struct rtentry *) 0 ||
  397             ro->ro_rt->rt_ifp == (struct ifnet *) 0) {
  398                 bzero(&ro->ro_dst, sizeof(struct sockaddr_at));
  399                 ro->ro_dst.sa_len = sizeof(struct sockaddr_at);
  400                 ro->ro_dst.sa_family = AF_APPLETALK;
  401                 if (hintnet) {
  402                         satosat(&ro->ro_dst)->sat_addr.s_net = hintnet;
  403                 } else {
  404                         satosat(&ro->ro_dst)->sat_addr.s_net =
  405                             sat->sat_addr.s_net;
  406                 }
  407                 satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node;
  408                 rtalloc(ro);
  409         }
  410         /*
  411          * Make sure any route that we have has a valid interface.
  412          */
  413         aa = 0;
  414         if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
  415                 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) {
  416                         if (aa->aa_ifp == ifp) {
  417                                 break;
  418                         }
  419                 }
  420         }
  421         if (aa == 0) {
  422                 return (ENETUNREACH);
  423         }
  424         ddp->ddp_fsat = *sat;
  425         if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
  426                 return (at_pcbsetaddr(ddp, (struct mbuf *) 0, l));
  427         }
  428         return (0);
  429 }
  430 
  431 static void
  432 at_pcbdisconnect(ddp)
  433         struct ddpcb   *ddp;
  434 {
  435         ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
  436         ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
  437         ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
  438 }
  439 
  440 static int
  441 at_pcballoc(so)
  442         struct socket  *so;
  443 {
  444         struct ddpcb   *ddp;
  445 
  446         MALLOC(ddp, struct ddpcb *, sizeof(*ddp), M_PCB, M_WAITOK|M_ZERO);
  447         if (!ddp)
  448                 panic("at_pcballoc");
  449         ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
  450 
  451         ddp->ddp_next = ddpcb;
  452         ddp->ddp_prev = NULL;
  453         ddp->ddp_pprev = NULL;
  454         ddp->ddp_pnext = NULL;
  455         if (ddpcb) {
  456                 ddpcb->ddp_prev = ddp;
  457         }
  458         ddpcb = ddp;
  459 
  460         ddp->ddp_socket = so;
  461         so->so_pcb = (caddr_t) ddp;
  462 #ifdef MBUFTRACE
  463         so->so_rcv.sb_mowner = &atalk_rx_mowner;
  464         so->so_snd.sb_mowner = &atalk_tx_mowner;
  465 #endif
  466         return (0);
  467 }
  468 
  469 static void
  470 at_pcbdetach(so, ddp)
  471         struct socket  *so;
  472         struct ddpcb   *ddp;
  473 {
  474         soisdisconnected(so);
  475         so->so_pcb = 0;
  476         sofree(so);
  477 
  478         /* remove ddp from ddp_ports list */
  479         if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
  480             ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) {
  481                 if (ddp->ddp_pprev != NULL) {
  482                         ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
  483                 } else {
  484                         ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext;
  485                 }
  486                 if (ddp->ddp_pnext != NULL) {
  487                         ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
  488                 }
  489         }
  490         if (ddp->ddp_route.ro_rt) {
  491                 rtfree(ddp->ddp_route.ro_rt);
  492         }
  493         if (ddp->ddp_prev) {
  494                 ddp->ddp_prev->ddp_next = ddp->ddp_next;
  495         } else {
  496                 ddpcb = ddp->ddp_next;
  497         }
  498         if (ddp->ddp_next) {
  499                 ddp->ddp_next->ddp_prev = ddp->ddp_prev;
  500         }
  501         free(ddp, M_PCB);
  502 }
  503 
  504 /*
  505  * For the moment, this just find the pcb with the correct local address.
  506  * In the future, this will actually do some real searching, so we can use
  507  * the sender's address to do de-multiplexing on a single port to many
  508  * sockets (pcbs).
  509  */
  510 struct ddpcb   *
  511 ddp_search(
  512     struct sockaddr_at *from,
  513     struct sockaddr_at *to,
  514     struct at_ifaddr *aa)
  515 {
  516         struct ddpcb   *ddp;
  517 
  518         /*
  519          * Check for bad ports.
  520          */
  521         if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) {
  522                 return (NULL);
  523         }
  524         /*
  525          * Make sure the local address matches the sent address.  What about
  526          * the interface?
  527          */
  528         for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) {
  529                 /* XXX should we handle 0.YY? */
  530 
  531                 /* XXXX.YY to socket on destination interface */
  532                 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
  533                     to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
  534                         break;
  535                 }
  536                 /* 0.255 to socket on receiving interface */
  537                 if (to->sat_addr.s_node == ATADDR_BCAST &&
  538                     (to->sat_addr.s_net == 0 ||
  539                     to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
  540                 ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) {
  541                         break;
  542                 }
  543                 /* XXXX.0 to socket on destination interface */
  544                 if (to->sat_addr.s_net == aa->aa_firstnet &&
  545                     to->sat_addr.s_node == 0 &&
  546                     ntohs(ddp->ddp_lsat.sat_addr.s_net) >=
  547                     ntohs(aa->aa_firstnet) &&
  548                     ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
  549                     ntohs(aa->aa_lastnet)) {
  550                         break;
  551                 }
  552         }
  553         return (ddp);
  554 }
  555 
  556 /*
  557  * Initialize all the ddp & appletalk stuff
  558  */
  559 void
  560 ddp_init()
  561 {
  562         TAILQ_INIT(&at_ifaddr);
  563         atintrq1.ifq_maxlen = IFQ_MAXLEN;
  564         atintrq2.ifq_maxlen = IFQ_MAXLEN;
  565 
  566         MOWNER_ATTACH(&atalk_tx_mowner);
  567         MOWNER_ATTACH(&atalk_rx_mowner);
  568 }
  569 
  570 #if 0
  571 static void
  572 ddp_clean()
  573 {
  574         struct ddpcb   *ddp;
  575 
  576         for (ddp = ddpcb; ddp; ddp = ddp->ddp_next)
  577                 at_pcbdetach(ddp->ddp_socket, ddp);
  578 }
  579 #endif

Cache object: 7f073b30ce73289922827e70901c9c5d


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