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_ksocket.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 /*
    3  * ng_ksocket.c
    4  *
    5  * Copyright (c) 1996-1999 Whistle Communications, Inc.
    6  * All rights reserved.
    7  * 
    8  * Subject to the following obligations and disclaimer of warranty, use and
    9  * redistribution of this software, in source or object code forms, with or
   10  * without modifications are expressly permitted by Whistle Communications;
   11  * provided, however, that:
   12  * 1. Any and all reproductions of the source or object code must include the
   13  *    copyright notice above and the following disclaimer of warranties; and
   14  * 2. No rights are granted, in any manner or form, to use Whistle
   15  *    Communications, Inc. trademarks, including the mark "WHISTLE
   16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   17  *    such appears in the above copyright notice or in the software.
   18  * 
   19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   35  * OF SUCH DAMAGE.
   36  *
   37  * Author: Archie Cobbs <archie@freebsd.org>
   38  *
   39  * $FreeBSD$
   40  * $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $
   41  */
   42 
   43 /*
   44  * Kernel socket node type.  This node type is basically a kernel-mode
   45  * version of a socket... kindof like the reverse of the socket node type.
   46  */
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/kernel.h>
   51 #include <sys/mbuf.h>
   52 #include <sys/proc.h>
   53 #include <sys/malloc.h>
   54 #include <sys/ctype.h>
   55 #include <sys/protosw.h>
   56 #include <sys/errno.h>
   57 #include <sys/socket.h>
   58 #include <sys/socketvar.h>
   59 #include <sys/uio.h>
   60 #include <sys/un.h>
   61 
   62 #include <netgraph/ng_message.h>
   63 #include <netgraph/netgraph.h>
   64 #include <netgraph/ng_parse.h>
   65 #include <netgraph/ng_ksocket.h>
   66 
   67 #include <netinet/in.h>
   68 #include <netatalk/at.h>
   69 
   70 #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
   71 #define SADATA_OFFSET   (OFFSETOF(struct sockaddr, sa_data))
   72 
   73 /* Node private data */
   74 struct ng_ksocket_private {
   75         hook_p          hook;
   76         struct socket   *so;
   77 };
   78 typedef struct ng_ksocket_private *priv_p;
   79 
   80 /* Netgraph node methods */
   81 static ng_constructor_t ng_ksocket_constructor;
   82 static ng_rcvmsg_t      ng_ksocket_rcvmsg;
   83 static ng_shutdown_t    ng_ksocket_rmnode;
   84 static ng_newhook_t     ng_ksocket_newhook;
   85 static ng_rcvdata_t     ng_ksocket_rcvdata;
   86 static ng_disconnect_t  ng_ksocket_disconnect;
   87 
   88 /* Alias structure */
   89 struct ng_ksocket_alias {
   90         const char      *name;
   91         const int       value;
   92         const int       family;
   93 };
   94 
   95 /* Protocol family aliases */
   96 static const struct ng_ksocket_alias ng_ksocket_families[] = {
   97         { "local",      PF_LOCAL        },
   98         { "inet",       PF_INET         },
   99         { "inet6",      PF_INET6        },
  100         { "atalk",      PF_APPLETALK    },
  101         { "ipx",        PF_IPX          },
  102         { "atm",        PF_ATM          },
  103         { NULL,         -1              },
  104 };
  105 
  106 /* Socket type aliases */
  107 static const struct ng_ksocket_alias ng_ksocket_types[] = {
  108         { "stream",     SOCK_STREAM     },
  109         { "dgram",      SOCK_DGRAM      },
  110         { "raw",        SOCK_RAW        },
  111         { "rdm",        SOCK_RDM        },
  112         { "seqpacket",  SOCK_SEQPACKET  },
  113         { NULL,         -1              },
  114 };
  115 
  116 /* Protocol aliases */
  117 static const struct ng_ksocket_alias ng_ksocket_protos[] = {
  118         { "ip",         IPPROTO_IP,             PF_INET         },
  119         { "raw",        IPPROTO_IP,             PF_INET         },
  120         { "icmp",       IPPROTO_ICMP,           PF_INET         },
  121         { "igmp",       IPPROTO_IGMP,           PF_INET         },
  122         { "tcp",        IPPROTO_TCP,            PF_INET         },
  123         { "udp",        IPPROTO_UDP,            PF_INET         },
  124         { "gre",        IPPROTO_GRE,            PF_INET         },
  125         { "esp",        IPPROTO_ESP,            PF_INET         },
  126         { "ah",         IPPROTO_AH,             PF_INET         },
  127         { "swipe",      IPPROTO_SWIPE,          PF_INET         },
  128         { "encap",      IPPROTO_ENCAP,          PF_INET         },
  129         { "divert",     IPPROTO_DIVERT,         PF_INET         },
  130         { "ddp",        ATPROTO_DDP,            PF_APPLETALK    },
  131         { "aarp",       ATPROTO_AARP,           PF_APPLETALK    },
  132         { NULL,         -1                                      },
  133 };
  134 
  135 /* Helper functions */
  136 static void     ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
  137 static int      ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
  138                         const char *s, int family);
  139 
  140 /************************************************************************
  141                         STRUCT SOCKADDR PARSE TYPE
  142  ************************************************************************/
  143 
  144 /* Get the length of the data portion of a generic struct sockaddr */
  145 static int
  146 ng_parse_generic_sockdata_getLength(const struct ng_parse_type *type,
  147         const u_char *start, const u_char *buf)
  148 {
  149         const struct sockaddr *sa;
  150 
  151         sa = (const struct sockaddr *)(buf - SADATA_OFFSET);
  152         return sa->sa_len - SADATA_OFFSET;
  153 }
  154 
  155 /* Type for the variable length data portion of a generic struct sockaddr */
  156 static const struct ng_parse_type ng_ksocket_generic_sockdata_type = {
  157         &ng_parse_bytearray_type,
  158         &ng_parse_generic_sockdata_getLength
  159 };
  160 
  161 /* Type for a generic struct sockaddr */
  162 static const struct ng_parse_struct_info ng_parse_generic_sockaddr_type_info = {
  163         {
  164           { "len",      &ng_parse_int8_type                     },
  165           { "family",   &ng_parse_int8_type                     },
  166           { "data",     &ng_ksocket_generic_sockdata_type       },
  167           { NULL }
  168         }
  169 };
  170 static const struct ng_parse_type ng_ksocket_generic_sockaddr_type = {
  171         &ng_parse_struct_type,
  172         &ng_parse_generic_sockaddr_type_info
  173 };
  174 
  175 /* Convert a struct sockaddr from ASCII to binary.  If its a protocol
  176    family that we specially handle, do that, otherwise defer to the
  177    generic parse type ng_ksocket_generic_sockaddr_type. */
  178 static int
  179 ng_ksocket_sockaddr_parse(const struct ng_parse_type *type,
  180         const char *s, int *off, const u_char *const start,
  181         u_char *const buf, int *buflen)
  182 {
  183         struct sockaddr *const sa = (struct sockaddr *)buf;
  184         enum ng_parse_token tok;
  185         char fambuf[32];
  186         int family, len;
  187         char *t;
  188 
  189         /* If next token is a left curly brace, use generic parse type */
  190         if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) {
  191                 return (*ng_ksocket_generic_sockaddr_type.supertype->parse)
  192                     (&ng_ksocket_generic_sockaddr_type,
  193                     s, off, start, buf, buflen);
  194         }
  195 
  196         /* Get socket address family followed by a slash */
  197         while (isspace(s[*off]))
  198                 (*off)++;
  199         if ((t = index(s + *off, '/')) == NULL)
  200                 return (EINVAL);
  201         if ((len = t - (s + *off)) > sizeof(fambuf) - 1)
  202                 return (EINVAL);
  203         strncpy(fambuf, s + *off, len);
  204         fambuf[len] = '\0';
  205         *off += len + 1;
  206         if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1)
  207                 return (EINVAL);
  208 
  209         /* Set family */
  210         if (*buflen < SADATA_OFFSET)
  211                 return (ERANGE);
  212         sa->sa_family = family;
  213 
  214         /* Set family-specific data and length */
  215         switch (sa->sa_family) {
  216         case PF_LOCAL:          /* Get pathname */
  217             {
  218                 const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
  219                 struct sockaddr_un *const sun = (struct sockaddr_un *)sa;
  220                 int toklen, pathlen;
  221                 char *path;
  222 
  223                 if ((path = ng_get_string_token(s, off, &toklen)) == NULL)
  224                         return (EINVAL);
  225                 pathlen = strlen(path);
  226                 if (pathlen > SOCK_MAXADDRLEN) {
  227                         FREE(path, M_NETGRAPH);
  228                         return (E2BIG);
  229                 }
  230                 if (*buflen < pathoff + pathlen) {
  231                         FREE(path, M_NETGRAPH);
  232                         return (ERANGE);
  233                 }
  234                 *off += toklen;
  235                 bcopy(path, sun->sun_path, pathlen);
  236                 sun->sun_len = pathoff + pathlen;
  237                 FREE(path, M_NETGRAPH);
  238                 break;
  239             }
  240 
  241         case PF_INET:           /* Get an IP address with optional port */
  242             {
  243                 struct sockaddr_in *const sin = (struct sockaddr_in *)sa;
  244                 int i;
  245 
  246                 /* Parse this: <ipaddress>[:port] */
  247                 for (i = 0; i < 4; i++) {
  248                         u_long val;
  249                         char *eptr;
  250 
  251                         val = strtoul(s + *off, &eptr, 10);
  252                         if (val > 0xff || eptr == s + *off)
  253                                 return (EINVAL);
  254                         *off += (eptr - (s + *off));
  255                         ((u_char *)&sin->sin_addr)[i] = (u_char)val;
  256                         if (i < 3) {
  257                                 if (s[*off] != '.')
  258                                         return (EINVAL);
  259                                 (*off)++;
  260                         } else if (s[*off] == ':') {
  261                                 (*off)++;
  262                                 val = strtoul(s + *off, &eptr, 10);
  263                                 if (val > 0xffff || eptr == s + *off)
  264                                         return (EINVAL);
  265                                 *off += (eptr - (s + *off));
  266                                 sin->sin_port = htons(val);
  267                         } else
  268                                 sin->sin_port = 0;
  269                 }
  270                 bzero(&sin->sin_zero, sizeof(sin->sin_zero));
  271                 sin->sin_len = sizeof(*sin);
  272                 break;
  273             }
  274 
  275 #if 0
  276         case PF_APPLETALK:      /* XXX implement these someday */
  277         case PF_INET6:
  278         case PF_IPX:
  279 #endif
  280 
  281         default:
  282                 return (EINVAL);
  283         }
  284 
  285         /* Done */
  286         *buflen = sa->sa_len;
  287         return (0);
  288 }
  289 
  290 /* Convert a struct sockaddr from binary to ASCII */
  291 static int
  292 ng_ksocket_sockaddr_unparse(const struct ng_parse_type *type,
  293         const u_char *data, int *off, char *cbuf, int cbuflen)
  294 {
  295         const struct sockaddr *sa = (const struct sockaddr *)(data + *off);
  296         int slen = 0;
  297 
  298         /* Output socket address, either in special or generic format */
  299         switch (sa->sa_family) {
  300         case PF_LOCAL:
  301             {
  302                 const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
  303                 const struct sockaddr_un *sun = (const struct sockaddr_un *)sa;
  304                 const int pathlen = sun->sun_len - pathoff;
  305                 char pathbuf[SOCK_MAXADDRLEN + 1];
  306                 char *pathtoken;
  307 
  308                 bcopy(sun->sun_path, pathbuf, pathlen);
  309                 pathbuf[pathlen] = '\0';
  310                 if ((pathtoken = ng_encode_string(pathbuf)) == NULL)
  311                         return (ENOMEM);
  312                 slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken);
  313                 FREE(pathtoken, M_NETGRAPH);
  314                 if (slen >= cbuflen)
  315                         return (ERANGE);
  316                 *off += sun->sun_len;
  317                 return (0);
  318             }
  319 
  320         case PF_INET:
  321             {
  322                 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
  323 
  324                 slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d",
  325                   ((const u_char *)&sin->sin_addr)[0],
  326                   ((const u_char *)&sin->sin_addr)[1],
  327                   ((const u_char *)&sin->sin_addr)[2],
  328                   ((const u_char *)&sin->sin_addr)[3]);
  329                 if (sin->sin_port != 0) {
  330                         slen += snprintf(cbuf + strlen(cbuf),
  331                             cbuflen - strlen(cbuf), ":%d",
  332                             (u_int)ntohs(sin->sin_port));
  333                 }
  334                 if (slen >= cbuflen)
  335                         return (ERANGE);
  336                 *off += sizeof(*sin);
  337                 return(0);
  338             }
  339 
  340 #if 0
  341         case PF_APPLETALK:      /* XXX implement these someday */
  342         case PF_INET6:
  343         case PF_IPX:
  344 #endif
  345 
  346         default:
  347                 return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
  348                     (&ng_ksocket_generic_sockaddr_type,
  349                     data, off, cbuf, cbuflen);
  350         }
  351 }
  352 
  353 /* Parse type for struct sockaddr */
  354 static const struct ng_parse_type ng_ksocket_sockaddr_type = {
  355         NULL,
  356         NULL,
  357         NULL,
  358         &ng_ksocket_sockaddr_parse,
  359         &ng_ksocket_sockaddr_unparse,
  360         NULL            /* no such thing as a default struct sockaddr */
  361 };
  362 
  363 /************************************************************************
  364                 STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
  365  ************************************************************************/
  366 
  367 /* Get length of the struct ng_ksocket_sockopt value field, which is the
  368    just the excess of the message argument portion over the length of
  369    the struct ng_ksocket_sockopt. */
  370 static int
  371 ng_parse_sockoptval_getLength(const struct ng_parse_type *type,
  372         const u_char *start, const u_char *buf)
  373 {
  374         static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
  375         const struct ng_ksocket_sockopt *sopt;
  376         const struct ng_mesg *msg;
  377 
  378         sopt = (const struct ng_ksocket_sockopt *)(buf - offset);
  379         msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg));
  380         return msg->header.arglen - sizeof(*sopt);
  381 }
  382 
  383 /* Parse type for the option value part of a struct ng_ksocket_sockopt
  384    XXX Eventually, we should handle the different socket options specially.
  385    XXX This would avoid byte order problems, eg an integer value of 1 is
  386    XXX going to be "[1]" for little endian or "[3=1]" for big endian. */
  387 static const struct ng_parse_type ng_ksocket_sockoptval_type = {
  388         &ng_parse_bytearray_type,
  389         &ng_parse_sockoptval_getLength
  390 };
  391 
  392 /* Parse type for struct ng_ksocket_sockopt */
  393 static const struct ng_parse_struct_info ng_ksocket_sockopt_type_info
  394         = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type);
  395 static const struct ng_parse_type ng_ksocket_sockopt_type = {
  396         &ng_parse_struct_type,
  397         &ng_ksocket_sockopt_type_info,
  398 };
  399 
  400 /* List of commands and how to convert arguments to/from ASCII */
  401 static const struct ng_cmdlist ng_ksocket_cmds[] = {
  402         {
  403           NGM_KSOCKET_COOKIE,
  404           NGM_KSOCKET_BIND,
  405           "bind",
  406           &ng_ksocket_sockaddr_type,
  407           NULL
  408         },
  409         {
  410           NGM_KSOCKET_COOKIE,
  411           NGM_KSOCKET_LISTEN,
  412           "listen",
  413           &ng_parse_int32_type,
  414           NULL
  415         },
  416         {
  417           NGM_KSOCKET_COOKIE,
  418           NGM_KSOCKET_ACCEPT,
  419           "accept",
  420           NULL,
  421           &ng_ksocket_sockaddr_type
  422         },
  423         {
  424           NGM_KSOCKET_COOKIE,
  425           NGM_KSOCKET_CONNECT,
  426           "connect",
  427           &ng_ksocket_sockaddr_type,
  428           NULL
  429         },
  430         {
  431           NGM_KSOCKET_COOKIE,
  432           NGM_KSOCKET_GETNAME,
  433           "getname",
  434           NULL,
  435           &ng_ksocket_sockaddr_type
  436         },
  437         {
  438           NGM_KSOCKET_COOKIE,
  439           NGM_KSOCKET_GETPEERNAME,
  440           "getpeername",
  441           NULL,
  442           &ng_ksocket_sockaddr_type
  443         },
  444         {
  445           NGM_KSOCKET_COOKIE,
  446           NGM_KSOCKET_SETOPT,
  447           "setopt",
  448           &ng_ksocket_sockopt_type,
  449           NULL
  450         },
  451         {
  452           NGM_KSOCKET_COOKIE,
  453           NGM_KSOCKET_GETOPT,
  454           "getopt",
  455           &ng_ksocket_sockopt_type,
  456           &ng_ksocket_sockopt_type
  457         },
  458         { 0 }
  459 };
  460 
  461 /* Node type descriptor */
  462 static struct ng_type ng_ksocket_typestruct = {
  463         NG_VERSION,
  464         NG_KSOCKET_NODE_TYPE,
  465         NULL,
  466         ng_ksocket_constructor,
  467         ng_ksocket_rcvmsg,
  468         ng_ksocket_rmnode,
  469         ng_ksocket_newhook,
  470         NULL,
  471         NULL,
  472         ng_ksocket_rcvdata,
  473         ng_ksocket_rcvdata,
  474         ng_ksocket_disconnect,
  475         ng_ksocket_cmds
  476 };
  477 NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
  478 
  479 #define ERROUT(x)       do { error = (x); goto done; } while (0)
  480 
  481 /************************************************************************
  482                         NETGRAPH NODE STUFF
  483  ************************************************************************/
  484 
  485 /*
  486  * Node type constructor
  487  */
  488 static int
  489 ng_ksocket_constructor(node_p *nodep)
  490 {
  491         priv_p priv;
  492         int error;
  493 
  494         /* Allocate private structure */
  495         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
  496         if (priv == NULL)
  497                 return (ENOMEM);
  498         bzero(priv, sizeof(*priv));
  499 
  500         /* Call generic node constructor */
  501         if ((error = ng_make_node_common(&ng_ksocket_typestruct, nodep))) {
  502                 FREE(priv, M_NETGRAPH);
  503                 return (error);
  504         }
  505         (*nodep)->private = priv;
  506 
  507         /* Done */
  508         return (0);
  509 }
  510 
  511 /*
  512  * Give our OK for a hook to be added. The hook name is of the
  513  * form "<family>:<type>:<proto>" where the three components may
  514  * be decimal numbers or else aliases from the above lists.
  515  *
  516  * Connecting a hook amounts to opening the socket.  Disconnecting
  517  * the hook closes the socket and destroys the node as well.
  518  */
  519 static int
  520 ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
  521 {
  522         struct proc *p = curproc ? curproc : &proc0;    /* XXX broken */
  523         const priv_p priv = node->private;
  524         char *s1, *s2, name[NG_HOOKLEN+1];
  525         int family, type, protocol, error;
  526 
  527         /* Check if we're already connected */
  528         if (priv->hook != NULL)
  529                 return (EISCONN);
  530 
  531         /* Extract family, type, and protocol from hook name */
  532         snprintf(name, sizeof(name), "%s", name0);
  533         s1 = name;
  534         if ((s2 = index(s1, '/')) == NULL)
  535                 return (EINVAL);
  536         *s2++ = '\0';
  537         if ((family = ng_ksocket_parse(ng_ksocket_families, s1, 0)) == -1)
  538                 return (EINVAL);
  539         s1 = s2;
  540         if ((s2 = index(s1, '/')) == NULL)
  541                 return (EINVAL);
  542         *s2++ = '\0';
  543         if ((type = ng_ksocket_parse(ng_ksocket_types, s1, 0)) == -1)
  544                 return (EINVAL);
  545         s1 = s2;
  546         if ((protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family)) == -1)
  547                 return (EINVAL);
  548 
  549         /* Create the socket */
  550         if ((error = socreate(family, &priv->so, type, protocol, p)) != 0)
  551                 return (error);
  552 
  553         /* XXX call soreserve() ? */
  554 
  555         /* Add our hook for incoming data */
  556         priv->so->so_upcallarg = (caddr_t)node;
  557         priv->so->so_upcall = ng_ksocket_incoming;
  558         priv->so->so_rcv.sb_flags |= SB_UPCALL;
  559 
  560         /* OK */
  561         priv->hook = hook;
  562         return (0);
  563 }
  564 
  565 /*
  566  * Receive a control message
  567  */
  568 static int
  569 ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
  570               const char *raddr, struct ng_mesg **rptr)
  571 {
  572         struct proc *p = curproc ? curproc : &proc0;    /* XXX broken */
  573         const priv_p priv = node->private;
  574         struct socket *const so = priv->so;
  575         struct ng_mesg *resp = NULL;
  576         int error = 0;
  577 
  578         switch (msg->header.typecookie) {
  579         case NGM_KSOCKET_COOKIE:
  580                 switch (msg->header.cmd) {
  581                 case NGM_KSOCKET_BIND:
  582                     {
  583                         struct sockaddr *const sa
  584                             = (struct sockaddr *)msg->data;
  585 
  586                         /* Sanity check */
  587                         if (msg->header.arglen < SADATA_OFFSET
  588                             || msg->header.arglen < sa->sa_len)
  589                                 ERROUT(EINVAL);
  590                         if (so == NULL)
  591                                 ERROUT(ENXIO);
  592 
  593                         /* Bind */
  594                         error = sobind(so, sa, p);
  595                         break;
  596                     }
  597                 case NGM_KSOCKET_LISTEN:
  598                     {
  599                         /* Sanity check */
  600                         if (msg->header.arglen != sizeof(int))
  601                                 ERROUT(EINVAL);
  602                         if (so == NULL)
  603                                 ERROUT(ENXIO);
  604 
  605                         /* Listen */
  606                         if ((error = solisten(so, *((int *)msg->data), p)) != 0)
  607                                 break;
  608 
  609                         /* Notify sender when we get a connection attempt */
  610                                 /* XXX implement me */
  611                         error = ENODEV;
  612                         break;
  613                     }
  614 
  615                 case NGM_KSOCKET_ACCEPT:
  616                     {
  617                         /* Sanity check */
  618                         if (msg->header.arglen != 0)
  619                                 ERROUT(EINVAL);
  620                         if (so == NULL)
  621                                 ERROUT(ENXIO);
  622 
  623                         /* Accept on the socket in a non-blocking way */
  624                         /* Create a new ksocket node for the new connection */
  625                         /* Return a response with the peer's sockaddr and
  626                            the absolute name of the newly created node */
  627                            
  628                                 /* XXX implement me */
  629 
  630                         error = ENODEV;
  631                         break;
  632                     }
  633 
  634                 case NGM_KSOCKET_CONNECT:
  635                     {
  636                         struct sockaddr *const sa
  637                             = (struct sockaddr *)msg->data;
  638 
  639                         /* Sanity check */
  640                         if (msg->header.arglen < SADATA_OFFSET
  641                             || msg->header.arglen < sa->sa_len)
  642                                 ERROUT(EINVAL);
  643                         if (so == NULL)
  644                                 ERROUT(ENXIO);
  645 
  646                         /* Do connect */
  647                         if ((so->so_state & SS_ISCONNECTING) != 0)
  648                                 ERROUT(EALREADY);
  649                         if ((error = soconnect(so, sa, p)) != 0) {
  650                                 so->so_state &= ~SS_ISCONNECTING;
  651                                 ERROUT(error);
  652                         }
  653                         if ((so->so_state & SS_ISCONNECTING) != 0)
  654                                 /* Notify sender when we connect */
  655                                 /* XXX implement me */
  656                                 ERROUT(EINPROGRESS);
  657                         break;
  658                     }
  659 
  660                 case NGM_KSOCKET_GETNAME:
  661                 case NGM_KSOCKET_GETPEERNAME:
  662                     {
  663                         int (*func)(struct socket *so, struct sockaddr **nam);
  664                         struct sockaddr *sa = NULL;
  665                         int len;
  666 
  667                         /* Sanity check */
  668                         if (msg->header.arglen != 0)
  669                                 ERROUT(EINVAL);
  670                         if (so == NULL)
  671                                 ERROUT(ENXIO);
  672 
  673                         /* Get function */
  674                         if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
  675                                 if ((so->so_state
  676                                     & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) 
  677                                         ERROUT(ENOTCONN);
  678                                 func = so->so_proto->pr_usrreqs->pru_peeraddr;
  679                         } else
  680                                 func = so->so_proto->pr_usrreqs->pru_sockaddr;
  681 
  682                         /* Get local or peer address */
  683                         if ((error = (*func)(so, &sa)) != 0)
  684                                 goto bail;
  685                         len = (sa == NULL) ? 0 : sa->sa_len;
  686 
  687                         /* Send it back in a response */
  688                         NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
  689                         if (resp == NULL) {
  690                                 error = ENOMEM;
  691                                 goto bail;
  692                         }
  693                         bcopy(sa, resp->data, len);
  694 
  695                 bail:
  696                         /* Cleanup */
  697                         if (sa != NULL)
  698                                 FREE(sa, M_SONAME);
  699                         break;
  700                     }
  701 
  702                 case NGM_KSOCKET_GETOPT:
  703                     {
  704                         struct ng_ksocket_sockopt *ksopt = 
  705                             (struct ng_ksocket_sockopt *)msg->data;
  706                         struct sockopt sopt;
  707 
  708                         /* Sanity check */
  709                         if (msg->header.arglen != sizeof(*ksopt))
  710                                 ERROUT(EINVAL);
  711                         if (so == NULL)
  712                                 ERROUT(ENXIO);
  713 
  714                         /* Get response with room for option value */
  715                         NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
  716                             + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
  717                         if (resp == NULL)
  718                                 ERROUT(ENOMEM);
  719 
  720                         /* Get socket option, and put value in the response */
  721                         sopt.sopt_dir = SOPT_GET;
  722                         sopt.sopt_level = ksopt->level;
  723                         sopt.sopt_name = ksopt->name;
  724                         sopt.sopt_p = p;
  725                         sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
  726                         ksopt = (struct ng_ksocket_sockopt *)resp->data;
  727                         sopt.sopt_val = ksopt->value;
  728                         if ((error = sogetopt(so, &sopt)) != 0) {
  729                                 FREE(resp, M_NETGRAPH);
  730                                 break;
  731                         }
  732 
  733                         /* Set actual value length */
  734                         resp->header.arglen = sizeof(*ksopt)
  735                             + sopt.sopt_valsize;
  736                         break;
  737                     }
  738 
  739                 case NGM_KSOCKET_SETOPT:
  740                     {
  741                         struct ng_ksocket_sockopt *const ksopt = 
  742                             (struct ng_ksocket_sockopt *)msg->data;
  743                         const int valsize = msg->header.arglen - sizeof(*ksopt);
  744                         struct sockopt sopt;
  745 
  746                         /* Sanity check */
  747                         if (valsize < 0)
  748                                 ERROUT(EINVAL);
  749                         if (so == NULL)
  750                                 ERROUT(ENXIO);
  751 
  752                         /* Set socket option */
  753                         sopt.sopt_dir = SOPT_SET;
  754                         sopt.sopt_level = ksopt->level;
  755                         sopt.sopt_name = ksopt->name;
  756                         sopt.sopt_val = ksopt->value;
  757                         sopt.sopt_valsize = valsize;
  758                         sopt.sopt_p = p;
  759                         error = sosetopt(so, &sopt);
  760                         break;
  761                     }
  762 
  763                 default:
  764                         error = EINVAL;
  765                         break;
  766                 }
  767                 break;
  768         default:
  769                 error = EINVAL;
  770                 break;
  771         }
  772         if (rptr)
  773                 *rptr = resp;
  774         else if (resp)
  775                 FREE(resp, M_NETGRAPH);
  776 
  777 done:
  778         FREE(msg, M_NETGRAPH);
  779         return (error);
  780 }
  781 
  782 /*
  783  * Receive incoming data on our hook.  Send it out the socket.
  784  */
  785 static int
  786 ng_ksocket_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
  787 {
  788         struct proc *p = curproc ? curproc : &proc0;    /* XXX broken */
  789         const node_p node = hook->node;
  790         const priv_p priv = node->private;
  791         struct socket *const so = priv->so;
  792         int error;
  793 
  794         NG_FREE_META(meta);
  795         error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, 0, 0, m, 0, 0, p);
  796         return (error);
  797 }
  798 
  799 /*
  800  * Destroy node
  801  */
  802 static int
  803 ng_ksocket_rmnode(node_p node)
  804 {
  805         const priv_p priv = node->private;
  806 
  807         /* Close our socket (if any) */
  808         if (priv->so != NULL) {
  809 
  810                 priv->so->so_upcall = NULL;
  811                 priv->so->so_rcv.sb_flags &= ~SB_UPCALL;
  812                 soclose(priv->so);
  813                 priv->so = NULL;
  814         }
  815 
  816         /* Take down netgraph node */
  817         node->flags |= NG_INVALID;
  818         ng_cutlinks(node);
  819         ng_unname(node);
  820         bzero(priv, sizeof(*priv));
  821         FREE(priv, M_NETGRAPH);
  822         node->private = NULL;
  823         ng_unref(node);         /* let the node escape */
  824         return (0);
  825 }
  826 
  827 /*
  828  * Hook disconnection
  829  */
  830 static int
  831 ng_ksocket_disconnect(hook_p hook)
  832 {
  833         KASSERT(hook->node->numhooks == 0,
  834             ("%s: numhooks=%d?", __FUNCTION__, hook->node->numhooks));
  835         ng_rmnode(hook->node);
  836         return (0);
  837 }
  838 
  839 /************************************************************************
  840                         HELPER STUFF
  841  ************************************************************************/
  842 
  843 /*
  844  * When incoming data is appended to the socket, we get notified here.
  845  */
  846 static void
  847 ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
  848 {
  849         const node_p node = arg;
  850         const priv_p priv = node->private;
  851         meta_p meta = NULL;
  852         struct sockaddr *nam;
  853         struct mbuf *m;
  854         struct uio auio;
  855         int s, flags, error;
  856 
  857         s = splnet();
  858 
  859         /* Sanity check */
  860         if ((node->flags & NG_INVALID) != 0) {
  861                 splx(s);
  862                 return;
  863         }
  864         KASSERT(so == priv->so, ("%s: wrong socket", __FUNCTION__));
  865         KASSERT(priv->hook != NULL, ("%s: no hook", __FUNCTION__));
  866 
  867         /* Read and forward available mbuf's */
  868         auio.uio_procp = NULL;
  869         auio.uio_resid = 1000000000;
  870         flags = MSG_DONTWAIT;
  871         do {
  872                 if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
  873                       (so, &nam, &auio, &m, (struct mbuf **)0, &flags)) == 0
  874                     && m != NULL) {
  875                         struct mbuf *n;
  876 
  877                         /* Don't trust the various socket layers to get the
  878                            packet header and length correct (eg. kern/15175) */
  879                         for (n = m, m->m_pkthdr.len = 0; n; n = n->m_next)
  880                                 m->m_pkthdr.len += n->m_len;
  881                         NG_SEND_DATA(error, priv->hook, m, meta);
  882                 }
  883         } while (error == 0 && m != NULL);
  884         splx(s);
  885 }
  886 
  887 /*
  888  * Parse out either an integer value or an alias.
  889  */
  890 static int
  891 ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
  892         const char *s, int family)
  893 {
  894         int k, val;
  895         char *eptr;
  896 
  897         /* Try aliases */
  898         for (k = 0; aliases[k].name != NULL; k++) {
  899                 if (strcmp(s, aliases[k].name) == 0
  900                     && aliases[k].family == family)
  901                         return aliases[k].value;
  902         }
  903 
  904         /* Try parsing as a number */
  905         val = (int)strtoul(s, &eptr, 10);
  906         if (val < 0 || *eptr != '\0')
  907                 return (-1);
  908         return (val);
  909 }
  910 

Cache object: a8859b203806bb1b319ff77c1b5c0298


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