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/netgraph/ng_socket.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  * ng_socket.c
    3  */
    4 
    5 /*-
    6  * Copyright (c) 1996-1999 Whistle Communications, Inc.
    7  * All rights reserved.
    8  *
    9  * Subject to the following obligations and disclaimer of warranty, use and
   10  * redistribution of this software, in source or object code forms, with or
   11  * without modifications are expressly permitted by Whistle Communications;
   12  * provided, however, that:
   13  * 1. Any and all reproductions of the source or object code must include the
   14  *    copyright notice above and the following disclaimer of warranties; and
   15  * 2. No rights are granted, in any manner or form, to use Whistle
   16  *    Communications, Inc. trademarks, including the mark "WHISTLE
   17  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   18  *    such appears in the above copyright notice or in the software.
   19  *
   20  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   21  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   22  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   23  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   25  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   26  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   27  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   28  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   29  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   30  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   31  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   32  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   35  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   36  * OF SUCH DAMAGE.
   37  *
   38  * Author: Julian Elischer <julian@freebsd.org>
   39  *
   40  * $FreeBSD$
   41  * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $
   42  */
   43 
   44 /*
   45  * Netgraph socket nodes
   46  *
   47  * There are two types of netgraph sockets, control and data.
   48  * Control sockets have a netgraph node, but data sockets are
   49  * parasitic on control sockets, and have no node of their own.
   50  */
   51 
   52 #include <sys/param.h>
   53 #include <sys/domain.h>
   54 #include <sys/hash.h>
   55 #include <sys/kernel.h>
   56 #include <sys/linker.h>
   57 #include <sys/lock.h>
   58 #include <sys/malloc.h>
   59 #include <sys/mbuf.h>
   60 #include <sys/mutex.h>
   61 #include <sys/proc.h>
   62 #include <sys/epoch.h>
   63 #include <sys/priv.h>
   64 #include <sys/protosw.h>
   65 #include <sys/queue.h>
   66 #include <sys/socket.h>
   67 #include <sys/socketvar.h>
   68 #include <sys/syscallsubr.h>
   69 #include <sys/sysctl.h>
   70 
   71 #include <net/vnet.h>
   72 
   73 #include <netgraph/ng_message.h>
   74 #include <netgraph/netgraph.h>
   75 #include <netgraph/ng_socketvar.h>
   76 #include <netgraph/ng_socket.h>
   77 
   78 #ifdef NG_SEPARATE_MALLOC
   79 static MALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info");
   80 static MALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info");
   81 #else
   82 #define M_NETGRAPH_PATH M_NETGRAPH
   83 #define M_NETGRAPH_SOCK M_NETGRAPH
   84 #endif
   85 
   86 /*
   87  * It's Ascii-art time!
   88  *   +-------------+   +-------------+
   89  *   |socket  (ctl)|   |socket (data)|
   90  *   +-------------+   +-------------+
   91  *          ^                 ^
   92  *          |                 |
   93  *          v                 v
   94  *    +-----------+     +-----------+
   95  *    |pcb   (ctl)|     |pcb  (data)|
   96  *    +-----------+     +-----------+
   97  *          ^                 ^
   98  *          |                 |
   99  *          v                 v
  100  *      +--------------------------+
  101  *      |   Socket type private    |
  102  *      |       data               |
  103  *      +--------------------------+
  104  *                   ^
  105  *                   |
  106  *                   v
  107  *           +----------------+
  108  *           | struct ng_node |
  109  *           +----------------+
  110  */
  111 
  112 /* Netgraph node methods */
  113 static ng_constructor_t ngs_constructor;
  114 static ng_rcvmsg_t      ngs_rcvmsg;
  115 static ng_shutdown_t    ngs_shutdown;
  116 static ng_newhook_t     ngs_newhook;
  117 static ng_connect_t     ngs_connect;
  118 static ng_findhook_t    ngs_findhook;
  119 static ng_rcvdata_t     ngs_rcvdata;
  120 static ng_disconnect_t  ngs_disconnect;
  121 
  122 /* Internal methods */
  123 static int      ng_attach_data(struct socket *so);
  124 static int      ng_attach_cntl(struct socket *so);
  125 static int      ng_attach_common(struct socket *so, int type);
  126 static void     ng_detach_common(struct ngpcb *pcbp, int type);
  127 static void     ng_socket_free_priv(struct ngsock *priv);
  128 static int      ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
  129 static int      ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
  130 
  131 static int      ngs_mod_event(module_t mod, int event, void *data);
  132 static void     ng_socket_item_applied(void *context, int error);
  133 
  134 /* Netgraph type descriptor */
  135 static struct ng_type typestruct = {
  136         .version =      NG_ABI_VERSION,
  137         .name =         NG_SOCKET_NODE_TYPE,
  138         .mod_event =    ngs_mod_event,
  139         .constructor =  ngs_constructor,
  140         .rcvmsg =       ngs_rcvmsg,
  141         .shutdown =     ngs_shutdown,
  142         .newhook =      ngs_newhook,
  143         .connect =      ngs_connect,
  144         .findhook =     ngs_findhook,
  145         .rcvdata =      ngs_rcvdata,
  146         .disconnect =   ngs_disconnect,
  147 };
  148 NETGRAPH_INIT_ORDERED(socket, &typestruct, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
  149 
  150 /* Buffer space */
  151 static u_long ngpdg_sendspace = 20 * 1024;      /* really max datagram size */
  152 SYSCTL_ULONG(_net_graph, OID_AUTO, maxdgram, CTLFLAG_RW,
  153     &ngpdg_sendspace , 0, "Maximum outgoing Netgraph datagram size");
  154 static u_long ngpdg_recvspace = 20 * 1024;
  155 SYSCTL_ULONG(_net_graph, OID_AUTO, recvspace, CTLFLAG_RW,
  156     &ngpdg_recvspace , 0, "Maximum space for incoming Netgraph datagrams");
  157 
  158 /* List of all sockets (for netstat -f netgraph) */
  159 static LIST_HEAD(, ngpcb) ngsocklist;
  160 
  161 static struct mtx       ngsocketlist_mtx;
  162 
  163 #define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb)
  164 
  165 /* If getting unexplained errors returned, set this to "kdb_enter("X"); */
  166 #ifndef TRAP_ERROR
  167 #define TRAP_ERROR
  168 #endif
  169 
  170 struct hookpriv {
  171         LIST_ENTRY(hookpriv)    next;
  172         hook_p                  hook;
  173 };
  174 LIST_HEAD(ngshash, hookpriv);
  175 
  176 /* Per-node private data */
  177 struct ngsock {
  178         struct ng_node  *node;          /* the associated netgraph node */
  179         struct ngpcb    *datasock;      /* optional data socket */
  180         struct ngpcb    *ctlsock;       /* optional control socket */
  181         struct ngshash  *hash;          /* hash for hook names */
  182         u_long          hmask;          /* hash mask */
  183         int     flags;
  184         int     refs;
  185         struct mtx      mtx;            /* mtx to wait on */
  186         int             error;          /* place to store error */
  187 };
  188 
  189 #define NGS_FLAG_NOLINGER       1       /* close with last hook */
  190 
  191 /***************************************************************
  192         Control sockets
  193 ***************************************************************/
  194 
  195 static int
  196 ngc_attach(struct socket *so, int proto, struct thread *td)
  197 {
  198         struct ngpcb *const pcbp = sotongpcb(so);
  199         int error;
  200 
  201         error = priv_check(td, PRIV_NETGRAPH_CONTROL);
  202         if (error)
  203                 return (error);
  204         if (pcbp != NULL)
  205                 return (EISCONN);
  206         return (ng_attach_cntl(so));
  207 }
  208 
  209 static void
  210 ngc_detach(struct socket *so)
  211 {
  212         struct ngpcb *const pcbp = sotongpcb(so);
  213 
  214         KASSERT(pcbp != NULL, ("ngc_detach: pcbp == NULL"));
  215         ng_detach_common(pcbp, NG_CONTROL);
  216 }
  217 
  218 static int
  219 ngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  220          struct mbuf *control, struct thread *td)
  221 {
  222         struct ngpcb *const pcbp = sotongpcb(so);
  223         struct ngsock *const priv = NG_NODE_PRIVATE(pcbp->sockdata->node);
  224         struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
  225         struct ng_mesg *msg;
  226         struct mbuf *m0;
  227         item_p item;
  228         char *path = NULL;
  229         int len, error = 0;
  230         struct ng_apply_info apply;
  231 
  232         if (control) {
  233                 error = EINVAL;
  234                 goto release;
  235         }
  236 
  237         /* Require destination as there may be >= 1 hooks on this node. */
  238         if (addr == NULL) {
  239                 error = EDESTADDRREQ;
  240                 goto release;
  241         }
  242 
  243         if (sap->sg_len > NG_NODESIZ + offsetof(struct sockaddr_ng, sg_data)) {
  244                 error = EINVAL;
  245                 goto release;
  246         }
  247 
  248         /*
  249          * Allocate an expendable buffer for the path, chop off
  250          * the sockaddr header, and make sure it's NUL terminated.
  251          */
  252         len = sap->sg_len - offsetof(struct sockaddr_ng, sg_data);
  253         path = malloc(len + 1, M_NETGRAPH_PATH, M_WAITOK);
  254         bcopy(sap->sg_data, path, len);
  255         path[len] = '\0';
  256 
  257         /*
  258          * Move the actual message out of mbufs into a linear buffer.
  259          * Start by adding up the size of the data. (could use mh_len?)
  260          */
  261         for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
  262                 len += m0->m_len;
  263 
  264         /*
  265          * Move the data into a linear buffer as well.
  266          * Messages are not delivered in mbufs.
  267          */
  268         msg = malloc(len + 1, M_NETGRAPH_MSG, M_WAITOK);
  269         m_copydata(m, 0, len, (char *)msg);
  270 
  271         if (msg->header.version != NG_VERSION) {
  272                 free(msg, M_NETGRAPH_MSG);
  273                 error = EINVAL;
  274                 goto release;
  275         }
  276 
  277         /*
  278          * Hack alert!
  279          * We look into the message and if it mkpeers a node of unknown type, we
  280          * try to load it. We need to do this now, in syscall thread, because if
  281          * message gets queued and applied later we will get panic.
  282          */
  283         if (msg->header.typecookie == NGM_GENERIC_COOKIE &&
  284             msg->header.cmd == NGM_MKPEER) {
  285                 struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data;
  286 
  287                 if (ng_findtype(mkp->type) == NULL) {
  288                         char filename[NG_TYPESIZ + 3];
  289                         int fileid;
  290 
  291                         /* Not found, try to load it as a loadable module. */
  292                         snprintf(filename, sizeof(filename), "ng_%s",
  293                             mkp->type);
  294                         error = kern_kldload(curthread, filename, &fileid);
  295                         if (error != 0) {
  296                                 free(msg, M_NETGRAPH_MSG);
  297                                 goto release;
  298                         }
  299 
  300                         /* See if type has been loaded successfully. */
  301                         if (ng_findtype(mkp->type) == NULL) {
  302                                 free(msg, M_NETGRAPH_MSG);
  303                                 (void)kern_kldunload(curthread, fileid,
  304                                     LINKER_UNLOAD_NORMAL);
  305                                 error =  ENXIO;
  306                                 goto release;
  307                         }
  308                 }
  309         }
  310 
  311         item = ng_package_msg(msg, NG_WAITOK);
  312         if ((error = ng_address_path((pcbp->sockdata->node), item, path, 0))
  313             != 0) {
  314 #ifdef TRACE_MESSAGES
  315                 printf("ng_address_path: errx=%d\n", error);
  316 #endif
  317                 goto release;
  318         }
  319 
  320 #ifdef TRACE_MESSAGES
  321         printf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n",
  322                 item->el_dest->nd_ID,
  323                 msg->header.typecookie,
  324                 msg->header.cmd,
  325                 msg->header.cmdstr,
  326                 msg->header.flags,
  327                 msg->header.token,
  328                 item->el_dest->nd_type->name);
  329 #endif
  330         SAVE_LINE(item);
  331         /*
  332          * We do not want to return from syscall until the item
  333          * is processed by destination node. We register callback
  334          * on the item, which will update priv->error when item
  335          * was applied.
  336          * If ng_snd_item() has queued item, we sleep until
  337          * callback wakes us up.
  338          */
  339         bzero(&apply, sizeof(apply));
  340         apply.apply = ng_socket_item_applied;
  341         apply.context = priv;
  342         item->apply = &apply;
  343         priv->error = -1;
  344 
  345         error = ng_snd_item(item, 0);
  346 
  347         mtx_lock(&priv->mtx);
  348         if (priv->error == -1)
  349                 msleep(priv, &priv->mtx, 0, "ngsock", 0);
  350         mtx_unlock(&priv->mtx);
  351         KASSERT(priv->error != -1,
  352             ("ng_socket: priv->error wasn't updated"));
  353         error = priv->error;
  354 
  355 release:
  356         if (path != NULL)
  357                 free(path, M_NETGRAPH_PATH);
  358         if (control != NULL)
  359                 m_freem(control);
  360         if (m != NULL)
  361                 m_freem(m);
  362         return (error);
  363 }
  364 
  365 static int
  366 ngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  367 {
  368         struct ngpcb *const pcbp = sotongpcb(so);
  369 
  370         if (pcbp == NULL)
  371                 return (EINVAL);
  372         return (ng_bind(nam, pcbp));
  373 }
  374 
  375 static int
  376 ngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  377 {
  378         /*
  379          * At this time refuse to do this.. it used to
  380          * do something but it was undocumented and not used.
  381          */
  382         printf("program tried to connect control socket to remote node\n");
  383         return (EINVAL);
  384 }
  385 
  386 /***************************************************************
  387         Data sockets
  388 ***************************************************************/
  389 
  390 static int
  391 ngd_attach(struct socket *so, int proto, struct thread *td)
  392 {
  393         struct ngpcb *const pcbp = sotongpcb(so);
  394 
  395         if (pcbp != NULL)
  396                 return (EISCONN);
  397         return (ng_attach_data(so));
  398 }
  399 
  400 static void
  401 ngd_detach(struct socket *so)
  402 {
  403         struct ngpcb *const pcbp = sotongpcb(so);
  404 
  405         KASSERT(pcbp != NULL, ("ngd_detach: pcbp == NULL"));
  406         ng_detach_common(pcbp, NG_DATA);
  407 }
  408 
  409 static int
  410 ngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  411          struct mbuf *control, struct thread *td)
  412 {
  413         struct epoch_tracker et;
  414         struct ngpcb *const pcbp = sotongpcb(so);
  415         struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
  416         int     len, error;
  417         hook_p  hook = NULL;
  418         item_p  item;
  419         char    hookname[NG_HOOKSIZ];
  420 
  421         if ((pcbp == NULL) || (control != NULL)) {
  422                 error = EINVAL;
  423                 goto release;
  424         }
  425         if (pcbp->sockdata == NULL) {
  426                 error = ENOTCONN;
  427                 goto release;
  428         }
  429 
  430         if (sap == NULL) {
  431                 len = 0;                /* Make compiler happy. */
  432         } else {
  433                 if (sap->sg_len > NG_NODESIZ +
  434                     offsetof(struct sockaddr_ng, sg_data)) {
  435                         error = EINVAL;
  436                         goto release;
  437                 }
  438                 len = sap->sg_len - offsetof(struct sockaddr_ng, sg_data);
  439         }
  440 
  441         /*
  442          * If the user used any of these ways to not specify an address
  443          * then handle specially.
  444          */
  445         if ((sap == NULL) || (len <= 0) || (*sap->sg_data == '\0')) {
  446                 if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) {
  447                         error = EDESTADDRREQ;
  448                         goto release;
  449                 }
  450                 /*
  451                  * If exactly one hook exists, just use it.
  452                  * Special case to allow write(2) to work on an ng_socket.
  453                  */
  454                 hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks);
  455         } else {
  456                 if (len >= NG_HOOKSIZ) {
  457                         error = EINVAL;
  458                         goto release;
  459                 }
  460 
  461                 /*
  462                  * chop off the sockaddr header, and make sure it's NUL
  463                  * terminated
  464                  */
  465                 bcopy(sap->sg_data, hookname, len);
  466                 hookname[len] = '\0';
  467 
  468                 /* Find the correct hook from 'hookname' */
  469                 hook = ng_findhook(pcbp->sockdata->node, hookname);
  470                 if (hook == NULL) {
  471                         error = EHOSTUNREACH;
  472                         goto release;
  473                 }
  474         }
  475 
  476         /* Send data. */
  477         item = ng_package_data(m, NG_WAITOK);
  478         m = NULL;
  479         NET_EPOCH_ENTER(et);
  480         NG_FWD_ITEM_HOOK(error, item, hook);
  481         NET_EPOCH_EXIT(et);
  482 
  483 release:
  484         if (control != NULL)
  485                 m_freem(control);
  486         if (m != NULL)
  487                 m_freem(m);
  488         return (error);
  489 }
  490 
  491 static int
  492 ngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  493 {
  494         struct ngpcb *const pcbp = sotongpcb(so);
  495 
  496         if (pcbp == NULL)
  497                 return (EINVAL);
  498         return (ng_connect_data(nam, pcbp));
  499 }
  500 
  501 /*
  502  * Used for both data and control sockets
  503  */
  504 static int
  505 ng_getsockaddr(struct socket *so, struct sockaddr **addr)
  506 {
  507         struct ngpcb *pcbp;
  508         struct sockaddr_ng *sg;
  509         int sg_len;
  510         int error = 0;
  511 
  512         pcbp = sotongpcb(so);
  513         if ((pcbp == NULL) || (pcbp->sockdata == NULL))
  514                 /* XXXGL: can this still happen? */
  515                 return (EINVAL);
  516 
  517         sg_len = sizeof(struct sockaddr_ng) + NG_NODESIZ -
  518             sizeof(sg->sg_data);
  519         sg = malloc(sg_len, M_SONAME, M_WAITOK | M_ZERO);
  520 
  521         mtx_lock(&pcbp->sockdata->mtx);
  522         if (pcbp->sockdata->node != NULL) {
  523                 node_p node = pcbp->sockdata->node;
  524 
  525                 if (NG_NODE_HAS_NAME(node))
  526                         bcopy(NG_NODE_NAME(node), sg->sg_data,
  527                             strlen(NG_NODE_NAME(node)));
  528                 mtx_unlock(&pcbp->sockdata->mtx);
  529 
  530                 sg->sg_len = sg_len;
  531                 sg->sg_family = AF_NETGRAPH;
  532                 *addr = (struct sockaddr *)sg;
  533         } else {
  534                 mtx_unlock(&pcbp->sockdata->mtx);
  535                 free(sg, M_SONAME);
  536                 error = EINVAL;
  537         }
  538 
  539         return (error);
  540 }
  541 
  542 /*
  543  * Attach a socket to it's protocol specific partner.
  544  * For a control socket, actually create a netgraph node and attach
  545  * to it as well.
  546  */
  547 
  548 static int
  549 ng_attach_cntl(struct socket *so)
  550 {
  551         struct ngsock *priv;
  552         struct ngpcb *pcbp;
  553         node_p node;
  554         int error;
  555 
  556         /* Setup protocol control block */
  557         if ((error = ng_attach_common(so, NG_CONTROL)) != 0)
  558                 return (error);
  559         pcbp = sotongpcb(so);
  560 
  561         /* Make the generic node components */
  562         if ((error = ng_make_node_common(&typestruct, &node)) != 0) {
  563                 ng_detach_common(pcbp, NG_CONTROL);
  564                 return (error);
  565         }
  566 
  567         /*
  568          * Allocate node private info and hash. We start
  569          * with 16 hash entries, however we may grow later
  570          * in ngs_newhook(). We can't predict how much hooks
  571          * does this node plan to have.
  572          */
  573         priv = malloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO);
  574         priv->hash = hashinit(16, M_NETGRAPH_SOCK, &priv->hmask);
  575 
  576         /* Initialize mutex. */
  577         mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF);
  578 
  579         /* Link the pcb the private data. */
  580         priv->ctlsock = pcbp;
  581         pcbp->sockdata = priv;
  582         priv->refs++;
  583         priv->node = node;
  584         pcbp->node_id = node->nd_ID;    /* hint for netstat(1) */
  585 
  586         /* Link the node and the private data. */
  587         NG_NODE_SET_PRIVATE(priv->node, priv);
  588         NG_NODE_REF(priv->node);
  589         priv->refs++;
  590 
  591         return (0);
  592 }
  593 
  594 static int
  595 ng_attach_data(struct socket *so)
  596 {
  597         return (ng_attach_common(so, NG_DATA));
  598 }
  599 
  600 /*
  601  * Set up a socket protocol control block.
  602  * This code is shared between control and data sockets.
  603  */
  604 static int
  605 ng_attach_common(struct socket *so, int type)
  606 {
  607         struct ngpcb *pcbp;
  608         int error;
  609 
  610         /* Standard socket setup stuff. */
  611         error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
  612         if (error)
  613                 return (error);
  614 
  615         /* Allocate the pcb. */
  616         pcbp = malloc(sizeof(struct ngpcb), M_PCB, M_WAITOK | M_ZERO);
  617         pcbp->type = type;
  618 
  619         /* Link the pcb and the socket. */
  620         so->so_pcb = (caddr_t)pcbp;
  621         pcbp->ng_socket = so;
  622 
  623         /* Add the socket to linked list */
  624         mtx_lock(&ngsocketlist_mtx);
  625         LIST_INSERT_HEAD(&ngsocklist, pcbp, socks);
  626         mtx_unlock(&ngsocketlist_mtx);
  627         return (0);
  628 }
  629 
  630 /*
  631  * Disassociate the socket from it's protocol specific
  632  * partner. If it's attached to a node's private data structure,
  633  * then unlink from that too. If we were the last socket attached to it,
  634  * then shut down the entire node. Shared code for control and data sockets.
  635  */
  636 static void
  637 ng_detach_common(struct ngpcb *pcbp, int which)
  638 {
  639         struct ngsock *priv = pcbp->sockdata;
  640 
  641         if (priv != NULL) {
  642                 mtx_lock(&priv->mtx);
  643 
  644                 switch (which) {
  645                 case NG_CONTROL:
  646                         priv->ctlsock = NULL;
  647                         break;
  648                 case NG_DATA:
  649                         priv->datasock = NULL;
  650                         break;
  651                 default:
  652                         panic("%s", __func__);
  653                 }
  654                 pcbp->sockdata = NULL;
  655                 pcbp->node_id = 0;
  656 
  657                 ng_socket_free_priv(priv);
  658         }
  659 
  660         pcbp->ng_socket->so_pcb = NULL;
  661         mtx_lock(&ngsocketlist_mtx);
  662         LIST_REMOVE(pcbp, socks);
  663         mtx_unlock(&ngsocketlist_mtx);
  664         free(pcbp, M_PCB);
  665 }
  666 
  667 /*
  668  * Remove a reference from node private data.
  669  */
  670 static void
  671 ng_socket_free_priv(struct ngsock *priv)
  672 {
  673         mtx_assert(&priv->mtx, MA_OWNED);
  674 
  675         priv->refs--;
  676 
  677         if (priv->refs == 0) {
  678                 mtx_destroy(&priv->mtx);
  679                 hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask);
  680                 free(priv, M_NETGRAPH_SOCK);
  681                 return;
  682         }
  683 
  684         if ((priv->refs == 1) && (priv->node != NULL)) {
  685                 node_p node = priv->node;
  686 
  687                 priv->node = NULL;
  688                 mtx_unlock(&priv->mtx);
  689                 NG_NODE_UNREF(node);
  690                 ng_rmnode_self(node);
  691         } else
  692                 mtx_unlock(&priv->mtx);
  693 }
  694 
  695 /*
  696  * Connect the data socket to a named control socket node.
  697  */
  698 static int
  699 ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
  700 {
  701         struct sockaddr_ng *sap;
  702         node_p farnode;
  703         struct ngsock *priv;
  704         int error;
  705         item_p item;
  706 
  707         /* If we are already connected, don't do it again. */
  708         if (pcbp->sockdata != NULL)
  709                 return (EISCONN);
  710 
  711         /*
  712          * Find the target (victim) and check it doesn't already have
  713          * a data socket. Also check it is a 'socket' type node.
  714          * Use ng_package_data() and ng_address_path() to do this.
  715          */
  716 
  717         sap = (struct sockaddr_ng *) nam;
  718         /* The item will hold the node reference. */
  719         item = ng_package_data(NULL, NG_WAITOK);
  720 
  721         if ((error = ng_address_path(NULL, item,  sap->sg_data, 0)))
  722                 return (error); /* item is freed on failure */
  723 
  724         /*
  725          * Extract node from item and free item. Remember we now have
  726          * a reference on the node. The item holds it for us.
  727          * when we free the item we release the reference.
  728          */
  729         farnode = item->el_dest; /* shortcut */
  730         if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) {
  731                 NG_FREE_ITEM(item); /* drop the reference to the node */
  732                 return (EINVAL);
  733         }
  734         priv = NG_NODE_PRIVATE(farnode);
  735         if (priv->datasock != NULL) {
  736                 NG_FREE_ITEM(item);     /* drop the reference to the node */
  737                 return (EADDRINUSE);
  738         }
  739 
  740         /*
  741          * Link the PCB and the private data struct. and note the extra
  742          * reference. Drop the extra reference on the node.
  743          */
  744         mtx_lock(&priv->mtx);
  745         priv->datasock = pcbp;
  746         pcbp->sockdata = priv;
  747         pcbp->node_id = priv->node->nd_ID;      /* hint for netstat(1) */
  748         priv->refs++;
  749         mtx_unlock(&priv->mtx);
  750         NG_FREE_ITEM(item);     /* drop the reference to the node */
  751         return (0);
  752 }
  753 
  754 /*
  755  * Binding a socket means giving the corresponding node a name
  756  */
  757 static int
  758 ng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
  759 {
  760         struct ngsock *const priv = pcbp->sockdata;
  761         struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
  762 
  763         if (priv == NULL) {
  764                 TRAP_ERROR;
  765                 return (EINVAL);
  766         }
  767         if ((sap->sg_len < 4) || (sap->sg_len > (NG_NODESIZ + 2)) ||
  768             (sap->sg_data[0] == '\0') ||
  769             (sap->sg_data[sap->sg_len - 3] != '\0')) {
  770                 TRAP_ERROR;
  771                 return (EINVAL);
  772         }
  773         return (ng_name_node(priv->node, sap->sg_data));
  774 }
  775 
  776 /***************************************************************
  777         Netgraph node
  778 ***************************************************************/
  779 
  780 /*
  781  * You can only create new nodes from the socket end of things.
  782  */
  783 static int
  784 ngs_constructor(node_p nodep)
  785 {
  786         return (EINVAL);
  787 }
  788 
  789 static void
  790 ngs_rehash(node_p node)
  791 {
  792         struct ngsock *priv = NG_NODE_PRIVATE(node);
  793         struct ngshash *new;
  794         struct hookpriv *hp;
  795         hook_p hook;
  796         uint32_t h;
  797         u_long hmask;
  798 
  799         new = hashinit_flags((priv->hmask + 1) * 2, M_NETGRAPH_SOCK, &hmask,
  800             HASH_NOWAIT);
  801         if (new == NULL)
  802                 return;
  803 
  804         LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
  805                 hp = NG_HOOK_PRIVATE(hook);
  806 #ifdef INVARIANTS
  807                 LIST_REMOVE(hp, next);
  808 #endif
  809                 h = hash32_str(NG_HOOK_NAME(hook), HASHINIT) & hmask;
  810                 LIST_INSERT_HEAD(&new[h], hp, next);
  811         }
  812 
  813         hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask);
  814         priv->hash = new;
  815         priv->hmask = hmask;
  816 }
  817 
  818 /*
  819  * We allow any hook to be connected to the node.
  820  * There is no per-hook private information though.
  821  */
  822 static int
  823 ngs_newhook(node_p node, hook_p hook, const char *name)
  824 {
  825         struct ngsock *const priv = NG_NODE_PRIVATE(node);
  826         struct hookpriv *hp;
  827         uint32_t h;
  828 
  829         hp = malloc(sizeof(*hp), M_NETGRAPH_SOCK, M_NOWAIT);
  830         if (hp == NULL)
  831                 return (ENOMEM);
  832         if (node->nd_numhooks * 2 > priv->hmask)
  833                 ngs_rehash(node);
  834         hp->hook = hook;
  835         h = hash32_str(name, HASHINIT) & priv->hmask;
  836         LIST_INSERT_HEAD(&priv->hash[h], hp, next);
  837         NG_HOOK_SET_PRIVATE(hook, hp);
  838 
  839         return (0);
  840 }
  841 
  842 /*
  843  * If only one hook, allow read(2) and write(2) to work.
  844  */
  845 static int
  846 ngs_connect(hook_p hook)
  847 {
  848         node_p node = NG_HOOK_NODE(hook);
  849         struct ngsock *priv = NG_NODE_PRIVATE(node);
  850 
  851         if ((priv->datasock) && (priv->datasock->ng_socket)) {
  852                 if (NG_NODE_NUMHOOKS(node) == 1)
  853                         priv->datasock->ng_socket->so_state |= SS_ISCONNECTED;
  854                 else
  855                         priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED;
  856         }
  857         return (0);
  858 }
  859 
  860 /* Look up hook by name */
  861 static hook_p
  862 ngs_findhook(node_p node, const char *name)
  863 {
  864         struct ngsock *priv = NG_NODE_PRIVATE(node);
  865         struct hookpriv *hp;
  866         uint32_t h;
  867 
  868         /*
  869          * Microoptimisation for an ng_socket with
  870          * a single hook, which is a common case.
  871          */
  872         if (node->nd_numhooks == 1) {
  873                 hook_p hook;
  874 
  875                 hook = LIST_FIRST(&node->nd_hooks);
  876 
  877                 if (strcmp(NG_HOOK_NAME(hook), name) == 0)
  878                         return (hook);
  879                 else
  880                         return (NULL);
  881         }
  882 
  883         h = hash32_str(name, HASHINIT) & priv->hmask;
  884 
  885         LIST_FOREACH(hp, &priv->hash[h], next)
  886                 if (strcmp(NG_HOOK_NAME(hp->hook), name) == 0)
  887                         return (hp->hook);
  888 
  889         return (NULL);
  890 }
  891 
  892 /*
  893  * Incoming messages get passed up to the control socket.
  894  * Unless they are for us specifically (socket_type)
  895  */
  896 static int
  897 ngs_rcvmsg(node_p node, item_p item, hook_p lasthook)
  898 {
  899         struct ngsock *const priv = NG_NODE_PRIVATE(node);
  900         struct ngpcb *pcbp;
  901         struct socket *so;
  902         struct sockaddr_ng addr;
  903         struct ng_mesg *msg;
  904         struct mbuf *m;
  905         ng_ID_t retaddr = NGI_RETADDR(item);
  906         int addrlen;
  907         int error = 0;
  908 
  909         NGI_GET_MSG(item, msg);
  910         NG_FREE_ITEM(item);
  911 
  912         /*
  913          * Grab priv->mtx here to prevent destroying of control socket
  914          * after checking that priv->ctlsock is not NULL.
  915          */
  916         mtx_lock(&priv->mtx);
  917         pcbp = priv->ctlsock;
  918 
  919         /*
  920          * Only allow mesgs to be passed if we have the control socket.
  921          * Data sockets can only support the generic messages.
  922          */
  923         if (pcbp == NULL) {
  924                 mtx_unlock(&priv->mtx);
  925                 TRAP_ERROR;
  926                 NG_FREE_MSG(msg);
  927                 return (EINVAL);
  928         }
  929         so = pcbp->ng_socket;
  930         SOCKBUF_LOCK(&so->so_rcv);
  931 
  932         /* As long as the race is handled, priv->mtx may be unlocked now. */
  933         mtx_unlock(&priv->mtx);
  934 
  935 #ifdef TRACE_MESSAGES
  936         printf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n",
  937                 retaddr,
  938                 msg->header.typecookie,
  939                 msg->header.cmd,
  940                 msg->header.cmdstr,
  941                 msg->header.flags,
  942                 msg->header.token);
  943 #endif
  944 
  945         if (msg->header.typecookie == NGM_SOCKET_COOKIE) {
  946                 switch (msg->header.cmd) {
  947                 case NGM_SOCK_CMD_NOLINGER:
  948                         priv->flags |= NGS_FLAG_NOLINGER;
  949                         break;
  950                 case NGM_SOCK_CMD_LINGER:
  951                         priv->flags &= ~NGS_FLAG_NOLINGER;
  952                         break;
  953                 default:
  954                         error = EINVAL;         /* unknown command */
  955                 }
  956                 SOCKBUF_UNLOCK(&so->so_rcv);
  957 
  958                 /* Free the message and return. */
  959                 NG_FREE_MSG(msg);
  960                 return (error);
  961         }
  962 
  963         /* Get the return address into a sockaddr. */
  964         bzero(&addr, sizeof(addr));
  965         addr.sg_len = sizeof(addr);
  966         addr.sg_family = AF_NETGRAPH;
  967         addrlen = snprintf((char *)&addr.sg_data, sizeof(addr.sg_data),
  968             "[%x]:", retaddr);
  969         if (addrlen < 0 || addrlen > sizeof(addr.sg_data)) {
  970                 SOCKBUF_UNLOCK(&so->so_rcv);
  971                 printf("%s: snprintf([%x]) failed - %d\n", __func__, retaddr,
  972                     addrlen);
  973                 NG_FREE_MSG(msg);
  974                 return (EINVAL);
  975         }
  976 
  977         /* Copy the message itself into an mbuf chain. */
  978         m = m_devget((caddr_t)msg, sizeof(struct ng_mesg) + msg->header.arglen,
  979             0, NULL, NULL);
  980 
  981         /*
  982          * Here we free the message. We need to do that
  983          * regardless of whether we got mbufs.
  984          */
  985         NG_FREE_MSG(msg);
  986 
  987         if (m == NULL) {
  988                 SOCKBUF_UNLOCK(&so->so_rcv);
  989                 TRAP_ERROR;
  990                 return (ENOBUFS);
  991         }
  992 
  993         /* Send it up to the socket. */
  994         if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)&addr, m,
  995             NULL) == 0) {
  996                 soroverflow_locked(so);
  997                 TRAP_ERROR;
  998                 m_freem(m);
  999                 return (ENOBUFS);
 1000         }
 1001 
 1002         /* sorwakeup_locked () releases the lock internally. */
 1003         sorwakeup_locked(so);
 1004 
 1005         return (error);
 1006 }
 1007 
 1008 /*
 1009  * Receive data on a hook
 1010  */
 1011 static int
 1012 ngs_rcvdata(hook_p hook, item_p item)
 1013 {
 1014         struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
 1015         struct ngpcb *const pcbp = priv->datasock;
 1016         struct socket *so;
 1017         struct sockaddr_ng *addr;
 1018         char *addrbuf[NG_HOOKSIZ + 4];
 1019         int addrlen;
 1020         struct mbuf *m;
 1021 
 1022         NGI_GET_M(item, m);
 1023         NG_FREE_ITEM(item);
 1024 
 1025         /* If there is no data socket, black-hole it. */
 1026         if (pcbp == NULL) {
 1027                 NG_FREE_M(m);
 1028                 return (0);
 1029         }
 1030         so = pcbp->ng_socket;
 1031 
 1032         /* Get the return address into a sockaddr. */
 1033         addrlen = strlen(NG_HOOK_NAME(hook));   /* <= NG_HOOKSIZ - 1 */
 1034         addr = (struct sockaddr_ng *) addrbuf;
 1035         addr->sg_len = addrlen + 3;
 1036         addr->sg_family = AF_NETGRAPH;
 1037         bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen);
 1038         addr->sg_data[addrlen] = '\0';
 1039 
 1040         /* Try to tell the socket which hook it came in on. */
 1041         SOCKBUF_LOCK(&so->so_rcv);
 1042         if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)addr, m,
 1043             NULL) == 0) {
 1044                 SOCKBUF_UNLOCK(&so->so_rcv);
 1045                 m_freem(m);
 1046                 TRAP_ERROR;
 1047                 return (ENOBUFS);
 1048         }
 1049 
 1050         /* sorwakeup_locked () releases the lock internally. */
 1051         sorwakeup_locked(so);
 1052         return (0);
 1053 }
 1054 
 1055 /*
 1056  * Hook disconnection
 1057  *
 1058  * For this type, removal of the last link destroys the node
 1059  * if the NOLINGER flag is set.
 1060  */
 1061 static int
 1062 ngs_disconnect(hook_p hook)
 1063 {
 1064         node_p node = NG_HOOK_NODE(hook);
 1065         struct ngsock *const priv = NG_NODE_PRIVATE(node);
 1066         struct hookpriv *hp = NG_HOOK_PRIVATE(hook);
 1067 
 1068         LIST_REMOVE(hp, next);
 1069         free(hp, M_NETGRAPH_SOCK);
 1070 
 1071         if ((priv->datasock) && (priv->datasock->ng_socket)) {
 1072                 if (NG_NODE_NUMHOOKS(node) == 1)
 1073                         priv->datasock->ng_socket->so_state |= SS_ISCONNECTED;
 1074                 else
 1075                         priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED;
 1076         }
 1077 
 1078         if ((priv->flags & NGS_FLAG_NOLINGER) &&
 1079             (NG_NODE_NUMHOOKS(node) == 0) && (NG_NODE_IS_VALID(node)))
 1080                 ng_rmnode_self(node);
 1081 
 1082         return (0);
 1083 }
 1084 
 1085 /*
 1086  * Do local shutdown processing.
 1087  * In this case, that involves making sure the socket
 1088  * knows we should be shutting down.
 1089  */
 1090 static int
 1091 ngs_shutdown(node_p node)
 1092 {
 1093         struct ngsock *const priv = NG_NODE_PRIVATE(node);
 1094         struct ngpcb *dpcbp, *pcbp;
 1095 
 1096         mtx_lock(&priv->mtx);
 1097         dpcbp = priv->datasock;
 1098         pcbp = priv->ctlsock;
 1099 
 1100         if (dpcbp != NULL)
 1101                 soisdisconnected(dpcbp->ng_socket);
 1102 
 1103         if (pcbp != NULL)
 1104                 soisdisconnected(pcbp->ng_socket);
 1105 
 1106         priv->node = NULL;
 1107         NG_NODE_SET_PRIVATE(node, NULL);
 1108         ng_socket_free_priv(priv);
 1109 
 1110         NG_NODE_UNREF(node);
 1111         return (0);
 1112 }
 1113 
 1114 static void
 1115 ng_socket_item_applied(void *context, int error)
 1116 {
 1117         struct ngsock *const priv = (struct ngsock *)context;
 1118 
 1119         mtx_lock(&priv->mtx);
 1120         priv->error = error;
 1121         wakeup(priv);
 1122         mtx_unlock(&priv->mtx);
 1123 
 1124 }
 1125 
 1126 static  int
 1127 dummy_disconnect(struct socket *so)
 1128 {
 1129         return (0);
 1130 }
 1131 
 1132 /*
 1133  * Definitions of protocols supported in the NETGRAPH domain.
 1134  * Control and data socket type descriptors
 1135  *
 1136  * XXXRW: Perhaps _close should do something?
 1137  */
 1138 static struct protosw ngcontrol_protosw = {
 1139         .pr_type =              SOCK_DGRAM,
 1140         .pr_protocol =          NG_CONTROL,
 1141         .pr_flags =             PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,
 1142         .pr_attach =            ngc_attach,
 1143         .pr_bind =              ngc_bind,
 1144         .pr_connect =           ngc_connect,
 1145         .pr_detach =            ngc_detach,
 1146         .pr_disconnect =        dummy_disconnect,
 1147         .pr_send =              ngc_send,
 1148         .pr_sockaddr =          ng_getsockaddr,
 1149 };
 1150 static struct protosw ngdata_protosw = {
 1151         .pr_type =              SOCK_DGRAM,
 1152         .pr_protocol =          NG_DATA,
 1153         .pr_flags =             PR_ATOMIC | PR_ADDR,
 1154         .pr_attach =            ngd_attach,
 1155         .pr_connect =           ngd_connect,
 1156         .pr_detach =            ngd_detach,
 1157         .pr_disconnect =        dummy_disconnect,
 1158         .pr_send =              ngd_send,
 1159         .pr_sockaddr =          ng_getsockaddr,
 1160 };
 1161 
 1162 static struct domain ngdomain = {
 1163         .dom_family =           AF_NETGRAPH,
 1164         .dom_name =             "netgraph",
 1165         .dom_nprotosw =         2,
 1166         .dom_protosw =          { &ngcontrol_protosw, &ngdata_protosw },
 1167 };
 1168 
 1169 /*
 1170  * Handle loading and unloading for this node type.
 1171  * This is to handle auxiliary linkages (e.g protocol domain addition).
 1172  */
 1173 static int
 1174 ngs_mod_event(module_t mod, int event, void *data)
 1175 {
 1176         int error = 0;
 1177 
 1178         switch (event) {
 1179         case MOD_LOAD:
 1180                 mtx_init(&ngsocketlist_mtx, "ng_socketlist", NULL, MTX_DEF);
 1181                 break;
 1182         case MOD_UNLOAD:
 1183                 /* Ensure there are no open netgraph sockets. */
 1184                 if (!LIST_EMPTY(&ngsocklist)) {
 1185                         error = EBUSY;
 1186                         break;
 1187                 }
 1188 #ifdef NOTYET
 1189                 /* Unregister protocol domain XXX can't do this yet.. */
 1190 #endif
 1191                 error = EBUSY;
 1192                 break;
 1193         default:
 1194                 error = EOPNOTSUPP;
 1195                 break;
 1196         }
 1197         return (error);
 1198 }
 1199 
 1200 DOMAIN_SET(ng);
 1201 
 1202 SYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, AF_NETGRAPH, "");
 1203 static SYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
 1204     "DATA");
 1205 SYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, NG_DATA, "");
 1206 static SYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
 1207     "CONTROL");
 1208 SYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, NG_CONTROL, "");

Cache object: 42dc445c0a794fa43ef90febb4db0134


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