149191e0fSNuno Antunes /*
249191e0fSNuno Antunes * ng_ksocket.c
349191e0fSNuno Antunes */
449191e0fSNuno Antunes
549191e0fSNuno Antunes /*-
649191e0fSNuno Antunes * Copyright (c) 1996-1999 Whistle Communications, Inc.
749191e0fSNuno Antunes * All rights reserved.
849191e0fSNuno Antunes *
949191e0fSNuno Antunes * Subject to the following obligations and disclaimer of warranty, use and
1049191e0fSNuno Antunes * redistribution of this software, in source or object code forms, with or
1149191e0fSNuno Antunes * without modifications are expressly permitted by Whistle Communications;
1249191e0fSNuno Antunes * provided, however, that:
1349191e0fSNuno Antunes * 1. Any and all reproductions of the source or object code must include the
1449191e0fSNuno Antunes * copyright notice above and the following disclaimer of warranties; and
1549191e0fSNuno Antunes * 2. No rights are granted, in any manner or form, to use Whistle
1649191e0fSNuno Antunes * Communications, Inc. trademarks, including the mark "WHISTLE
1749191e0fSNuno Antunes * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1849191e0fSNuno Antunes * such appears in the above copyright notice or in the software.
1949191e0fSNuno Antunes *
2049191e0fSNuno Antunes * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2149191e0fSNuno Antunes * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2249191e0fSNuno Antunes * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2349191e0fSNuno Antunes * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2449191e0fSNuno Antunes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2549191e0fSNuno Antunes * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2649191e0fSNuno Antunes * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2749191e0fSNuno Antunes * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2849191e0fSNuno Antunes * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2949191e0fSNuno Antunes * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
3049191e0fSNuno Antunes * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3149191e0fSNuno Antunes * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3249191e0fSNuno Antunes * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3349191e0fSNuno Antunes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3449191e0fSNuno Antunes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3549191e0fSNuno Antunes * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3649191e0fSNuno Antunes * OF SUCH DAMAGE.
3749191e0fSNuno Antunes *
3849191e0fSNuno Antunes * Author: Archie Cobbs <archie@freebsd.org>
3949191e0fSNuno Antunes *
4049191e0fSNuno Antunes * $FreeBSD: src/sys/netgraph/ng_ksocket.c,v 1.61 2008/03/07 21:12:56 mav Exp $
4149191e0fSNuno Antunes * $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $
4249191e0fSNuno Antunes */
4349191e0fSNuno Antunes
4449191e0fSNuno Antunes /*
4549191e0fSNuno Antunes * Kernel socket node type. This node type is basically a kernel-mode
4649191e0fSNuno Antunes * version of a socket... kindof like the reverse of the socket node type.
4749191e0fSNuno Antunes */
4849191e0fSNuno Antunes
4949191e0fSNuno Antunes #include <sys/param.h>
5049191e0fSNuno Antunes #include <sys/systm.h>
5149191e0fSNuno Antunes #include <sys/kernel.h>
5249191e0fSNuno Antunes #include <sys/mbuf.h>
5349191e0fSNuno Antunes #include <sys/proc.h>
5449191e0fSNuno Antunes #include <sys/malloc.h>
5549191e0fSNuno Antunes #include <sys/ctype.h>
5649191e0fSNuno Antunes #include <sys/protosw.h>
5749191e0fSNuno Antunes #include <sys/errno.h>
58*22c1d6caSSascha Wildner #include <sys/fcntl.h>
5949191e0fSNuno Antunes #include <sys/socket.h>
60e858b308SNuno Antunes #include <sys/socketops.h>
6149191e0fSNuno Antunes #include <sys/socketvar.h>
62a48a177fSNuno Antunes #include <sys/socketvar2.h>
6349191e0fSNuno Antunes #include <sys/thread2.h>
6449191e0fSNuno Antunes #include <sys/uio.h>
6549191e0fSNuno Antunes #include <sys/un.h>
6649191e0fSNuno Antunes
6749191e0fSNuno Antunes #include <netgraph7/ng_message.h>
6849191e0fSNuno Antunes #include <netgraph7/netgraph.h>
6949191e0fSNuno Antunes #include <netgraph7/ng_parse.h>
7049191e0fSNuno Antunes #include "ng_ksocket.h"
7149191e0fSNuno Antunes
7249191e0fSNuno Antunes #include <netinet/in.h>
7349191e0fSNuno Antunes
7449191e0fSNuno Antunes #ifdef NG_SEPARATE_MALLOC
7549191e0fSNuno Antunes MALLOC_DEFINE(M_NETGRAPH_KSOCKET, "netgraph_ksock", "netgraph ksock node ");
7649191e0fSNuno Antunes #else
7749191e0fSNuno Antunes #define M_NETGRAPH_KSOCKET M_NETGRAPH
7849191e0fSNuno Antunes #endif
7949191e0fSNuno Antunes
8049191e0fSNuno Antunes #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
8149191e0fSNuno Antunes #define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data))
8249191e0fSNuno Antunes
8349191e0fSNuno Antunes /* Node private data */
8449191e0fSNuno Antunes struct ng_ksocket_private {
8549191e0fSNuno Antunes node_p node;
8649191e0fSNuno Antunes hook_p hook;
8749191e0fSNuno Antunes struct socket *so;
8849191e0fSNuno Antunes int fn_sent; /* FN call on incoming event was sent */
8949191e0fSNuno Antunes LIST_HEAD(, ng_ksocket_private) embryos;
9049191e0fSNuno Antunes LIST_ENTRY(ng_ksocket_private) siblings;
9149191e0fSNuno Antunes u_int32_t flags;
9249191e0fSNuno Antunes u_int32_t response_token;
9349191e0fSNuno Antunes ng_ID_t response_addr;
9449191e0fSNuno Antunes };
9549191e0fSNuno Antunes typedef struct ng_ksocket_private *priv_p;
9649191e0fSNuno Antunes
9749191e0fSNuno Antunes /* Flags for priv_p */
9849191e0fSNuno Antunes #define KSF_CONNECTING 0x00000001 /* Waiting for connection complete */
9949191e0fSNuno Antunes #define KSF_ACCEPTING 0x00000002 /* Waiting for accept complete */
10049191e0fSNuno Antunes #define KSF_EOFSEEN 0x00000004 /* Have sent 0-length EOF mbuf */
10149191e0fSNuno Antunes #define KSF_CLONED 0x00000008 /* Cloned from an accepting socket */
10249191e0fSNuno Antunes #define KSF_EMBRYONIC 0x00000010 /* Cloned node with no hooks yet */
10349191e0fSNuno Antunes
10449191e0fSNuno Antunes /* Netgraph node methods */
10549191e0fSNuno Antunes static ng_constructor_t ng_ksocket_constructor;
10649191e0fSNuno Antunes static ng_rcvmsg_t ng_ksocket_rcvmsg;
10749191e0fSNuno Antunes static ng_shutdown_t ng_ksocket_shutdown;
10849191e0fSNuno Antunes static ng_newhook_t ng_ksocket_newhook;
10949191e0fSNuno Antunes static ng_rcvdata_t ng_ksocket_rcvdata;
11049191e0fSNuno Antunes static ng_connect_t ng_ksocket_connect;
11149191e0fSNuno Antunes static ng_disconnect_t ng_ksocket_disconnect;
11249191e0fSNuno Antunes
11349191e0fSNuno Antunes /* Alias structure */
11449191e0fSNuno Antunes struct ng_ksocket_alias {
11549191e0fSNuno Antunes const char *name;
11649191e0fSNuno Antunes const int value;
11749191e0fSNuno Antunes const int family;
11849191e0fSNuno Antunes };
11949191e0fSNuno Antunes
12049191e0fSNuno Antunes /* Protocol family aliases */
12149191e0fSNuno Antunes static const struct ng_ksocket_alias ng_ksocket_families[] = {
12249191e0fSNuno Antunes { "local", PF_LOCAL },
12349191e0fSNuno Antunes { "inet", PF_INET },
12449191e0fSNuno Antunes { "inet6", PF_INET6 },
12549191e0fSNuno Antunes { "atm", PF_ATM },
12649191e0fSNuno Antunes { NULL, -1 },
12749191e0fSNuno Antunes };
12849191e0fSNuno Antunes
12949191e0fSNuno Antunes /* Socket type aliases */
13049191e0fSNuno Antunes static const struct ng_ksocket_alias ng_ksocket_types[] = {
13149191e0fSNuno Antunes { "stream", SOCK_STREAM },
13249191e0fSNuno Antunes { "dgram", SOCK_DGRAM },
13349191e0fSNuno Antunes { "raw", SOCK_RAW },
13449191e0fSNuno Antunes { "rdm", SOCK_RDM },
13549191e0fSNuno Antunes { "seqpacket", SOCK_SEQPACKET },
13649191e0fSNuno Antunes { NULL, -1 },
13749191e0fSNuno Antunes };
13849191e0fSNuno Antunes
13949191e0fSNuno Antunes /* Protocol aliases */
14049191e0fSNuno Antunes static const struct ng_ksocket_alias ng_ksocket_protos[] = {
14149191e0fSNuno Antunes { "ip", IPPROTO_IP, PF_INET },
14249191e0fSNuno Antunes { "raw", IPPROTO_RAW, PF_INET },
14349191e0fSNuno Antunes { "icmp", IPPROTO_ICMP, PF_INET },
14449191e0fSNuno Antunes { "igmp", IPPROTO_IGMP, PF_INET },
14549191e0fSNuno Antunes { "tcp", IPPROTO_TCP, PF_INET },
14649191e0fSNuno Antunes { "udp", IPPROTO_UDP, PF_INET },
14749191e0fSNuno Antunes { "gre", IPPROTO_GRE, PF_INET },
14849191e0fSNuno Antunes { "esp", IPPROTO_ESP, PF_INET },
14949191e0fSNuno Antunes { "ah", IPPROTO_AH, PF_INET },
15049191e0fSNuno Antunes { "swipe", IPPROTO_SWIPE, PF_INET },
15149191e0fSNuno Antunes { "encap", IPPROTO_ENCAP, PF_INET },
15249191e0fSNuno Antunes { "divert", IPPROTO_DIVERT, PF_INET },
15349191e0fSNuno Antunes { "pim", IPPROTO_PIM, PF_INET },
15449191e0fSNuno Antunes { NULL, -1 },
15549191e0fSNuno Antunes };
15649191e0fSNuno Antunes
15749191e0fSNuno Antunes /* Helper functions */
15849191e0fSNuno Antunes static int ng_ksocket_check_accept(priv_p);
15949191e0fSNuno Antunes static void ng_ksocket_finish_accept(priv_p);
16049191e0fSNuno Antunes static void ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
16149191e0fSNuno Antunes static int ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
16249191e0fSNuno Antunes const char *s, int family);
16349191e0fSNuno Antunes static void ng_ksocket_incoming2(node_p node, hook_p hook,
16449191e0fSNuno Antunes void *arg1, int arg2);
16549191e0fSNuno Antunes
16649191e0fSNuno Antunes /************************************************************************
16749191e0fSNuno Antunes STRUCT SOCKADDR PARSE TYPE
16849191e0fSNuno Antunes ************************************************************************/
16949191e0fSNuno Antunes
17049191e0fSNuno Antunes /* Get the length of the data portion of a generic struct sockaddr */
17149191e0fSNuno Antunes static int
ng_parse_generic_sockdata_getLength(const struct ng_parse_type * type,const u_char * start,const u_char * buf)17249191e0fSNuno Antunes ng_parse_generic_sockdata_getLength(const struct ng_parse_type *type,
17349191e0fSNuno Antunes const u_char *start, const u_char *buf)
17449191e0fSNuno Antunes {
17549191e0fSNuno Antunes const struct sockaddr *sa;
17649191e0fSNuno Antunes
17749191e0fSNuno Antunes sa = (const struct sockaddr *)(buf - SADATA_OFFSET);
17849191e0fSNuno Antunes return (sa->sa_len < SADATA_OFFSET) ? 0 : sa->sa_len - SADATA_OFFSET;
17949191e0fSNuno Antunes }
18049191e0fSNuno Antunes
18149191e0fSNuno Antunes /* Type for the variable length data portion of a generic struct sockaddr */
18249191e0fSNuno Antunes static const struct ng_parse_type ng_ksocket_generic_sockdata_type = {
18349191e0fSNuno Antunes &ng_parse_bytearray_type,
18449191e0fSNuno Antunes &ng_parse_generic_sockdata_getLength
18549191e0fSNuno Antunes };
18649191e0fSNuno Antunes
18749191e0fSNuno Antunes /* Type for a generic struct sockaddr */
18849191e0fSNuno Antunes static const struct ng_parse_struct_field
18949191e0fSNuno Antunes ng_parse_generic_sockaddr_type_fields[] = {
19049191e0fSNuno Antunes { "len", &ng_parse_uint8_type },
19149191e0fSNuno Antunes { "family", &ng_parse_uint8_type },
19249191e0fSNuno Antunes { "data", &ng_ksocket_generic_sockdata_type },
19349191e0fSNuno Antunes { NULL }
19449191e0fSNuno Antunes };
19549191e0fSNuno Antunes static const struct ng_parse_type ng_ksocket_generic_sockaddr_type = {
19649191e0fSNuno Antunes &ng_parse_struct_type,
19749191e0fSNuno Antunes &ng_parse_generic_sockaddr_type_fields
19849191e0fSNuno Antunes };
19949191e0fSNuno Antunes
20049191e0fSNuno Antunes /* Convert a struct sockaddr from ASCII to binary. If its a protocol
20149191e0fSNuno Antunes family that we specially handle, do that, otherwise defer to the
20249191e0fSNuno Antunes generic parse type ng_ksocket_generic_sockaddr_type. */
20349191e0fSNuno Antunes static int
ng_ksocket_sockaddr_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)20449191e0fSNuno Antunes ng_ksocket_sockaddr_parse(const struct ng_parse_type *type,
20549191e0fSNuno Antunes const char *s, int *off, const u_char *const start,
20649191e0fSNuno Antunes u_char *const buf, int *buflen)
20749191e0fSNuno Antunes {
20849191e0fSNuno Antunes struct sockaddr *const sa = (struct sockaddr *)buf;
20949191e0fSNuno Antunes enum ng_parse_token tok;
21049191e0fSNuno Antunes char fambuf[32];
21149191e0fSNuno Antunes int family, len;
21249191e0fSNuno Antunes char *t;
21349191e0fSNuno Antunes
21449191e0fSNuno Antunes /* If next token is a left curly brace, use generic parse type */
21549191e0fSNuno Antunes if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) {
21649191e0fSNuno Antunes return (*ng_ksocket_generic_sockaddr_type.supertype->parse)
21749191e0fSNuno Antunes (&ng_ksocket_generic_sockaddr_type,
21849191e0fSNuno Antunes s, off, start, buf, buflen);
21949191e0fSNuno Antunes }
22049191e0fSNuno Antunes
22149191e0fSNuno Antunes /* Get socket address family followed by a slash */
22249191e0fSNuno Antunes while (isspace(s[*off]))
22349191e0fSNuno Antunes (*off)++;
22449191e0fSNuno Antunes if ((t = index(s + *off, '/')) == NULL)
22549191e0fSNuno Antunes return (EINVAL);
22649191e0fSNuno Antunes if ((len = t - (s + *off)) > sizeof(fambuf) - 1)
22749191e0fSNuno Antunes return (EINVAL);
22849191e0fSNuno Antunes strncpy(fambuf, s + *off, len);
22949191e0fSNuno Antunes fambuf[len] = '\0';
23049191e0fSNuno Antunes *off += len + 1;
23149191e0fSNuno Antunes if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1)
23249191e0fSNuno Antunes return (EINVAL);
23349191e0fSNuno Antunes
23449191e0fSNuno Antunes /* Set family */
23549191e0fSNuno Antunes if (*buflen < SADATA_OFFSET)
23649191e0fSNuno Antunes return (ERANGE);
23749191e0fSNuno Antunes sa->sa_family = family;
23849191e0fSNuno Antunes
23949191e0fSNuno Antunes /* Set family-specific data and length */
24049191e0fSNuno Antunes switch (sa->sa_family) {
24149191e0fSNuno Antunes case PF_LOCAL: /* Get pathname */
24249191e0fSNuno Antunes {
24349191e0fSNuno Antunes const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
24449191e0fSNuno Antunes struct sockaddr_un *const sun = (struct sockaddr_un *)sa;
24549191e0fSNuno Antunes int toklen, pathlen;
24649191e0fSNuno Antunes char *path;
24749191e0fSNuno Antunes
24849191e0fSNuno Antunes if ((path = ng_get_string_token(s, off, &toklen, NULL)) == NULL)
24949191e0fSNuno Antunes return (EINVAL);
25049191e0fSNuno Antunes pathlen = strlen(path);
25149191e0fSNuno Antunes if (pathlen > SOCK_MAXADDRLEN) {
25249191e0fSNuno Antunes kfree(path, M_NETGRAPH_KSOCKET);
25349191e0fSNuno Antunes return (E2BIG);
25449191e0fSNuno Antunes }
25549191e0fSNuno Antunes if (*buflen < pathoff + pathlen) {
25649191e0fSNuno Antunes kfree(path, M_NETGRAPH_KSOCKET);
25749191e0fSNuno Antunes return (ERANGE);
25849191e0fSNuno Antunes }
25949191e0fSNuno Antunes *off += toklen;
26049191e0fSNuno Antunes bcopy(path, sun->sun_path, pathlen);
26149191e0fSNuno Antunes sun->sun_len = pathoff + pathlen;
26249191e0fSNuno Antunes kfree(path, M_NETGRAPH_KSOCKET);
26349191e0fSNuno Antunes break;
26449191e0fSNuno Antunes }
26549191e0fSNuno Antunes
26649191e0fSNuno Antunes case PF_INET: /* Get an IP address with optional port */
26749191e0fSNuno Antunes {
26849191e0fSNuno Antunes struct sockaddr_in *const sin = (struct sockaddr_in *)sa;
26949191e0fSNuno Antunes int i;
27049191e0fSNuno Antunes
27149191e0fSNuno Antunes /* Parse this: <ipaddress>[:port] */
27249191e0fSNuno Antunes for (i = 0; i < 4; i++) {
27349191e0fSNuno Antunes u_long val;
27449191e0fSNuno Antunes char *eptr;
27549191e0fSNuno Antunes
27649191e0fSNuno Antunes val = strtoul(s + *off, &eptr, 10);
27749191e0fSNuno Antunes if (val > 0xff || eptr == s + *off)
27849191e0fSNuno Antunes return (EINVAL);
27949191e0fSNuno Antunes *off += (eptr - (s + *off));
28049191e0fSNuno Antunes ((u_char *)&sin->sin_addr)[i] = (u_char)val;
28149191e0fSNuno Antunes if (i < 3) {
28249191e0fSNuno Antunes if (s[*off] != '.')
28349191e0fSNuno Antunes return (EINVAL);
28449191e0fSNuno Antunes (*off)++;
28549191e0fSNuno Antunes } else if (s[*off] == ':') {
28649191e0fSNuno Antunes (*off)++;
28749191e0fSNuno Antunes val = strtoul(s + *off, &eptr, 10);
28849191e0fSNuno Antunes if (val > 0xffff || eptr == s + *off)
28949191e0fSNuno Antunes return (EINVAL);
29049191e0fSNuno Antunes *off += (eptr - (s + *off));
29149191e0fSNuno Antunes sin->sin_port = htons(val);
29249191e0fSNuno Antunes } else
29349191e0fSNuno Antunes sin->sin_port = 0;
29449191e0fSNuno Antunes }
29549191e0fSNuno Antunes bzero(&sin->sin_zero, sizeof(sin->sin_zero));
29649191e0fSNuno Antunes sin->sin_len = sizeof(*sin);
29749191e0fSNuno Antunes break;
29849191e0fSNuno Antunes }
29949191e0fSNuno Antunes
30049191e0fSNuno Antunes #if 0
30149191e0fSNuno Antunes case PF_INET6:
30249191e0fSNuno Antunes #endif
30349191e0fSNuno Antunes
30449191e0fSNuno Antunes default:
30549191e0fSNuno Antunes return (EINVAL);
30649191e0fSNuno Antunes }
30749191e0fSNuno Antunes
30849191e0fSNuno Antunes /* Done */
30949191e0fSNuno Antunes *buflen = sa->sa_len;
31049191e0fSNuno Antunes return (0);
31149191e0fSNuno Antunes }
31249191e0fSNuno Antunes
31349191e0fSNuno Antunes /* Convert a struct sockaddr from binary to ASCII */
31449191e0fSNuno Antunes static int
ng_ksocket_sockaddr_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)31549191e0fSNuno Antunes ng_ksocket_sockaddr_unparse(const struct ng_parse_type *type,
31649191e0fSNuno Antunes const u_char *data, int *off, char *cbuf, int cbuflen)
31749191e0fSNuno Antunes {
31849191e0fSNuno Antunes const struct sockaddr *sa = (const struct sockaddr *)(data + *off);
31949191e0fSNuno Antunes int slen = 0;
32049191e0fSNuno Antunes
32149191e0fSNuno Antunes /* Output socket address, either in special or generic format */
32249191e0fSNuno Antunes switch (sa->sa_family) {
32349191e0fSNuno Antunes case PF_LOCAL:
32449191e0fSNuno Antunes {
32549191e0fSNuno Antunes const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
32649191e0fSNuno Antunes const struct sockaddr_un *sun = (const struct sockaddr_un *)sa;
32749191e0fSNuno Antunes const int pathlen = sun->sun_len - pathoff;
32849191e0fSNuno Antunes char pathbuf[SOCK_MAXADDRLEN + 1];
32949191e0fSNuno Antunes char *pathtoken;
33049191e0fSNuno Antunes
33149191e0fSNuno Antunes bcopy(sun->sun_path, pathbuf, pathlen);
33249191e0fSNuno Antunes if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL)
33349191e0fSNuno Antunes return (ENOMEM);
33449191e0fSNuno Antunes slen += ksnprintf(cbuf, cbuflen, "local/%s", pathtoken);
33549191e0fSNuno Antunes kfree(pathtoken, M_NETGRAPH_KSOCKET);
33649191e0fSNuno Antunes if (slen >= cbuflen)
33749191e0fSNuno Antunes return (ERANGE);
33849191e0fSNuno Antunes *off += sun->sun_len;
33949191e0fSNuno Antunes return (0);
34049191e0fSNuno Antunes }
34149191e0fSNuno Antunes
34249191e0fSNuno Antunes case PF_INET:
34349191e0fSNuno Antunes {
34449191e0fSNuno Antunes const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
34549191e0fSNuno Antunes
34649191e0fSNuno Antunes slen += ksnprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d",
34749191e0fSNuno Antunes ((const u_char *)&sin->sin_addr)[0],
34849191e0fSNuno Antunes ((const u_char *)&sin->sin_addr)[1],
34949191e0fSNuno Antunes ((const u_char *)&sin->sin_addr)[2],
35049191e0fSNuno Antunes ((const u_char *)&sin->sin_addr)[3]);
35149191e0fSNuno Antunes if (sin->sin_port != 0) {
35249191e0fSNuno Antunes slen += ksnprintf(cbuf + strlen(cbuf),
35349191e0fSNuno Antunes cbuflen - strlen(cbuf), ":%d",
35449191e0fSNuno Antunes (u_int)ntohs(sin->sin_port));
35549191e0fSNuno Antunes }
35649191e0fSNuno Antunes if (slen >= cbuflen)
35749191e0fSNuno Antunes return (ERANGE);
35849191e0fSNuno Antunes *off += sizeof(*sin);
35949191e0fSNuno Antunes return(0);
36049191e0fSNuno Antunes }
36149191e0fSNuno Antunes
36249191e0fSNuno Antunes #if 0
36349191e0fSNuno Antunes case PF_INET6:
36449191e0fSNuno Antunes #endif
36549191e0fSNuno Antunes
36649191e0fSNuno Antunes default:
36749191e0fSNuno Antunes return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
36849191e0fSNuno Antunes (&ng_ksocket_generic_sockaddr_type,
36949191e0fSNuno Antunes data, off, cbuf, cbuflen);
37049191e0fSNuno Antunes }
37149191e0fSNuno Antunes }
37249191e0fSNuno Antunes
37349191e0fSNuno Antunes /* Parse type for struct sockaddr */
37449191e0fSNuno Antunes static const struct ng_parse_type ng_ksocket_sockaddr_type = {
37549191e0fSNuno Antunes NULL,
37649191e0fSNuno Antunes NULL,
37749191e0fSNuno Antunes NULL,
37849191e0fSNuno Antunes &ng_ksocket_sockaddr_parse,
37949191e0fSNuno Antunes &ng_ksocket_sockaddr_unparse,
38049191e0fSNuno Antunes NULL /* no such thing as a default struct sockaddr */
38149191e0fSNuno Antunes };
38249191e0fSNuno Antunes
38349191e0fSNuno Antunes /************************************************************************
38449191e0fSNuno Antunes STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
38549191e0fSNuno Antunes ************************************************************************/
38649191e0fSNuno Antunes
38749191e0fSNuno Antunes /* Get length of the struct ng_ksocket_sockopt value field, which is the
38849191e0fSNuno Antunes just the excess of the message argument portion over the length of
38949191e0fSNuno Antunes the struct ng_ksocket_sockopt. */
39049191e0fSNuno Antunes static int
ng_parse_sockoptval_getLength(const struct ng_parse_type * type,const u_char * start,const u_char * buf)39149191e0fSNuno Antunes ng_parse_sockoptval_getLength(const struct ng_parse_type *type,
39249191e0fSNuno Antunes const u_char *start, const u_char *buf)
39349191e0fSNuno Antunes {
39449191e0fSNuno Antunes static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
39549191e0fSNuno Antunes const struct ng_ksocket_sockopt *sopt;
39649191e0fSNuno Antunes const struct ng_mesg *msg;
39749191e0fSNuno Antunes
39849191e0fSNuno Antunes sopt = (const struct ng_ksocket_sockopt *)(buf - offset);
39949191e0fSNuno Antunes msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg));
40049191e0fSNuno Antunes return msg->header.arglen - sizeof(*sopt);
40149191e0fSNuno Antunes }
40249191e0fSNuno Antunes
40349191e0fSNuno Antunes /* Parse type for the option value part of a struct ng_ksocket_sockopt
40449191e0fSNuno Antunes XXX Eventually, we should handle the different socket options specially.
40549191e0fSNuno Antunes XXX This would avoid byte order problems, eg an integer value of 1 is
40649191e0fSNuno Antunes XXX going to be "[1]" for little endian or "[3=1]" for big endian. */
40749191e0fSNuno Antunes static const struct ng_parse_type ng_ksocket_sockoptval_type = {
40849191e0fSNuno Antunes &ng_parse_bytearray_type,
40949191e0fSNuno Antunes &ng_parse_sockoptval_getLength
41049191e0fSNuno Antunes };
41149191e0fSNuno Antunes
41249191e0fSNuno Antunes /* Parse type for struct ng_ksocket_sockopt */
41349191e0fSNuno Antunes static const struct ng_parse_struct_field ng_ksocket_sockopt_type_fields[]
41449191e0fSNuno Antunes = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type);
41549191e0fSNuno Antunes static const struct ng_parse_type ng_ksocket_sockopt_type = {
41649191e0fSNuno Antunes &ng_parse_struct_type,
41749191e0fSNuno Antunes &ng_ksocket_sockopt_type_fields
41849191e0fSNuno Antunes };
41949191e0fSNuno Antunes
42049191e0fSNuno Antunes /* Parse type for struct ng_ksocket_accept */
42149191e0fSNuno Antunes static const struct ng_parse_struct_field ng_ksocket_accept_type_fields[]
42249191e0fSNuno Antunes = NGM_KSOCKET_ACCEPT_INFO;
42349191e0fSNuno Antunes static const struct ng_parse_type ng_ksocket_accept_type = {
42449191e0fSNuno Antunes &ng_parse_struct_type,
42549191e0fSNuno Antunes &ng_ksocket_accept_type_fields
42649191e0fSNuno Antunes };
42749191e0fSNuno Antunes
42849191e0fSNuno Antunes /* List of commands and how to convert arguments to/from ASCII */
42949191e0fSNuno Antunes static const struct ng_cmdlist ng_ksocket_cmds[] = {
43049191e0fSNuno Antunes {
43149191e0fSNuno Antunes NGM_KSOCKET_COOKIE,
43249191e0fSNuno Antunes NGM_KSOCKET_BIND,
43349191e0fSNuno Antunes "bind",
43449191e0fSNuno Antunes &ng_ksocket_sockaddr_type,
43549191e0fSNuno Antunes NULL
43649191e0fSNuno Antunes },
43749191e0fSNuno Antunes {
43849191e0fSNuno Antunes NGM_KSOCKET_COOKIE,
43949191e0fSNuno Antunes NGM_KSOCKET_LISTEN,
44049191e0fSNuno Antunes "listen",
44149191e0fSNuno Antunes &ng_parse_int32_type,
44249191e0fSNuno Antunes NULL
44349191e0fSNuno Antunes },
44449191e0fSNuno Antunes {
44549191e0fSNuno Antunes NGM_KSOCKET_COOKIE,
44649191e0fSNuno Antunes NGM_KSOCKET_ACCEPT,
44749191e0fSNuno Antunes "accept",
44849191e0fSNuno Antunes NULL,
44949191e0fSNuno Antunes &ng_ksocket_accept_type
45049191e0fSNuno Antunes },
45149191e0fSNuno Antunes {
45249191e0fSNuno Antunes NGM_KSOCKET_COOKIE,
45349191e0fSNuno Antunes NGM_KSOCKET_CONNECT,
45449191e0fSNuno Antunes "connect",
45549191e0fSNuno Antunes &ng_ksocket_sockaddr_type,
45649191e0fSNuno Antunes &ng_parse_int32_type
45749191e0fSNuno Antunes },
45849191e0fSNuno Antunes {
45949191e0fSNuno Antunes NGM_KSOCKET_COOKIE,
46049191e0fSNuno Antunes NGM_KSOCKET_GETNAME,
46149191e0fSNuno Antunes "getname",
46249191e0fSNuno Antunes NULL,
46349191e0fSNuno Antunes &ng_ksocket_sockaddr_type
46449191e0fSNuno Antunes },
46549191e0fSNuno Antunes {
46649191e0fSNuno Antunes NGM_KSOCKET_COOKIE,
46749191e0fSNuno Antunes NGM_KSOCKET_GETPEERNAME,
46849191e0fSNuno Antunes "getpeername",
46949191e0fSNuno Antunes NULL,
47049191e0fSNuno Antunes &ng_ksocket_sockaddr_type
47149191e0fSNuno Antunes },
47249191e0fSNuno Antunes {
47349191e0fSNuno Antunes NGM_KSOCKET_COOKIE,
47449191e0fSNuno Antunes NGM_KSOCKET_SETOPT,
47549191e0fSNuno Antunes "setopt",
47649191e0fSNuno Antunes &ng_ksocket_sockopt_type,
47749191e0fSNuno Antunes NULL
47849191e0fSNuno Antunes },
47949191e0fSNuno Antunes {
48049191e0fSNuno Antunes NGM_KSOCKET_COOKIE,
48149191e0fSNuno Antunes NGM_KSOCKET_GETOPT,
48249191e0fSNuno Antunes "getopt",
48349191e0fSNuno Antunes &ng_ksocket_sockopt_type,
48449191e0fSNuno Antunes &ng_ksocket_sockopt_type
48549191e0fSNuno Antunes },
48649191e0fSNuno Antunes { 0 }
48749191e0fSNuno Antunes };
48849191e0fSNuno Antunes
48949191e0fSNuno Antunes /* Node type descriptor */
49049191e0fSNuno Antunes static struct ng_type ng_ksocket_typestruct = {
49149191e0fSNuno Antunes .version = NG_ABI_VERSION,
49249191e0fSNuno Antunes .name = NG_KSOCKET_NODE_TYPE,
49349191e0fSNuno Antunes .constructor = ng_ksocket_constructor,
49449191e0fSNuno Antunes .rcvmsg = ng_ksocket_rcvmsg,
49549191e0fSNuno Antunes .shutdown = ng_ksocket_shutdown,
49649191e0fSNuno Antunes .newhook = ng_ksocket_newhook,
49749191e0fSNuno Antunes .connect = ng_ksocket_connect,
49849191e0fSNuno Antunes .rcvdata = ng_ksocket_rcvdata,
49949191e0fSNuno Antunes .disconnect = ng_ksocket_disconnect,
50049191e0fSNuno Antunes .cmdlist = ng_ksocket_cmds,
50149191e0fSNuno Antunes };
50249191e0fSNuno Antunes NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
50349191e0fSNuno Antunes
50449191e0fSNuno Antunes #define ERROUT(x) do { error = (x); goto done; } while (0)
50549191e0fSNuno Antunes
50649191e0fSNuno Antunes /************************************************************************
50749191e0fSNuno Antunes NETGRAPH NODE STUFF
50849191e0fSNuno Antunes ************************************************************************/
50949191e0fSNuno Antunes
51049191e0fSNuno Antunes /*
51149191e0fSNuno Antunes * Node type constructor
51249191e0fSNuno Antunes * The NODE part is assumed to be all set up.
51349191e0fSNuno Antunes * There is already a reference to the node for us.
51449191e0fSNuno Antunes */
51549191e0fSNuno Antunes static int
ng_ksocket_constructor(node_p node)51649191e0fSNuno Antunes ng_ksocket_constructor(node_p node)
51749191e0fSNuno Antunes {
51849191e0fSNuno Antunes priv_p priv;
51949191e0fSNuno Antunes
52049191e0fSNuno Antunes /* Allocate private structure */
52149191e0fSNuno Antunes priv = kmalloc(sizeof(*priv), M_NETGRAPH,
52249191e0fSNuno Antunes M_WAITOK | M_NULLOK | M_ZERO);
52349191e0fSNuno Antunes if (priv == NULL)
52449191e0fSNuno Antunes return (ENOMEM);
52549191e0fSNuno Antunes
52649191e0fSNuno Antunes LIST_INIT(&priv->embryos);
52749191e0fSNuno Antunes /* cross link them */
52849191e0fSNuno Antunes priv->node = node;
52949191e0fSNuno Antunes NG_NODE_SET_PRIVATE(node, priv);
53049191e0fSNuno Antunes
53149191e0fSNuno Antunes /* Done */
53249191e0fSNuno Antunes return (0);
53349191e0fSNuno Antunes }
53449191e0fSNuno Antunes
53549191e0fSNuno Antunes /*
53649191e0fSNuno Antunes * Give our OK for a hook to be added. The hook name is of the
53749191e0fSNuno Antunes * form "<family>/<type>/<proto>" where the three components may
53849191e0fSNuno Antunes * be decimal numbers or else aliases from the above lists.
53949191e0fSNuno Antunes *
54049191e0fSNuno Antunes * Connecting a hook amounts to opening the socket. Disconnecting
54149191e0fSNuno Antunes * the hook closes the socket and destroys the node as well.
54249191e0fSNuno Antunes */
54349191e0fSNuno Antunes static int
ng_ksocket_newhook(node_p node,hook_p hook,const char * name0)54449191e0fSNuno Antunes ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
54549191e0fSNuno Antunes {
54649191e0fSNuno Antunes struct thread *td = curthread->td_proc ? curthread : &thread0; /* XXX broken */
54749191e0fSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
54849191e0fSNuno Antunes char *s1, *s2, name[NG_HOOKSIZ];
54949191e0fSNuno Antunes int family, type, protocol, error;
55049191e0fSNuno Antunes
55149191e0fSNuno Antunes /* Check if we're already connected */
55249191e0fSNuno Antunes if (priv->hook != NULL)
55349191e0fSNuno Antunes return (EISCONN);
55449191e0fSNuno Antunes
55549191e0fSNuno Antunes if (priv->flags & KSF_CLONED) {
55649191e0fSNuno Antunes if (priv->flags & KSF_EMBRYONIC) {
55749191e0fSNuno Antunes /* Remove ourselves from our parent's embryo list */
55849191e0fSNuno Antunes LIST_REMOVE(priv, siblings);
55949191e0fSNuno Antunes priv->flags &= ~KSF_EMBRYONIC;
56049191e0fSNuno Antunes }
56149191e0fSNuno Antunes } else {
56249191e0fSNuno Antunes /* Extract family, type, and protocol from hook name */
56349191e0fSNuno Antunes ksnprintf(name, sizeof(name), "%s", name0);
56449191e0fSNuno Antunes s1 = name;
56549191e0fSNuno Antunes if ((s2 = index(s1, '/')) == NULL)
56649191e0fSNuno Antunes return (EINVAL);
56749191e0fSNuno Antunes *s2++ = '\0';
56849191e0fSNuno Antunes family = ng_ksocket_parse(ng_ksocket_families, s1, 0);
56949191e0fSNuno Antunes if (family == -1)
57049191e0fSNuno Antunes return (EINVAL);
57149191e0fSNuno Antunes s1 = s2;
57249191e0fSNuno Antunes if ((s2 = index(s1, '/')) == NULL)
57349191e0fSNuno Antunes return (EINVAL);
57449191e0fSNuno Antunes *s2++ = '\0';
57549191e0fSNuno Antunes type = ng_ksocket_parse(ng_ksocket_types, s1, 0);
57649191e0fSNuno Antunes if (type == -1)
57749191e0fSNuno Antunes return (EINVAL);
57849191e0fSNuno Antunes s1 = s2;
57949191e0fSNuno Antunes protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family);
58049191e0fSNuno Antunes if (protocol == -1)
58149191e0fSNuno Antunes return (EINVAL);
58249191e0fSNuno Antunes
58349191e0fSNuno Antunes /* Create the socket */
58449191e0fSNuno Antunes error = socreate(family, &priv->so, type, protocol, td);
58549191e0fSNuno Antunes if (error != 0)
58649191e0fSNuno Antunes return (error);
58749191e0fSNuno Antunes
58849191e0fSNuno Antunes /* XXX call soreserve() ? */
58949191e0fSNuno Antunes
59049191e0fSNuno Antunes }
59149191e0fSNuno Antunes
59249191e0fSNuno Antunes /* OK */
59349191e0fSNuno Antunes priv->hook = hook;
59449191e0fSNuno Antunes
59549191e0fSNuno Antunes /*
59649191e0fSNuno Antunes * In case of misconfigured routing a packet may reenter
59749191e0fSNuno Antunes * ksocket node recursively. Decouple stack to avoid possible
59849191e0fSNuno Antunes * panics about sleeping with locks held.
59949191e0fSNuno Antunes */
60049191e0fSNuno Antunes NG_HOOK_FORCE_QUEUE(hook);
60149191e0fSNuno Antunes
60249191e0fSNuno Antunes return(0);
60349191e0fSNuno Antunes }
60449191e0fSNuno Antunes
60549191e0fSNuno Antunes static int
ng_ksocket_connect(hook_p hook)60649191e0fSNuno Antunes ng_ksocket_connect(hook_p hook)
60749191e0fSNuno Antunes {
60849191e0fSNuno Antunes node_p node = NG_HOOK_NODE(hook);
60949191e0fSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
61049191e0fSNuno Antunes struct socket *const so = priv->so;
61149191e0fSNuno Antunes
61249191e0fSNuno Antunes /* Add our hook for incoming data and other events */
61349191e0fSNuno Antunes priv->so->so_upcallarg = (caddr_t)node;
61449191e0fSNuno Antunes priv->so->so_upcall = ng_ksocket_incoming;
615b728b13eSNuno Antunes atomic_set_int(&priv->so->so_rcv.ssb_flags, SSB_UPCALL);
616b728b13eSNuno Antunes atomic_set_int(&priv->so->so_snd.ssb_flags, SSB_UPCALL);
61749191e0fSNuno Antunes /*
61849191e0fSNuno Antunes * --Original comment--
61949191e0fSNuno Antunes * On a cloned socket we may have already received one or more
62049191e0fSNuno Antunes * upcalls which we couldn't handle without a hook. Handle
62149191e0fSNuno Antunes * those now.
62249191e0fSNuno Antunes * We cannot call the upcall function directly
62349191e0fSNuno Antunes * from here, because until this function has returned our
62449191e0fSNuno Antunes * hook isn't connected.
62549191e0fSNuno Antunes *
62649191e0fSNuno Antunes * ---meta comment for -current ---
62749191e0fSNuno Antunes * XXX This is dubius.
62849191e0fSNuno Antunes * Upcalls between the time that the hook was
62949191e0fSNuno Antunes * first created and now (on another processesor) will
63049191e0fSNuno Antunes * be earlier on the queue than the request to finalise the hook.
63149191e0fSNuno Antunes * By the time the hook is finalised,
63249191e0fSNuno Antunes * The queued upcalls will have happenned and the code
63349191e0fSNuno Antunes * will have discarded them because of a lack of a hook.
63449191e0fSNuno Antunes * (socket not open).
63549191e0fSNuno Antunes *
63649191e0fSNuno Antunes * This is a bad byproduct of the complicated way in which hooks
63749191e0fSNuno Antunes * are now created (3 daisy chained async events).
63849191e0fSNuno Antunes *
63949191e0fSNuno Antunes * Since we are a netgraph operation
64049191e0fSNuno Antunes * We know that we hold a lock on this node. This forces the
64149191e0fSNuno Antunes * request we make below to be queued rather than implemented
64249191e0fSNuno Antunes * immediatly which will cause the upcall function to be called a bit
64349191e0fSNuno Antunes * later.
64449191e0fSNuno Antunes * However, as we will run any waiting queued operations immediatly
64549191e0fSNuno Antunes * after doing this one, if we have not finalised the other end
64649191e0fSNuno Antunes * of the hook, those queued operations will fail.
64749191e0fSNuno Antunes */
64849191e0fSNuno Antunes if (priv->flags & KSF_CLONED) {
64949191e0fSNuno Antunes ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_WAITOK | M_NULLOK);
65049191e0fSNuno Antunes }
65149191e0fSNuno Antunes
65249191e0fSNuno Antunes return (0);
65349191e0fSNuno Antunes }
65449191e0fSNuno Antunes
65549191e0fSNuno Antunes /*
65649191e0fSNuno Antunes * Receive a control message
65749191e0fSNuno Antunes */
65849191e0fSNuno Antunes static int
ng_ksocket_rcvmsg(node_p node,item_p item,hook_p lasthook)65949191e0fSNuno Antunes ng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook)
66049191e0fSNuno Antunes {
66149191e0fSNuno Antunes struct thread *td = curthread->td_proc ? curthread : &thread0; /* XXX broken */
66249191e0fSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
66349191e0fSNuno Antunes struct socket *const so = priv->so;
66449191e0fSNuno Antunes struct ng_mesg *resp = NULL;
66549191e0fSNuno Antunes int error = 0;
66649191e0fSNuno Antunes struct ng_mesg *msg;
66749191e0fSNuno Antunes
66849191e0fSNuno Antunes NGI_GET_MSG(item, msg);
66949191e0fSNuno Antunes switch (msg->header.typecookie) {
67049191e0fSNuno Antunes case NGM_KSOCKET_COOKIE:
67149191e0fSNuno Antunes switch (msg->header.cmd) {
67249191e0fSNuno Antunes case NGM_KSOCKET_BIND:
67349191e0fSNuno Antunes {
67449191e0fSNuno Antunes struct sockaddr *const sa
67549191e0fSNuno Antunes = (struct sockaddr *)msg->data;
67649191e0fSNuno Antunes
67749191e0fSNuno Antunes /* Sanity check */
67849191e0fSNuno Antunes if (msg->header.arglen < SADATA_OFFSET
67949191e0fSNuno Antunes || msg->header.arglen < sa->sa_len)
68049191e0fSNuno Antunes ERROUT(EINVAL);
68149191e0fSNuno Antunes if (so == NULL)
68249191e0fSNuno Antunes ERROUT(ENXIO);
68349191e0fSNuno Antunes
68449191e0fSNuno Antunes /* Bind */
68549191e0fSNuno Antunes error = sobind(so, sa, td);
68649191e0fSNuno Antunes break;
68749191e0fSNuno Antunes }
68849191e0fSNuno Antunes case NGM_KSOCKET_LISTEN:
68949191e0fSNuno Antunes {
69049191e0fSNuno Antunes /* Sanity check */
69149191e0fSNuno Antunes if (msg->header.arglen != sizeof(int32_t))
69249191e0fSNuno Antunes ERROUT(EINVAL);
69349191e0fSNuno Antunes if (so == NULL)
69449191e0fSNuno Antunes ERROUT(ENXIO);
69549191e0fSNuno Antunes
69649191e0fSNuno Antunes /* Listen */
69749191e0fSNuno Antunes error = solisten(so, *((int32_t *)msg->data), td);
69849191e0fSNuno Antunes break;
69949191e0fSNuno Antunes }
70049191e0fSNuno Antunes
70149191e0fSNuno Antunes case NGM_KSOCKET_ACCEPT:
70249191e0fSNuno Antunes {
70349191e0fSNuno Antunes /* Sanity check */
70449191e0fSNuno Antunes if (msg->header.arglen != 0)
70549191e0fSNuno Antunes ERROUT(EINVAL);
70649191e0fSNuno Antunes if (so == NULL)
70749191e0fSNuno Antunes ERROUT(ENXIO);
70849191e0fSNuno Antunes
70949191e0fSNuno Antunes /* Make sure the socket is capable of accepting */
71049191e0fSNuno Antunes if (!(so->so_options & SO_ACCEPTCONN))
71149191e0fSNuno Antunes ERROUT(EINVAL);
71249191e0fSNuno Antunes if (priv->flags & KSF_ACCEPTING)
71349191e0fSNuno Antunes ERROUT(EALREADY);
71449191e0fSNuno Antunes
71549191e0fSNuno Antunes error = ng_ksocket_check_accept(priv);
71649191e0fSNuno Antunes if (error != 0 && error != EWOULDBLOCK)
71749191e0fSNuno Antunes ERROUT(error);
71849191e0fSNuno Antunes
71949191e0fSNuno Antunes /*
72049191e0fSNuno Antunes * If a connection is already complete, take it.
72149191e0fSNuno Antunes * Otherwise let the upcall function deal with
72249191e0fSNuno Antunes * the connection when it comes in.
72349191e0fSNuno Antunes */
72449191e0fSNuno Antunes priv->response_token = msg->header.token;
72542a79bf8SSascha Wildner priv->response_addr = NGI_RETADDR(item);
72649191e0fSNuno Antunes if (error == 0) {
72749191e0fSNuno Antunes ng_ksocket_finish_accept(priv);
72849191e0fSNuno Antunes } else
72949191e0fSNuno Antunes priv->flags |= KSF_ACCEPTING;
73049191e0fSNuno Antunes break;
73149191e0fSNuno Antunes }
73249191e0fSNuno Antunes
73349191e0fSNuno Antunes case NGM_KSOCKET_CONNECT:
73449191e0fSNuno Antunes {
73549191e0fSNuno Antunes struct sockaddr *const sa
73649191e0fSNuno Antunes = (struct sockaddr *)msg->data;
73749191e0fSNuno Antunes
73849191e0fSNuno Antunes /* Sanity check */
73949191e0fSNuno Antunes if (msg->header.arglen < SADATA_OFFSET
74049191e0fSNuno Antunes || msg->header.arglen < sa->sa_len)
74149191e0fSNuno Antunes ERROUT(EINVAL);
74249191e0fSNuno Antunes if (so == NULL)
74349191e0fSNuno Antunes ERROUT(ENXIO);
74449191e0fSNuno Antunes
74549191e0fSNuno Antunes /* Do connect */
74649191e0fSNuno Antunes if ((so->so_state & SS_ISCONNECTING) != 0)
74749191e0fSNuno Antunes ERROUT(EALREADY);
748e368a6e9SSepherosa Ziehau if ((error = soconnect(so, sa, td, TRUE)) != 0) {
74949191e0fSNuno Antunes soclrstate(so, SS_ISCONNECTING);
75049191e0fSNuno Antunes ERROUT(error);
75149191e0fSNuno Antunes }
75249191e0fSNuno Antunes if ((so->so_state & SS_ISCONNECTING) != 0) {
75349191e0fSNuno Antunes /* We will notify the sender when we connect */
75449191e0fSNuno Antunes priv->response_token = msg->header.token;
75542a79bf8SSascha Wildner priv->response_addr = NGI_RETADDR(item);
75649191e0fSNuno Antunes priv->flags |= KSF_CONNECTING;
75749191e0fSNuno Antunes ERROUT(EINPROGRESS);
75849191e0fSNuno Antunes }
75949191e0fSNuno Antunes break;
76049191e0fSNuno Antunes }
76149191e0fSNuno Antunes
76249191e0fSNuno Antunes case NGM_KSOCKET_GETNAME:
76349191e0fSNuno Antunes case NGM_KSOCKET_GETPEERNAME:
76449191e0fSNuno Antunes {
76549191e0fSNuno Antunes struct sockaddr *sa = NULL;
76649191e0fSNuno Antunes int len;
76749191e0fSNuno Antunes
76849191e0fSNuno Antunes /* Sanity check */
76949191e0fSNuno Antunes if (msg->header.arglen != 0)
77049191e0fSNuno Antunes ERROUT(EINVAL);
77149191e0fSNuno Antunes if (so == NULL)
77249191e0fSNuno Antunes ERROUT(ENXIO);
77349191e0fSNuno Antunes
77449191e0fSNuno Antunes /* Get function */
77549191e0fSNuno Antunes if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
77649191e0fSNuno Antunes if ((so->so_state
77749191e0fSNuno Antunes & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
77849191e0fSNuno Antunes ERROUT(ENOTCONN);
779e858b308SNuno Antunes error = so_pru_peeraddr(so, &sa);
780e858b308SNuno Antunes } else {
781e858b308SNuno Antunes error = so_pru_sockaddr(so, &sa);
782e858b308SNuno Antunes }
78349191e0fSNuno Antunes
78449191e0fSNuno Antunes /* Get local or peer address */
785e858b308SNuno Antunes if (error != 0)
78649191e0fSNuno Antunes goto bail;
78749191e0fSNuno Antunes len = (sa == NULL) ? 0 : sa->sa_len;
78849191e0fSNuno Antunes
78949191e0fSNuno Antunes /* Send it back in a response */
79049191e0fSNuno Antunes NG_MKRESPONSE(resp, msg, len, M_WAITOK | M_NULLOK);
79149191e0fSNuno Antunes if (resp == NULL) {
79249191e0fSNuno Antunes error = ENOMEM;
79349191e0fSNuno Antunes goto bail;
79449191e0fSNuno Antunes }
79549191e0fSNuno Antunes bcopy(sa, resp->data, len);
79649191e0fSNuno Antunes
79749191e0fSNuno Antunes bail:
79849191e0fSNuno Antunes /* Cleanup */
79949191e0fSNuno Antunes if (sa != NULL)
80049191e0fSNuno Antunes kfree(sa, M_SONAME);
80149191e0fSNuno Antunes break;
80249191e0fSNuno Antunes }
80349191e0fSNuno Antunes
80449191e0fSNuno Antunes case NGM_KSOCKET_GETOPT:
80549191e0fSNuno Antunes {
80649191e0fSNuno Antunes struct ng_ksocket_sockopt *ksopt =
80749191e0fSNuno Antunes (struct ng_ksocket_sockopt *)msg->data;
80849191e0fSNuno Antunes struct sockopt sopt;
80949191e0fSNuno Antunes
81049191e0fSNuno Antunes /* Sanity check */
81149191e0fSNuno Antunes if (msg->header.arglen != sizeof(*ksopt))
81249191e0fSNuno Antunes ERROUT(EINVAL);
81349191e0fSNuno Antunes if (so == NULL)
81449191e0fSNuno Antunes ERROUT(ENXIO);
81549191e0fSNuno Antunes
81649191e0fSNuno Antunes /* Get response with room for option value */
81749191e0fSNuno Antunes NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
81849191e0fSNuno Antunes + NG_KSOCKET_MAX_OPTLEN, M_WAITOK | M_NULLOK);
81949191e0fSNuno Antunes if (resp == NULL)
82049191e0fSNuno Antunes ERROUT(ENOMEM);
82149191e0fSNuno Antunes
82249191e0fSNuno Antunes /* Get socket option, and put value in the response */
82349191e0fSNuno Antunes sopt.sopt_dir = SOPT_GET;
82449191e0fSNuno Antunes sopt.sopt_level = ksopt->level;
82549191e0fSNuno Antunes sopt.sopt_name = ksopt->name;
82649191e0fSNuno Antunes sopt.sopt_td = NULL;
82749191e0fSNuno Antunes sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
82849191e0fSNuno Antunes ksopt = (struct ng_ksocket_sockopt *)resp->data;
82949191e0fSNuno Antunes sopt.sopt_val = ksopt->value;
83049191e0fSNuno Antunes if ((error = sogetopt(so, &sopt)) != 0) {
83149191e0fSNuno Antunes NG_FREE_MSG(resp);
83249191e0fSNuno Antunes break;
83349191e0fSNuno Antunes }
83449191e0fSNuno Antunes
83549191e0fSNuno Antunes /* Set actual value length */
83649191e0fSNuno Antunes resp->header.arglen = sizeof(*ksopt)
83749191e0fSNuno Antunes + sopt.sopt_valsize;
83849191e0fSNuno Antunes break;
83949191e0fSNuno Antunes }
84049191e0fSNuno Antunes
84149191e0fSNuno Antunes case NGM_KSOCKET_SETOPT:
84249191e0fSNuno Antunes {
84349191e0fSNuno Antunes struct ng_ksocket_sockopt *const ksopt =
84449191e0fSNuno Antunes (struct ng_ksocket_sockopt *)msg->data;
84549191e0fSNuno Antunes const int valsize = msg->header.arglen - sizeof(*ksopt);
84649191e0fSNuno Antunes struct sockopt sopt;
84749191e0fSNuno Antunes
84849191e0fSNuno Antunes /* Sanity check */
84949191e0fSNuno Antunes if (valsize < 0)
85049191e0fSNuno Antunes ERROUT(EINVAL);
85149191e0fSNuno Antunes if (so == NULL)
85249191e0fSNuno Antunes ERROUT(ENXIO);
85349191e0fSNuno Antunes
85449191e0fSNuno Antunes /* Set socket option */
85549191e0fSNuno Antunes sopt.sopt_dir = SOPT_SET;
85649191e0fSNuno Antunes sopt.sopt_level = ksopt->level;
85749191e0fSNuno Antunes sopt.sopt_name = ksopt->name;
85849191e0fSNuno Antunes sopt.sopt_val = ksopt->value;
85949191e0fSNuno Antunes sopt.sopt_valsize = valsize;
86049191e0fSNuno Antunes sopt.sopt_td = NULL;
86149191e0fSNuno Antunes error = sosetopt(so, &sopt);
86249191e0fSNuno Antunes break;
86349191e0fSNuno Antunes }
86449191e0fSNuno Antunes
86549191e0fSNuno Antunes default:
86649191e0fSNuno Antunes error = EINVAL;
86749191e0fSNuno Antunes break;
86849191e0fSNuno Antunes }
86949191e0fSNuno Antunes break;
87049191e0fSNuno Antunes default:
87149191e0fSNuno Antunes error = EINVAL;
87249191e0fSNuno Antunes break;
87349191e0fSNuno Antunes }
87449191e0fSNuno Antunes done:
87549191e0fSNuno Antunes NG_RESPOND_MSG(error, node, item, resp);
87649191e0fSNuno Antunes NG_FREE_MSG(msg);
87749191e0fSNuno Antunes return (error);
87849191e0fSNuno Antunes }
87949191e0fSNuno Antunes
88049191e0fSNuno Antunes /*
88149191e0fSNuno Antunes * Receive incoming data on our hook. Send it out the socket.
88249191e0fSNuno Antunes */
88349191e0fSNuno Antunes static int
ng_ksocket_rcvdata(hook_p hook,item_p item)88449191e0fSNuno Antunes ng_ksocket_rcvdata(hook_p hook, item_p item)
88549191e0fSNuno Antunes {
88649191e0fSNuno Antunes struct thread *td = curthread->td_proc ? curthread : &thread0; /* XXX broken */
88749191e0fSNuno Antunes const node_p node = NG_HOOK_NODE(hook);
88849191e0fSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
88949191e0fSNuno Antunes struct socket *const so = priv->so;
89049191e0fSNuno Antunes struct sockaddr *sa = NULL;
89149191e0fSNuno Antunes int error;
89249191e0fSNuno Antunes struct mbuf *m;
89349191e0fSNuno Antunes struct sa_tag *stag;
89449191e0fSNuno Antunes
89549191e0fSNuno Antunes /* Extract data */
89649191e0fSNuno Antunes NGI_GET_M(item, m);
89749191e0fSNuno Antunes NG_FREE_ITEM(item);
89849191e0fSNuno Antunes
89949191e0fSNuno Antunes /*
90049191e0fSNuno Antunes * Look if socket address is stored in packet tags.
90149191e0fSNuno Antunes * If sockaddr is ours, or provided by a third party (zero id),
90249191e0fSNuno Antunes * then we accept it.
90349191e0fSNuno Antunes */
90449191e0fSNuno Antunes if (((stag = (struct sa_tag *)m_tag_locate(m, NGM_KSOCKET_COOKIE,
90549191e0fSNuno Antunes NG_KSOCKET_TAG_SOCKADDR, NULL)) != NULL) &&
90649191e0fSNuno Antunes (stag->id == NG_NODE_ID(node) || stag->id == 0))
90749191e0fSNuno Antunes sa = &stag->sa;
90849191e0fSNuno Antunes
90949191e0fSNuno Antunes /* Reset specific mbuf flags to prevent addressing problems. */
91049191e0fSNuno Antunes m->m_flags &= ~(M_BCAST|M_MCAST);
91149191e0fSNuno Antunes
91249191e0fSNuno Antunes /* Send packet */
91349191e0fSNuno Antunes error = sosend(so, sa, 0, m, 0, 0, td);
91449191e0fSNuno Antunes
91549191e0fSNuno Antunes return (error);
91649191e0fSNuno Antunes }
91749191e0fSNuno Antunes
91849191e0fSNuno Antunes /*
91949191e0fSNuno Antunes * Destroy node
92049191e0fSNuno Antunes */
92149191e0fSNuno Antunes static int
ng_ksocket_shutdown(node_p node)92249191e0fSNuno Antunes ng_ksocket_shutdown(node_p node)
92349191e0fSNuno Antunes {
92449191e0fSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
92549191e0fSNuno Antunes priv_p embryo;
92649191e0fSNuno Antunes
92749191e0fSNuno Antunes /* Close our socket (if any) */
92849191e0fSNuno Antunes if (priv->so != NULL) {
929b728b13eSNuno Antunes atomic_clear_int(&priv->so->so_rcv.ssb_flags, SSB_UPCALL);
930b728b13eSNuno Antunes atomic_clear_int(&priv->so->so_snd.ssb_flags, SSB_UPCALL);
93149191e0fSNuno Antunes priv->so->so_upcall = NULL;
93249191e0fSNuno Antunes soclose(priv->so, FNONBLOCK);
93349191e0fSNuno Antunes priv->so = NULL;
93449191e0fSNuno Antunes }
93549191e0fSNuno Antunes
93649191e0fSNuno Antunes /* If we are an embryo, take ourselves out of the parent's list */
93749191e0fSNuno Antunes if (priv->flags & KSF_EMBRYONIC) {
93849191e0fSNuno Antunes LIST_REMOVE(priv, siblings);
93949191e0fSNuno Antunes priv->flags &= ~KSF_EMBRYONIC;
94049191e0fSNuno Antunes }
94149191e0fSNuno Antunes
94249191e0fSNuno Antunes /* Remove any embryonic children we have */
94349191e0fSNuno Antunes while (!LIST_EMPTY(&priv->embryos)) {
94449191e0fSNuno Antunes embryo = LIST_FIRST(&priv->embryos);
94549191e0fSNuno Antunes ng_rmnode_self(embryo->node);
94649191e0fSNuno Antunes }
94749191e0fSNuno Antunes
94849191e0fSNuno Antunes /* Take down netgraph node */
94949191e0fSNuno Antunes bzero(priv, sizeof(*priv));
95049191e0fSNuno Antunes kfree(priv, M_NETGRAPH);
95149191e0fSNuno Antunes NG_NODE_SET_PRIVATE(node, NULL);
95249191e0fSNuno Antunes NG_NODE_UNREF(node); /* let the node escape */
95349191e0fSNuno Antunes return (0);
95449191e0fSNuno Antunes }
95549191e0fSNuno Antunes
95649191e0fSNuno Antunes /*
95749191e0fSNuno Antunes * Hook disconnection
95849191e0fSNuno Antunes */
95949191e0fSNuno Antunes static int
ng_ksocket_disconnect(hook_p hook)96049191e0fSNuno Antunes ng_ksocket_disconnect(hook_p hook)
96149191e0fSNuno Antunes {
96249191e0fSNuno Antunes KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0,
96349191e0fSNuno Antunes ("%s: numhooks=%d?", __func__,
96449191e0fSNuno Antunes NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook))));
96549191e0fSNuno Antunes if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))
96649191e0fSNuno Antunes ng_rmnode_self(NG_HOOK_NODE(hook));
96749191e0fSNuno Antunes return (0);
96849191e0fSNuno Antunes }
96949191e0fSNuno Antunes
97049191e0fSNuno Antunes /************************************************************************
97149191e0fSNuno Antunes HELPER STUFF
97249191e0fSNuno Antunes ************************************************************************/
97349191e0fSNuno Antunes /*
97449191e0fSNuno Antunes * You should not "just call" a netgraph node function from an external
97549191e0fSNuno Antunes * asynchronous event. This is because in doing so you are ignoring the
97649191e0fSNuno Antunes * locking on the netgraph nodes. Instead call your function via ng_send_fn().
97749191e0fSNuno Antunes * This will call the function you chose, but will first do all the
97849191e0fSNuno Antunes * locking rigmarole. Your function MAY only be called at some distant future
97949191e0fSNuno Antunes * time (several millisecs away) so don't give it any arguments
98049191e0fSNuno Antunes * that may be revoked soon (e.g. on your stack).
98149191e0fSNuno Antunes *
98249191e0fSNuno Antunes * To decouple stack, we use queue version of ng_send_fn().
98349191e0fSNuno Antunes */
98449191e0fSNuno Antunes
98549191e0fSNuno Antunes static void
ng_ksocket_incoming(struct socket * so,void * arg,int waitflag)98649191e0fSNuno Antunes ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
98749191e0fSNuno Antunes {
98849191e0fSNuno Antunes const node_p node = arg;
98949191e0fSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
99049191e0fSNuno Antunes int wait = ((waitflag & M_WAITOK) ? NG_WAITOK : 0) | NG_QUEUE;
99149191e0fSNuno Antunes
99249191e0fSNuno Antunes /*
99349191e0fSNuno Antunes * Even if node is not locked, as soon as we are called, we assume
99449191e0fSNuno Antunes * it exist and it's private area is valid. With some care we can
99549191e0fSNuno Antunes * access it. Mark node that incoming event for it was sent to
99649191e0fSNuno Antunes * avoid unneded queue trashing.
99749191e0fSNuno Antunes */
99849191e0fSNuno Antunes if (atomic_cmpset_int(&priv->fn_sent, 0, 1) &&
99949191e0fSNuno Antunes ng_send_fn1(node, NULL, &ng_ksocket_incoming2, so, 0, wait)) {
100049191e0fSNuno Antunes atomic_store_rel_int(&priv->fn_sent, 0);
100149191e0fSNuno Antunes }
100249191e0fSNuno Antunes }
100349191e0fSNuno Antunes
100449191e0fSNuno Antunes
100549191e0fSNuno Antunes /*
100649191e0fSNuno Antunes * When incoming data is appended to the socket, we get notified here.
100749191e0fSNuno Antunes * This is also called whenever a significant event occurs for the socket.
100849191e0fSNuno Antunes * Our original caller may have queued this even some time ago and
100949191e0fSNuno Antunes * we cannot trust that he even still exists. The node however is being
101049191e0fSNuno Antunes * held with a reference by the queueing code and guarantied to be valid.
101149191e0fSNuno Antunes */
101249191e0fSNuno Antunes static void
ng_ksocket_incoming2(node_p node,hook_p hook,void * arg1,int arg2)101349191e0fSNuno Antunes ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2)
101449191e0fSNuno Antunes {
101549191e0fSNuno Antunes struct socket *so = arg1;
101649191e0fSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
101749191e0fSNuno Antunes struct ng_mesg *response;
101849191e0fSNuno Antunes int flags, error;
101949191e0fSNuno Antunes
102049191e0fSNuno Antunes crit_enter();
102149191e0fSNuno Antunes
102249191e0fSNuno Antunes /* so = priv->so; *//* XXX could have derived this like so */
102349191e0fSNuno Antunes KASSERT(so == priv->so, ("%s: wrong socket", __func__));
102449191e0fSNuno Antunes
102549191e0fSNuno Antunes /* Allow next incoming event to be queued. */
102649191e0fSNuno Antunes atomic_store_rel_int(&priv->fn_sent, 0);
102749191e0fSNuno Antunes
102849191e0fSNuno Antunes /* Check whether a pending connect operation has completed */
102949191e0fSNuno Antunes if (priv->flags & KSF_CONNECTING) {
103049191e0fSNuno Antunes if ((error = so->so_error) != 0) {
103149191e0fSNuno Antunes so->so_error = 0;
103249191e0fSNuno Antunes soclrstate(so, SS_ISCONNECTING);
103349191e0fSNuno Antunes }
103449191e0fSNuno Antunes if (!(so->so_state & SS_ISCONNECTING)) {
103549191e0fSNuno Antunes NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE,
103649191e0fSNuno Antunes NGM_KSOCKET_CONNECT, sizeof(int32_t), M_WAITOK | M_NULLOK);
103749191e0fSNuno Antunes if (response != NULL) {
103849191e0fSNuno Antunes response->header.flags |= NGF_RESP;
103949191e0fSNuno Antunes response->header.token = priv->response_token;
104049191e0fSNuno Antunes *(int32_t *)response->data = error;
104149191e0fSNuno Antunes /*
104249191e0fSNuno Antunes * send an async "response" message
104349191e0fSNuno Antunes * to the node that set us up
104449191e0fSNuno Antunes * (if it still exists)
104549191e0fSNuno Antunes */
104649191e0fSNuno Antunes NG_SEND_MSG_ID(error, node,
104749191e0fSNuno Antunes response, priv->response_addr, 0);
104849191e0fSNuno Antunes }
104949191e0fSNuno Antunes priv->flags &= ~KSF_CONNECTING;
105049191e0fSNuno Antunes }
105149191e0fSNuno Antunes }
105249191e0fSNuno Antunes
105349191e0fSNuno Antunes /* Check whether a pending accept operation has completed */
105449191e0fSNuno Antunes if (priv->flags & KSF_ACCEPTING) {
105549191e0fSNuno Antunes error = ng_ksocket_check_accept(priv);
105649191e0fSNuno Antunes if (error != EWOULDBLOCK)
105749191e0fSNuno Antunes priv->flags &= ~KSF_ACCEPTING;
105849191e0fSNuno Antunes if (error == 0)
105949191e0fSNuno Antunes ng_ksocket_finish_accept(priv);
106049191e0fSNuno Antunes }
106149191e0fSNuno Antunes
106249191e0fSNuno Antunes /*
106349191e0fSNuno Antunes * If we don't have a hook, we must handle data events later. When
106449191e0fSNuno Antunes * the hook gets created and is connected, this upcall function
106549191e0fSNuno Antunes * will be called again.
106649191e0fSNuno Antunes */
106749191e0fSNuno Antunes if (priv->hook == NULL) {
106849191e0fSNuno Antunes crit_exit();
106949191e0fSNuno Antunes return;
107049191e0fSNuno Antunes }
107149191e0fSNuno Antunes
107249191e0fSNuno Antunes /* Read and forward available mbuf's */
107349191e0fSNuno Antunes while (1) {
107449191e0fSNuno Antunes struct sockaddr *sa = NULL;
107549191e0fSNuno Antunes struct sockbuf sio;
107649191e0fSNuno Antunes struct mbuf *n;
107749191e0fSNuno Antunes
107849191e0fSNuno Antunes sbinit(&sio, 1000000000);
107949191e0fSNuno Antunes flags = MSG_DONTWAIT;
108049191e0fSNuno Antunes
108149191e0fSNuno Antunes /* Try to get next packet from socket */
108249191e0fSNuno Antunes error = soreceive(so,
108349191e0fSNuno Antunes ((so->so_state & SS_ISCONNECTED) ? NULL : &sa),
108449191e0fSNuno Antunes NULL, &sio, NULL, &flags);
108549191e0fSNuno Antunes if (error)
108649191e0fSNuno Antunes break;
108749191e0fSNuno Antunes
108849191e0fSNuno Antunes /* See if we got anything */
108949191e0fSNuno Antunes if (sio.sb_mb == NULL) {
109049191e0fSNuno Antunes if (sa != NULL)
109149191e0fSNuno Antunes kfree(sa, M_SONAME);
109249191e0fSNuno Antunes break;
109349191e0fSNuno Antunes }
109449191e0fSNuno Antunes
109549191e0fSNuno Antunes /*
109649191e0fSNuno Antunes * Don't trust the various socket layers to get the
109749191e0fSNuno Antunes * packet header and length correct (e.g. kern/15175).
109849191e0fSNuno Antunes *
109949191e0fSNuno Antunes * Also, do not trust that soreceive() will clear m_nextpkt
110049191e0fSNuno Antunes * for us (e.g. kern/84952, kern/82413).
110149191e0fSNuno Antunes */
110249191e0fSNuno Antunes sio.sb_mb->m_pkthdr.csum_flags = 0;
110349191e0fSNuno Antunes sio.sb_mb->m_pkthdr.len = 0;
110449191e0fSNuno Antunes for (n = sio.sb_mb; n != NULL; n = n->m_next) {
110549191e0fSNuno Antunes sio.sb_mb->m_pkthdr.len += n->m_len;
110649191e0fSNuno Antunes n->m_nextpkt = NULL;
110749191e0fSNuno Antunes }
110849191e0fSNuno Antunes
110949191e0fSNuno Antunes /* Put peer's socket address (if any) into a tag */
111049191e0fSNuno Antunes if (sa != NULL) {
111149191e0fSNuno Antunes struct sa_tag *stag;
111249191e0fSNuno Antunes
111349191e0fSNuno Antunes stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE,
111449191e0fSNuno Antunes NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) +
1115b5523eacSSascha Wildner sa->sa_len, M_NOWAIT);
111649191e0fSNuno Antunes if (stag == NULL) {
111749191e0fSNuno Antunes kfree(sa, M_SONAME);
111849191e0fSNuno Antunes goto sendit;
111949191e0fSNuno Antunes }
112049191e0fSNuno Antunes bcopy(sa, &stag->sa, sa->sa_len);
112149191e0fSNuno Antunes kfree(sa, M_SONAME);
112249191e0fSNuno Antunes stag->id = NG_NODE_ID(node);
112349191e0fSNuno Antunes m_tag_prepend(sio.sb_mb, &stag->tag);
112449191e0fSNuno Antunes }
112549191e0fSNuno Antunes
112649191e0fSNuno Antunes sendit: /* Forward data with optional peer sockaddr as packet tag */
112749191e0fSNuno Antunes NG_SEND_DATA_ONLY(error, priv->hook, sio.sb_mb);
112849191e0fSNuno Antunes }
112949191e0fSNuno Antunes
113049191e0fSNuno Antunes /*
113149191e0fSNuno Antunes * If the peer has closed the connection, forward a 0-length mbuf
113249191e0fSNuno Antunes * to indicate end-of-file.
113349191e0fSNuno Antunes */
113449191e0fSNuno Antunes if (so->so_state & SS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) {
113549191e0fSNuno Antunes struct mbuf *m;
113649191e0fSNuno Antunes
1137b5523eacSSascha Wildner MGETHDR(m, M_NOWAIT, MT_DATA);
113849191e0fSNuno Antunes if (m != NULL) {
113949191e0fSNuno Antunes m->m_len = m->m_pkthdr.len = 0;
114049191e0fSNuno Antunes NG_SEND_DATA_ONLY(error, priv->hook, m);
114149191e0fSNuno Antunes }
114249191e0fSNuno Antunes priv->flags |= KSF_EOFSEEN;
114349191e0fSNuno Antunes }
114449191e0fSNuno Antunes crit_exit();
114549191e0fSNuno Antunes }
114649191e0fSNuno Antunes
114749191e0fSNuno Antunes /*
114849191e0fSNuno Antunes * Check for a completed incoming connection and return 0 if one is found.
114949191e0fSNuno Antunes * Otherwise return the appropriate error code.
115049191e0fSNuno Antunes */
115149191e0fSNuno Antunes static int
ng_ksocket_check_accept(priv_p priv)115249191e0fSNuno Antunes ng_ksocket_check_accept(priv_p priv)
115349191e0fSNuno Antunes {
115449191e0fSNuno Antunes struct socket *const head = priv->so;
115549191e0fSNuno Antunes int error;
115649191e0fSNuno Antunes
115749191e0fSNuno Antunes if ((error = head->so_error) != 0) {
115849191e0fSNuno Antunes head->so_error = 0;
115949191e0fSNuno Antunes return error;
116049191e0fSNuno Antunes }
116149191e0fSNuno Antunes /* Unlocked read. */
116249191e0fSNuno Antunes if (TAILQ_EMPTY(&head->so_comp)) {
116349191e0fSNuno Antunes if (head->so_state & SS_CANTRCVMORE)
116449191e0fSNuno Antunes return ECONNABORTED;
116549191e0fSNuno Antunes return EWOULDBLOCK;
116649191e0fSNuno Antunes }
116749191e0fSNuno Antunes return 0;
116849191e0fSNuno Antunes }
116949191e0fSNuno Antunes
117049191e0fSNuno Antunes /*
117149191e0fSNuno Antunes * Handle the first completed incoming connection, assumed to be already
117249191e0fSNuno Antunes * on the socket's so_comp queue.
117349191e0fSNuno Antunes */
117449191e0fSNuno Antunes static void
ng_ksocket_finish_accept(priv_p priv)117549191e0fSNuno Antunes ng_ksocket_finish_accept(priv_p priv)
117649191e0fSNuno Antunes {
117749191e0fSNuno Antunes struct socket *const head = priv->so;
117849191e0fSNuno Antunes struct socket *so;
117949191e0fSNuno Antunes struct sockaddr *sa = NULL;
118049191e0fSNuno Antunes struct ng_mesg *resp;
118149191e0fSNuno Antunes struct ng_ksocket_accept *resp_data;
118249191e0fSNuno Antunes node_p node;
118349191e0fSNuno Antunes priv_p priv2;
118449191e0fSNuno Antunes int len;
118549191e0fSNuno Antunes int error;
118649191e0fSNuno Antunes
11878f55a694SNuno Antunes lwkt_getpooltoken(head);
118849191e0fSNuno Antunes so = TAILQ_FIRST(&head->so_comp);
118949191e0fSNuno Antunes if (so == NULL) { /* Should never happen */
11908f55a694SNuno Antunes lwkt_relpooltoken(head);
119149191e0fSNuno Antunes return;
119249191e0fSNuno Antunes }
119349191e0fSNuno Antunes TAILQ_REMOVE(&head->so_comp, so, so_list);
119449191e0fSNuno Antunes head->so_qlen--;
1195c7435db9SNuno Antunes soclrstate(so, SS_COMP);
119649191e0fSNuno Antunes so->so_head = NULL;
1197c7435db9SNuno Antunes soreference(so);
11988f55a694SNuno Antunes lwkt_relpooltoken(head);
119949191e0fSNuno Antunes
120049191e0fSNuno Antunes /* XXX KNOTE(&head->so_rcv.ssb_sel.si_note, 0); */
120149191e0fSNuno Antunes
120249191e0fSNuno Antunes soaccept(so, &sa);
120349191e0fSNuno Antunes
120449191e0fSNuno Antunes len = OFFSETOF(struct ng_ksocket_accept, addr);
120549191e0fSNuno Antunes if (sa != NULL)
120649191e0fSNuno Antunes len += sa->sa_len;
120749191e0fSNuno Antunes
120849191e0fSNuno Antunes NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len,
120949191e0fSNuno Antunes M_WAITOK | M_NULLOK);
121049191e0fSNuno Antunes if (resp == NULL) {
121149191e0fSNuno Antunes soclose(so, FNONBLOCK);
121249191e0fSNuno Antunes goto out;
121349191e0fSNuno Antunes }
121449191e0fSNuno Antunes resp->header.flags |= NGF_RESP;
121549191e0fSNuno Antunes resp->header.token = priv->response_token;
121649191e0fSNuno Antunes
121749191e0fSNuno Antunes /* Clone a ksocket node to wrap the new socket */
121849191e0fSNuno Antunes error = ng_make_node_common(&ng_ksocket_typestruct, &node);
121949191e0fSNuno Antunes if (error) {
122049191e0fSNuno Antunes kfree(resp, M_NETGRAPH);
122149191e0fSNuno Antunes soclose(so, FNONBLOCK);
122249191e0fSNuno Antunes goto out;
122349191e0fSNuno Antunes }
122449191e0fSNuno Antunes
122549191e0fSNuno Antunes if (ng_ksocket_constructor(node) != 0) {
122649191e0fSNuno Antunes NG_NODE_UNREF(node);
122749191e0fSNuno Antunes kfree(resp, M_NETGRAPH);
122849191e0fSNuno Antunes soclose(so, FNONBLOCK);
122949191e0fSNuno Antunes goto out;
123049191e0fSNuno Antunes }
123149191e0fSNuno Antunes
123249191e0fSNuno Antunes priv2 = NG_NODE_PRIVATE(node);
123349191e0fSNuno Antunes priv2->so = so;
123449191e0fSNuno Antunes priv2->flags |= KSF_CLONED | KSF_EMBRYONIC;
123549191e0fSNuno Antunes
123649191e0fSNuno Antunes /*
123749191e0fSNuno Antunes * Insert the cloned node into a list of embryonic children
123849191e0fSNuno Antunes * on the parent node. When a hook is created on the cloned
123949191e0fSNuno Antunes * node it will be removed from this list. When the parent
124049191e0fSNuno Antunes * is destroyed it will destroy any embryonic children it has.
124149191e0fSNuno Antunes */
124249191e0fSNuno Antunes LIST_INSERT_HEAD(&priv->embryos, priv2, siblings);
124349191e0fSNuno Antunes
124449191e0fSNuno Antunes so->so_upcallarg = (caddr_t)node;
124549191e0fSNuno Antunes so->so_upcall = ng_ksocket_incoming;
1246b728b13eSNuno Antunes atomic_set_int(&priv->so->so_rcv.ssb_flags, SSB_UPCALL);
1247b728b13eSNuno Antunes atomic_set_int(&priv->so->so_snd.ssb_flags, SSB_UPCALL);
124849191e0fSNuno Antunes
124949191e0fSNuno Antunes /* Fill in the response data and send it or return it to the caller */
125049191e0fSNuno Antunes resp_data = (struct ng_ksocket_accept *)resp->data;
125149191e0fSNuno Antunes resp_data->nodeid = NG_NODE_ID(node);
125249191e0fSNuno Antunes if (sa != NULL)
125349191e0fSNuno Antunes bcopy(sa, &resp_data->addr, sa->sa_len);
125449191e0fSNuno Antunes NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0);
125549191e0fSNuno Antunes
125649191e0fSNuno Antunes out:
125749191e0fSNuno Antunes if (sa != NULL)
125849191e0fSNuno Antunes kfree(sa, M_SONAME);
125949191e0fSNuno Antunes }
126049191e0fSNuno Antunes
126149191e0fSNuno Antunes /*
126249191e0fSNuno Antunes * Parse out either an integer value or an alias.
126349191e0fSNuno Antunes */
126449191e0fSNuno Antunes static int
ng_ksocket_parse(const struct ng_ksocket_alias * aliases,const char * s,int family)126549191e0fSNuno Antunes ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
126649191e0fSNuno Antunes const char *s, int family)
126749191e0fSNuno Antunes {
126849191e0fSNuno Antunes int k, val;
126949191e0fSNuno Antunes char *eptr;
127049191e0fSNuno Antunes
127149191e0fSNuno Antunes /* Try aliases */
127249191e0fSNuno Antunes for (k = 0; aliases[k].name != NULL; k++) {
127349191e0fSNuno Antunes if (strcmp(s, aliases[k].name) == 0
127449191e0fSNuno Antunes && aliases[k].family == family)
127549191e0fSNuno Antunes return aliases[k].value;
127649191e0fSNuno Antunes }
127749191e0fSNuno Antunes
127849191e0fSNuno Antunes /* Try parsing as a number */
127949191e0fSNuno Antunes val = (int)strtoul(s, &eptr, 10);
128049191e0fSNuno Antunes if (val < 0 || *eptr != '\0')
128149191e0fSNuno Antunes return (-1);
128249191e0fSNuno Antunes return (val);
128349191e0fSNuno Antunes }
128449191e0fSNuno Antunes
1285