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

Cache object: 49814bfb88b43af779dd89a38546e5b0


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