xref: /dflybsd-src/sys/netgraph7/ksocket/ng_ksocket.c (revision 22c1d6caed6663b95a38d1a1979a4e539fa95413)
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