ng_ksocket.c revision 130480
153246Sarchie
253246Sarchie/*
353246Sarchie * ng_ksocket.c
453246Sarchie *
553246Sarchie * Copyright (c) 1996-1999 Whistle Communications, Inc.
653246Sarchie * All rights reserved.
753246Sarchie *
853246Sarchie * Subject to the following obligations and disclaimer of warranty, use and
953246Sarchie * redistribution of this software, in source or object code forms, with or
1053246Sarchie * without modifications are expressly permitted by Whistle Communications;
1153246Sarchie * provided, however, that:
1253246Sarchie * 1. Any and all reproductions of the source or object code must include the
1353246Sarchie *    copyright notice above and the following disclaimer of warranties; and
1453246Sarchie * 2. No rights are granted, in any manner or form, to use Whistle
1553246Sarchie *    Communications, Inc. trademarks, including the mark "WHISTLE
1653246Sarchie *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1753246Sarchie *    such appears in the above copyright notice or in the software.
1853246Sarchie *
1953246Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2053246Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2153246Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2253246Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2353246Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2453246Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2553246Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2653246Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2753246Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2853246Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2953246Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3053246Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3153246Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3253246Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3353246Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3453246Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3553246Sarchie * OF SUCH DAMAGE.
3653246Sarchie *
3767506Sjulian * Author: Archie Cobbs <archie@freebsd.org>
3853246Sarchie *
3953246Sarchie * $FreeBSD: head/sys/netgraph/ng_ksocket.c 130480 2004-06-14 18:16:22Z rwatson $
4053246Sarchie * $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $
4153246Sarchie */
4253246Sarchie
4353246Sarchie/*
4453246Sarchie * Kernel socket node type.  This node type is basically a kernel-mode
4553246Sarchie * version of a socket... kindof like the reverse of the socket node type.
4653246Sarchie */
4753246Sarchie
4853246Sarchie#include <sys/param.h>
4953246Sarchie#include <sys/systm.h>
5053246Sarchie#include <sys/kernel.h>
5153246Sarchie#include <sys/mbuf.h>
5253246Sarchie#include <sys/proc.h>
5353246Sarchie#include <sys/malloc.h>
5453913Sarchie#include <sys/ctype.h>
5553246Sarchie#include <sys/protosw.h>
5653246Sarchie#include <sys/errno.h>
5753246Sarchie#include <sys/socket.h>
5853246Sarchie#include <sys/socketvar.h>
5953246Sarchie#include <sys/uio.h>
6053913Sarchie#include <sys/un.h>
6153246Sarchie
6253246Sarchie#include <netgraph/ng_message.h>
6353246Sarchie#include <netgraph/netgraph.h>
6453913Sarchie#include <netgraph/ng_parse.h>
6553246Sarchie#include <netgraph/ng_ksocket.h>
6653246Sarchie
6753246Sarchie#include <netinet/in.h>
6853246Sarchie#include <netatalk/at.h>
6953246Sarchie
7070870Sjulian#ifdef NG_SEPARATE_MALLOC
7170870SjulianMALLOC_DEFINE(M_NETGRAPH_KSOCKET, "netgraph_ksock", "netgraph ksock node ");
7270870Sjulian#else
7370870Sjulian#define M_NETGRAPH_KSOCKET M_NETGRAPH
7470870Sjulian#endif
7570870Sjulian
7653913Sarchie#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
7753913Sarchie#define SADATA_OFFSET	(OFFSETOF(struct sockaddr, sa_data))
7853913Sarchie
7953246Sarchie/* Node private data */
8053404Sarchiestruct ng_ksocket_private {
8183186Sjulian	node_p		node;
8253246Sarchie	hook_p		hook;
8353246Sarchie	struct socket	*so;
8483186Sjulian	LIST_HEAD(, ng_ksocket_private)	embryos;
8583186Sjulian	LIST_ENTRY(ng_ksocket_private)	siblings;
8683186Sjulian	u_int32_t	flags;
8783186Sjulian	u_int32_t	response_token;
8883186Sjulian	ng_ID_t		response_addr;
8953246Sarchie};
9053404Sarchietypedef struct ng_ksocket_private *priv_p;
9153246Sarchie
9283186Sjulian/* Flags for priv_p */
9383186Sjulian#define	KSF_CONNECTING	0x00000001	/* Waiting for connection complete */
9483186Sjulian#define	KSF_ACCEPTING	0x00000002	/* Waiting for accept complete */
9583186Sjulian#define	KSF_EOFSEEN	0x00000004	/* Have sent 0-length EOF mbuf */
9683186Sjulian#define	KSF_CLONED	0x00000008	/* Cloned from an accepting socket */
9783186Sjulian#define	KSF_EMBRYONIC	0x00000010	/* Cloned node with no hooks yet */
9888945Sarchie#define	KSF_SENDING	0x00000020	/* Sending on socket */
9983186Sjulian
10053246Sarchie/* Netgraph node methods */
10153246Sarchiestatic ng_constructor_t	ng_ksocket_constructor;
10253246Sarchiestatic ng_rcvmsg_t	ng_ksocket_rcvmsg;
10370700Sjulianstatic ng_shutdown_t	ng_ksocket_shutdown;
10453246Sarchiestatic ng_newhook_t	ng_ksocket_newhook;
10553246Sarchiestatic ng_rcvdata_t	ng_ksocket_rcvdata;
10683186Sjulianstatic ng_connect_t	ng_ksocket_connect;
10753246Sarchiestatic ng_disconnect_t	ng_ksocket_disconnect;
10853246Sarchie
10953246Sarchie/* Alias structure */
11053246Sarchiestruct ng_ksocket_alias {
11153246Sarchie	const char	*name;
11253246Sarchie	const int	value;
11353246Sarchie	const int	family;
11453246Sarchie};
11553246Sarchie
11653246Sarchie/* Protocol family aliases */
11753246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_families[] = {
11853246Sarchie	{ "local",	PF_LOCAL	},
11953246Sarchie	{ "inet",	PF_INET		},
12053246Sarchie	{ "inet6",	PF_INET6	},
12153246Sarchie	{ "atalk",	PF_APPLETALK	},
12253246Sarchie	{ "ipx",	PF_IPX		},
12353246Sarchie	{ "atm",	PF_ATM		},
12453246Sarchie	{ NULL,		-1		},
12553246Sarchie};
12653246Sarchie
12753246Sarchie/* Socket type aliases */
12853246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_types[] = {
12953246Sarchie	{ "stream",	SOCK_STREAM	},
13053246Sarchie	{ "dgram",	SOCK_DGRAM	},
13153246Sarchie	{ "raw",	SOCK_RAW	},
13253246Sarchie	{ "rdm",	SOCK_RDM	},
13353246Sarchie	{ "seqpacket",	SOCK_SEQPACKET	},
13453246Sarchie	{ NULL,		-1		},
13553246Sarchie};
13653246Sarchie
13753246Sarchie/* Protocol aliases */
13853246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_protos[] = {
13953246Sarchie	{ "ip",		IPPROTO_IP,		PF_INET		},
14084776Sarchie	{ "raw",	IPPROTO_RAW,		PF_INET		},
14153246Sarchie	{ "icmp",	IPPROTO_ICMP,		PF_INET		},
14253246Sarchie	{ "igmp",	IPPROTO_IGMP,		PF_INET		},
14353246Sarchie	{ "tcp",	IPPROTO_TCP,		PF_INET		},
14453246Sarchie	{ "udp",	IPPROTO_UDP,		PF_INET		},
14553246Sarchie	{ "gre",	IPPROTO_GRE,		PF_INET		},
14653246Sarchie	{ "esp",	IPPROTO_ESP,		PF_INET		},
14753246Sarchie	{ "ah",		IPPROTO_AH,		PF_INET		},
14853246Sarchie	{ "swipe",	IPPROTO_SWIPE,		PF_INET		},
14953246Sarchie	{ "encap",	IPPROTO_ENCAP,		PF_INET		},
15053246Sarchie	{ "divert",	IPPROTO_DIVERT,		PF_INET		},
151119187Shsu	{ "pim",	IPPROTO_PIM,		PF_INET		},
15253246Sarchie	{ "ddp",	ATPROTO_DDP,		PF_APPLETALK	},
15353246Sarchie	{ "aarp",	ATPROTO_AARP,		PF_APPLETALK	},
15453246Sarchie	{ NULL,		-1					},
15553246Sarchie};
15653246Sarchie
15753913Sarchie/* Helper functions */
15883186Sjulianstatic int	ng_ksocket_check_accept(priv_p);
15983186Sjulianstatic void	ng_ksocket_finish_accept(priv_p);
16053913Sarchiestatic void	ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
16153913Sarchiestatic int	ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
16253913Sarchie			const char *s, int family);
16383186Sjulianstatic void	ng_ksocket_incoming2(node_p node, hook_p hook,
16483186Sjulian			void *arg1, int waitflag);
16553913Sarchie
16653913Sarchie/************************************************************************
16753913Sarchie			STRUCT SOCKADDR PARSE TYPE
16853913Sarchie ************************************************************************/
16953913Sarchie
17053913Sarchie/* Get the length of the data portion of a generic struct sockaddr */
17153913Sarchiestatic int
17253913Sarchieng_parse_generic_sockdata_getLength(const struct ng_parse_type *type,
17353913Sarchie	const u_char *start, const u_char *buf)
17453913Sarchie{
17553913Sarchie	const struct sockaddr *sa;
17653913Sarchie
17753913Sarchie	sa = (const struct sockaddr *)(buf - SADATA_OFFSET);
17864470Sarchie	return (sa->sa_len < SADATA_OFFSET) ? 0 : sa->sa_len - SADATA_OFFSET;
17953913Sarchie}
18053913Sarchie
18153913Sarchie/* Type for the variable length data portion of a generic struct sockaddr */
18253913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockdata_type = {
18353913Sarchie	&ng_parse_bytearray_type,
18453913Sarchie	&ng_parse_generic_sockdata_getLength
18553913Sarchie};
18653913Sarchie
18753913Sarchie/* Type for a generic struct sockaddr */
18897685Sarchiestatic const struct ng_parse_struct_field
18997685Sarchie    ng_parse_generic_sockaddr_type_fields[] = {
19064508Sarchie	  { "len",	&ng_parse_uint8_type			},
19164508Sarchie	  { "family",	&ng_parse_uint8_type			},
19253913Sarchie	  { "data",	&ng_ksocket_generic_sockdata_type	},
19353913Sarchie	  { NULL }
19453913Sarchie};
19553913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockaddr_type = {
19653913Sarchie	&ng_parse_struct_type,
19797685Sarchie	&ng_parse_generic_sockaddr_type_fields
19853913Sarchie};
19953913Sarchie
20053913Sarchie/* Convert a struct sockaddr from ASCII to binary.  If its a protocol
20153913Sarchie   family that we specially handle, do that, otherwise defer to the
20253913Sarchie   generic parse type ng_ksocket_generic_sockaddr_type. */
20353913Sarchiestatic int
20453913Sarchieng_ksocket_sockaddr_parse(const struct ng_parse_type *type,
20553913Sarchie	const char *s, int *off, const u_char *const start,
20653913Sarchie	u_char *const buf, int *buflen)
20753913Sarchie{
20853913Sarchie	struct sockaddr *const sa = (struct sockaddr *)buf;
20953913Sarchie	enum ng_parse_token tok;
21053913Sarchie	char fambuf[32];
21153913Sarchie	int family, len;
21253913Sarchie	char *t;
21353913Sarchie
21453913Sarchie	/* If next token is a left curly brace, use generic parse type */
21553913Sarchie	if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) {
21653913Sarchie		return (*ng_ksocket_generic_sockaddr_type.supertype->parse)
21753913Sarchie		    (&ng_ksocket_generic_sockaddr_type,
21853913Sarchie		    s, off, start, buf, buflen);
21953913Sarchie	}
22053913Sarchie
22153913Sarchie	/* Get socket address family followed by a slash */
22253913Sarchie	while (isspace(s[*off]))
22353913Sarchie		(*off)++;
22453913Sarchie	if ((t = index(s + *off, '/')) == NULL)
22553913Sarchie		return (EINVAL);
22653913Sarchie	if ((len = t - (s + *off)) > sizeof(fambuf) - 1)
22753913Sarchie		return (EINVAL);
22853913Sarchie	strncpy(fambuf, s + *off, len);
22953913Sarchie	fambuf[len] = '\0';
23053913Sarchie	*off += len + 1;
23153913Sarchie	if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1)
23253913Sarchie		return (EINVAL);
23353913Sarchie
23453913Sarchie	/* Set family */
23553913Sarchie	if (*buflen < SADATA_OFFSET)
23653913Sarchie		return (ERANGE);
23753913Sarchie	sa->sa_family = family;
23853913Sarchie
23953913Sarchie	/* Set family-specific data and length */
24053913Sarchie	switch (sa->sa_family) {
24153913Sarchie	case PF_LOCAL:		/* Get pathname */
24253913Sarchie	    {
24353913Sarchie		const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
24453913Sarchie		struct sockaddr_un *const sun = (struct sockaddr_un *)sa;
24553913Sarchie		int toklen, pathlen;
24653913Sarchie		char *path;
24753913Sarchie
24868845Sbrian		if ((path = ng_get_string_token(s, off, &toklen, NULL)) == NULL)
24953913Sarchie			return (EINVAL);
25053913Sarchie		pathlen = strlen(path);
25153913Sarchie		if (pathlen > SOCK_MAXADDRLEN) {
25270870Sjulian			FREE(path, M_NETGRAPH_KSOCKET);
25353913Sarchie			return (E2BIG);
25453913Sarchie		}
25553913Sarchie		if (*buflen < pathoff + pathlen) {
25670870Sjulian			FREE(path, M_NETGRAPH_KSOCKET);
25753913Sarchie			return (ERANGE);
25853913Sarchie		}
25953913Sarchie		*off += toklen;
26053913Sarchie		bcopy(path, sun->sun_path, pathlen);
26153913Sarchie		sun->sun_len = pathoff + pathlen;
26270870Sjulian		FREE(path, M_NETGRAPH_KSOCKET);
26353913Sarchie		break;
26453913Sarchie	    }
26553913Sarchie
26653913Sarchie	case PF_INET:		/* Get an IP address with optional port */
26753913Sarchie	    {
26853913Sarchie		struct sockaddr_in *const sin = (struct sockaddr_in *)sa;
26953913Sarchie		int i;
27053913Sarchie
27153913Sarchie		/* Parse this: <ipaddress>[:port] */
27253913Sarchie		for (i = 0; i < 4; i++) {
27353913Sarchie			u_long val;
27453913Sarchie			char *eptr;
27553913Sarchie
27653913Sarchie			val = strtoul(s + *off, &eptr, 10);
27753913Sarchie			if (val > 0xff || eptr == s + *off)
27853913Sarchie				return (EINVAL);
27953913Sarchie			*off += (eptr - (s + *off));
28053913Sarchie			((u_char *)&sin->sin_addr)[i] = (u_char)val;
28153913Sarchie			if (i < 3) {
28253913Sarchie				if (s[*off] != '.')
28353913Sarchie					return (EINVAL);
28453913Sarchie				(*off)++;
28553913Sarchie			} else if (s[*off] == ':') {
28653913Sarchie				(*off)++;
28753913Sarchie				val = strtoul(s + *off, &eptr, 10);
28853913Sarchie				if (val > 0xffff || eptr == s + *off)
28953913Sarchie					return (EINVAL);
29053913Sarchie				*off += (eptr - (s + *off));
29153913Sarchie				sin->sin_port = htons(val);
29253913Sarchie			} else
29353913Sarchie				sin->sin_port = 0;
29453913Sarchie		}
29553913Sarchie		bzero(&sin->sin_zero, sizeof(sin->sin_zero));
29653913Sarchie		sin->sin_len = sizeof(*sin);
29753913Sarchie		break;
29853913Sarchie	    }
29953913Sarchie
30053913Sarchie#if 0
30153913Sarchie	case PF_APPLETALK:	/* XXX implement these someday */
30253913Sarchie	case PF_INET6:
30353913Sarchie	case PF_IPX:
30453913Sarchie#endif
30553913Sarchie
30653913Sarchie	default:
30753913Sarchie		return (EINVAL);
30853913Sarchie	}
30953913Sarchie
31053913Sarchie	/* Done */
31153913Sarchie	*buflen = sa->sa_len;
31253913Sarchie	return (0);
31353913Sarchie}
31453913Sarchie
31553913Sarchie/* Convert a struct sockaddr from binary to ASCII */
31653913Sarchiestatic int
31753913Sarchieng_ksocket_sockaddr_unparse(const struct ng_parse_type *type,
31853913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
31953913Sarchie{
32053913Sarchie	const struct sockaddr *sa = (const struct sockaddr *)(data + *off);
32153913Sarchie	int slen = 0;
32253913Sarchie
32353913Sarchie	/* Output socket address, either in special or generic format */
32453913Sarchie	switch (sa->sa_family) {
32553913Sarchie	case PF_LOCAL:
32653913Sarchie	    {
32753913Sarchie		const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
32853913Sarchie		const struct sockaddr_un *sun = (const struct sockaddr_un *)sa;
32953913Sarchie		const int pathlen = sun->sun_len - pathoff;
33053913Sarchie		char pathbuf[SOCK_MAXADDRLEN + 1];
33153913Sarchie		char *pathtoken;
33253913Sarchie
33353913Sarchie		bcopy(sun->sun_path, pathbuf, pathlen);
33468845Sbrian		if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL)
33553913Sarchie			return (ENOMEM);
33653913Sarchie		slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken);
33770870Sjulian		FREE(pathtoken, M_NETGRAPH_KSOCKET);
33853913Sarchie		if (slen >= cbuflen)
33953913Sarchie			return (ERANGE);
34053913Sarchie		*off += sun->sun_len;
34153913Sarchie		return (0);
34253913Sarchie	    }
34353913Sarchie
34453913Sarchie	case PF_INET:
34553913Sarchie	    {
34653913Sarchie		const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
34753913Sarchie
34853913Sarchie		slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d",
34953913Sarchie		  ((const u_char *)&sin->sin_addr)[0],
35053913Sarchie		  ((const u_char *)&sin->sin_addr)[1],
35153913Sarchie		  ((const u_char *)&sin->sin_addr)[2],
35253913Sarchie		  ((const u_char *)&sin->sin_addr)[3]);
35353913Sarchie		if (sin->sin_port != 0) {
35453913Sarchie			slen += snprintf(cbuf + strlen(cbuf),
35553913Sarchie			    cbuflen - strlen(cbuf), ":%d",
35653913Sarchie			    (u_int)ntohs(sin->sin_port));
35753913Sarchie		}
35853913Sarchie		if (slen >= cbuflen)
35953913Sarchie			return (ERANGE);
36053913Sarchie		*off += sizeof(*sin);
36153913Sarchie		return(0);
36253913Sarchie	    }
36353913Sarchie
36453913Sarchie#if 0
36553913Sarchie	case PF_APPLETALK:	/* XXX implement these someday */
36653913Sarchie	case PF_INET6:
36753913Sarchie	case PF_IPX:
36853913Sarchie#endif
36953913Sarchie
37053913Sarchie	default:
37153913Sarchie		return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
37253913Sarchie		    (&ng_ksocket_generic_sockaddr_type,
37353913Sarchie		    data, off, cbuf, cbuflen);
37453913Sarchie	}
37553913Sarchie}
37653913Sarchie
37753913Sarchie/* Parse type for struct sockaddr */
37853913Sarchiestatic const struct ng_parse_type ng_ksocket_sockaddr_type = {
37953913Sarchie	NULL,
38053913Sarchie	NULL,
38153913Sarchie	NULL,
38253913Sarchie	&ng_ksocket_sockaddr_parse,
38353913Sarchie	&ng_ksocket_sockaddr_unparse,
38453913Sarchie	NULL		/* no such thing as a default struct sockaddr */
38553913Sarchie};
38653913Sarchie
38753913Sarchie/************************************************************************
38853913Sarchie		STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
38953913Sarchie ************************************************************************/
39053913Sarchie
39153913Sarchie/* Get length of the struct ng_ksocket_sockopt value field, which is the
39253913Sarchie   just the excess of the message argument portion over the length of
39353913Sarchie   the struct ng_ksocket_sockopt. */
39453913Sarchiestatic int
39553913Sarchieng_parse_sockoptval_getLength(const struct ng_parse_type *type,
39653913Sarchie	const u_char *start, const u_char *buf)
39753913Sarchie{
39853913Sarchie	static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
39953913Sarchie	const struct ng_ksocket_sockopt *sopt;
40053913Sarchie	const struct ng_mesg *msg;
40153913Sarchie
40253913Sarchie	sopt = (const struct ng_ksocket_sockopt *)(buf - offset);
40353913Sarchie	msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg));
40453913Sarchie	return msg->header.arglen - sizeof(*sopt);
40553913Sarchie}
40653913Sarchie
40753913Sarchie/* Parse type for the option value part of a struct ng_ksocket_sockopt
40853913Sarchie   XXX Eventually, we should handle the different socket options specially.
40953913Sarchie   XXX This would avoid byte order problems, eg an integer value of 1 is
41053913Sarchie   XXX going to be "[1]" for little endian or "[3=1]" for big endian. */
41153913Sarchiestatic const struct ng_parse_type ng_ksocket_sockoptval_type = {
41253913Sarchie	&ng_parse_bytearray_type,
41353913Sarchie	&ng_parse_sockoptval_getLength
41453913Sarchie};
41553913Sarchie
41653913Sarchie/* Parse type for struct ng_ksocket_sockopt */
41797685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_sockopt_type_fields[]
41853913Sarchie	= NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type);
41953913Sarchiestatic const struct ng_parse_type ng_ksocket_sockopt_type = {
42053913Sarchie	&ng_parse_struct_type,
42197685Sarchie	&ng_ksocket_sockopt_type_fields
42253913Sarchie};
42353913Sarchie
42483186Sjulian/* Parse type for struct ng_ksocket_accept */
42597685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_accept_type_fields[]
42683186Sjulian	= NGM_KSOCKET_ACCEPT_INFO;
42783186Sjulianstatic const struct ng_parse_type ng_ksocket_accept_type = {
42883186Sjulian	&ng_parse_struct_type,
42997685Sarchie	&ng_ksocket_accept_type_fields
43083186Sjulian};
43183186Sjulian
43253913Sarchie/* List of commands and how to convert arguments to/from ASCII */
43353913Sarchiestatic const struct ng_cmdlist ng_ksocket_cmds[] = {
43453913Sarchie	{
43553913Sarchie	  NGM_KSOCKET_COOKIE,
43653913Sarchie	  NGM_KSOCKET_BIND,
43753913Sarchie	  "bind",
43853913Sarchie	  &ng_ksocket_sockaddr_type,
43953913Sarchie	  NULL
44053913Sarchie	},
44153913Sarchie	{
44253913Sarchie	  NGM_KSOCKET_COOKIE,
44353913Sarchie	  NGM_KSOCKET_LISTEN,
44453913Sarchie	  "listen",
44553913Sarchie	  &ng_parse_int32_type,
44653913Sarchie	  NULL
44753913Sarchie	},
44853913Sarchie	{
44953913Sarchie	  NGM_KSOCKET_COOKIE,
45053913Sarchie	  NGM_KSOCKET_ACCEPT,
45153913Sarchie	  "accept",
45253913Sarchie	  NULL,
45383186Sjulian	  &ng_ksocket_accept_type
45453913Sarchie	},
45553913Sarchie	{
45653913Sarchie	  NGM_KSOCKET_COOKIE,
45753913Sarchie	  NGM_KSOCKET_CONNECT,
45853913Sarchie	  "connect",
45953913Sarchie	  &ng_ksocket_sockaddr_type,
46083186Sjulian	  &ng_parse_int32_type
46153913Sarchie	},
46253913Sarchie	{
46353913Sarchie	  NGM_KSOCKET_COOKIE,
46453913Sarchie	  NGM_KSOCKET_GETNAME,
46553913Sarchie	  "getname",
46653913Sarchie	  NULL,
46753913Sarchie	  &ng_ksocket_sockaddr_type
46853913Sarchie	},
46953913Sarchie	{
47053913Sarchie	  NGM_KSOCKET_COOKIE,
47153913Sarchie	  NGM_KSOCKET_GETPEERNAME,
47253913Sarchie	  "getpeername",
47353913Sarchie	  NULL,
47453913Sarchie	  &ng_ksocket_sockaddr_type
47553913Sarchie	},
47653913Sarchie	{
47753913Sarchie	  NGM_KSOCKET_COOKIE,
47853913Sarchie	  NGM_KSOCKET_SETOPT,
47953913Sarchie	  "setopt",
48053913Sarchie	  &ng_ksocket_sockopt_type,
48153913Sarchie	  NULL
48253913Sarchie	},
48353913Sarchie	{
48453913Sarchie	  NGM_KSOCKET_COOKIE,
48553913Sarchie	  NGM_KSOCKET_GETOPT,
48653913Sarchie	  "getopt",
48753913Sarchie	  &ng_ksocket_sockopt_type,
48853913Sarchie	  &ng_ksocket_sockopt_type
48953913Sarchie	},
49053913Sarchie	{ 0 }
49153913Sarchie};
49253913Sarchie
49353913Sarchie/* Node type descriptor */
49453913Sarchiestatic struct ng_type ng_ksocket_typestruct = {
495129823Sjulian	.version =	NG_ABI_VERSION,
496129823Sjulian	.name =		NG_KSOCKET_NODE_TYPE,
497129823Sjulian	.constructor =	ng_ksocket_constructor,
498129823Sjulian	.rcvmsg =	ng_ksocket_rcvmsg,
499129823Sjulian	.shutdown =	ng_ksocket_shutdown,
500129823Sjulian	.newhook =	ng_ksocket_newhook,
501129823Sjulian	.connect =	ng_ksocket_connect,
502129823Sjulian	.rcvdata =	ng_ksocket_rcvdata,
503129823Sjulian	.disconnect =	ng_ksocket_disconnect,
504129823Sjulian	.cmdlist =	ng_ksocket_cmds,
50553913Sarchie};
50653913SarchieNETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
50753913Sarchie
50897658Stanimura#define ERROUT(x)	do { error = (x); goto done; } while (0)
50953246Sarchie
51053246Sarchie/************************************************************************
51153246Sarchie			NETGRAPH NODE STUFF
51253246Sarchie ************************************************************************/
51353246Sarchie
51453246Sarchie/*
51553246Sarchie * Node type constructor
51683186Sjulian * The NODE part is assumed to be all set up.
51783186Sjulian * There is already a reference to the node for us.
51853246Sarchie */
51953246Sarchiestatic int
52070700Sjulianng_ksocket_constructor(node_p node)
52153246Sarchie{
52253246Sarchie	priv_p priv;
52353246Sarchie
52453246Sarchie	/* Allocate private structure */
52572545Sarchie	MALLOC(priv, priv_p, sizeof(*priv),
52672545Sarchie	    M_NETGRAPH_KSOCKET, M_NOWAIT | M_ZERO);
52753246Sarchie	if (priv == NULL)
52853246Sarchie		return (ENOMEM);
52953246Sarchie
53083186Sjulian	LIST_INIT(&priv->embryos);
53183186Sjulian	/* cross link them */
53283186Sjulian	priv->node = node;
53370784Sjulian	NG_NODE_SET_PRIVATE(node, priv);
53453246Sarchie
53553246Sarchie	/* Done */
53653246Sarchie	return (0);
53753246Sarchie}
53853246Sarchie
53953246Sarchie/*
54053246Sarchie * Give our OK for a hook to be added. The hook name is of the
54172545Sarchie * form "<family>/<type>/<proto>" where the three components may
54253246Sarchie * be decimal numbers or else aliases from the above lists.
54353246Sarchie *
54453246Sarchie * Connecting a hook amounts to opening the socket.  Disconnecting
54553246Sarchie * the hook closes the socket and destroys the node as well.
54653246Sarchie */
54753246Sarchiestatic int
54853246Sarchieng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
54953246Sarchie{
55090361Sjulian	struct thread *td = curthread ? curthread : &thread0;	/* XXX broken */
55170784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
552125028Sharti	char *s1, *s2, name[NG_HOOKSIZ];
55353246Sarchie	int family, type, protocol, error;
55453246Sarchie
55553246Sarchie	/* Check if we're already connected */
55653246Sarchie	if (priv->hook != NULL)
55753246Sarchie		return (EISCONN);
55853246Sarchie
55983186Sjulian	if (priv->flags & KSF_CLONED) {
56083186Sjulian		if (priv->flags & KSF_EMBRYONIC) {
56183186Sjulian			/* Remove ourselves from our parent's embryo list */
56283186Sjulian			LIST_REMOVE(priv, siblings);
56383186Sjulian			priv->flags &= ~KSF_EMBRYONIC;
56483186Sjulian		}
56583186Sjulian	} else {
56683186Sjulian		/* Extract family, type, and protocol from hook name */
56783186Sjulian		snprintf(name, sizeof(name), "%s", name0);
56883186Sjulian		s1 = name;
56983186Sjulian		if ((s2 = index(s1, '/')) == NULL)
57083186Sjulian			return (EINVAL);
57183186Sjulian		*s2++ = '\0';
57283186Sjulian		family = ng_ksocket_parse(ng_ksocket_families, s1, 0);
57383186Sjulian		if (family == -1)
57483186Sjulian			return (EINVAL);
57583186Sjulian		s1 = s2;
57683186Sjulian		if ((s2 = index(s1, '/')) == NULL)
57783186Sjulian			return (EINVAL);
57883186Sjulian		*s2++ = '\0';
57983186Sjulian		type = ng_ksocket_parse(ng_ksocket_types, s1, 0);
58083186Sjulian		if (type == -1)
58183186Sjulian			return (EINVAL);
58283186Sjulian		s1 = s2;
58383186Sjulian		protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family);
58483186Sjulian		if (protocol == -1)
58583186Sjulian			return (EINVAL);
58653246Sarchie
58783186Sjulian		/* Create the socket */
58888739Srwatson		error = socreate(family, &priv->so, type, protocol,
58991406Sjhb		   td->td_ucred, td);
59083186Sjulian		if (error != 0)
59183186Sjulian			return (error);
59253246Sarchie
59383186Sjulian		/* XXX call soreserve() ? */
59453246Sarchie
59583186Sjulian	}
59683186Sjulian
59783186Sjulian	/* OK */
59883186Sjulian	priv->hook = hook;
59983186Sjulian	return(0);
60083186Sjulian}
60183186Sjulian
60283186Sjulianstatic int
60383186Sjulianng_ksocket_connect(hook_p hook)
60483186Sjulian{
60583186Sjulian	node_p node = NG_HOOK_NODE(hook);
60683186Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
60783186Sjulian	struct socket *const so = priv->so;
60883186Sjulian
60983186Sjulian	/* Add our hook for incoming data and other events */
61053246Sarchie	priv->so->so_upcallarg = (caddr_t)node;
61153246Sarchie	priv->so->so_upcall = ng_ksocket_incoming;
61253246Sarchie	priv->so->so_rcv.sb_flags |= SB_UPCALL;
61383186Sjulian	priv->so->so_snd.sb_flags |= SB_UPCALL;
61483186Sjulian	priv->so->so_state |= SS_NBIO;
61583186Sjulian	/*
61683186Sjulian	 * --Original comment--
61783186Sjulian	 * On a cloned socket we may have already received one or more
61883186Sjulian	 * upcalls which we couldn't handle without a hook.  Handle
61983186Sjulian	 * those now.
62083186Sjulian	 * We cannot call the upcall function directly
62183186Sjulian	 * from here, because until this function has returned our
62283186Sjulian	 * hook isn't connected.
62383186Sjulian	 *
62483186Sjulian	 * ---meta comment for -current ---
62583186Sjulian	 * XXX This is dubius.
62683186Sjulian	 * Upcalls between the time that the hook was
62783186Sjulian	 * first created and now (on another processesor) will
62883186Sjulian	 * be earlier on the queue than the request to finalise the hook.
62983186Sjulian	 * By the time the hook is finalised,
63083186Sjulian	 * The queued upcalls will have happenned and the code
63183186Sjulian	 * will have discarded them because of a lack of a hook.
63283186Sjulian	 * (socket not open).
63383186Sjulian	 *
63483186Sjulian	 * This is a bad byproduct of the complicated way in which hooks
63583186Sjulian	 * are now created (3 daisy chained async events).
63683186Sjulian	 *
63783186Sjulian	 * Since we are a netgraph operation
63883186Sjulian	 * We know that we hold a lock on this node. This forces the
63983186Sjulian	 * request we make below to be queued rather than implemented
64083186Sjulian	 * immediatly which will cause the upcall function to be called a bit
64183186Sjulian	 * later.
64283186Sjulian	 * However, as we will run any waiting queued operations immediatly
64383186Sjulian	 * after doing this one, if we have not finalised the other end
64483186Sjulian	 * of the hook, those queued operations will fail.
64583186Sjulian	 */
64683186Sjulian	if (priv->flags & KSF_CLONED) {
64783186Sjulian		ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_NOWAIT);
64883186Sjulian	}
64953246Sarchie
65053246Sarchie	return (0);
65153246Sarchie}
65253246Sarchie
65353246Sarchie/*
65453246Sarchie * Receive a control message
65553246Sarchie */
65653246Sarchiestatic int
65770700Sjulianng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook)
65853246Sarchie{
65990361Sjulian	struct thread *td = curthread ? curthread : &thread0;	/* XXX broken */
66070784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
66153913Sarchie	struct socket *const so = priv->so;
66253246Sarchie	struct ng_mesg *resp = NULL;
66353246Sarchie	int error = 0;
66470700Sjulian	struct ng_mesg *msg;
66583186Sjulian	ng_ID_t raddr;
66653246Sarchie
66770700Sjulian	NGI_GET_MSG(item, msg);
66853246Sarchie	switch (msg->header.typecookie) {
66953246Sarchie	case NGM_KSOCKET_COOKIE:
67053246Sarchie		switch (msg->header.cmd) {
67153246Sarchie		case NGM_KSOCKET_BIND:
67253246Sarchie		    {
67353913Sarchie			struct sockaddr *const sa
67453913Sarchie			    = (struct sockaddr *)msg->data;
67553246Sarchie
67653913Sarchie			/* Sanity check */
67753913Sarchie			if (msg->header.arglen < SADATA_OFFSET
67853913Sarchie			    || msg->header.arglen < sa->sa_len)
67953913Sarchie				ERROUT(EINVAL);
68053913Sarchie			if (so == NULL)
68153913Sarchie				ERROUT(ENXIO);
68253246Sarchie
68353913Sarchie			/* Bind */
68483366Sjulian			error = sobind(so, sa, td);
68553246Sarchie			break;
68653246Sarchie		    }
68753246Sarchie		case NGM_KSOCKET_LISTEN:
68853246Sarchie		    {
68953913Sarchie			/* Sanity check */
69083186Sjulian			if (msg->header.arglen != sizeof(int32_t))
69153246Sarchie				ERROUT(EINVAL);
69253913Sarchie			if (so == NULL)
69353913Sarchie				ERROUT(ENXIO);
69453246Sarchie
69553913Sarchie			/* Listen */
69683366Sjulian			error = solisten(so, *((int32_t *)msg->data), td);
69753246Sarchie			break;
69853246Sarchie		    }
69953246Sarchie
70053246Sarchie		case NGM_KSOCKET_ACCEPT:
70153246Sarchie		    {
70253913Sarchie			/* Sanity check */
70353913Sarchie			if (msg->header.arglen != 0)
70453913Sarchie				ERROUT(EINVAL);
70553913Sarchie			if (so == NULL)
70653913Sarchie				ERROUT(ENXIO);
70753913Sarchie
70883186Sjulian			/* Make sure the socket is capable of accepting */
70983186Sjulian			if (!(so->so_options & SO_ACCEPTCONN))
71097658Stanimura				ERROUT(EINVAL);
71183186Sjulian			if (priv->flags & KSF_ACCEPTING)
71283186Sjulian				ERROUT(EALREADY);
71353913Sarchie
71483186Sjulian			error = ng_ksocket_check_accept(priv);
71583186Sjulian			if (error != 0 && error != EWOULDBLOCK)
71683186Sjulian				ERROUT(error);
71783186Sjulian
71883186Sjulian			/*
71983186Sjulian			 * If a connection is already complete, take it.
72083186Sjulian			 * Otherwise let the upcall function deal with
72183186Sjulian			 * the connection when it comes in.
72283186Sjulian			 */
72383186Sjulian			priv->response_token = msg->header.token;
724103205Sbenno			raddr = priv->response_addr = NGI_RETADDR(item);
72583186Sjulian			if (error == 0) {
72683186Sjulian				ng_ksocket_finish_accept(priv);
72783186Sjulian			} else
72883186Sjulian				priv->flags |= KSF_ACCEPTING;
72953246Sarchie			break;
73053246Sarchie		    }
73153246Sarchie
73253246Sarchie		case NGM_KSOCKET_CONNECT:
73353246Sarchie		    {
73453913Sarchie			struct sockaddr *const sa
73553913Sarchie			    = (struct sockaddr *)msg->data;
73653246Sarchie
73753913Sarchie			/* Sanity check */
73853913Sarchie			if (msg->header.arglen < SADATA_OFFSET
73953913Sarchie			    || msg->header.arglen < sa->sa_len)
74053913Sarchie				ERROUT(EINVAL);
74153913Sarchie			if (so == NULL)
74253913Sarchie				ERROUT(ENXIO);
74353246Sarchie
74453246Sarchie			/* Do connect */
74553246Sarchie			if ((so->so_state & SS_ISCONNECTING) != 0)
74697658Stanimura				ERROUT(EALREADY);
74783366Sjulian			if ((error = soconnect(so, sa, td)) != 0) {
74853246Sarchie				so->so_state &= ~SS_ISCONNECTING;
74997658Stanimura				ERROUT(error);
75053246Sarchie			}
751114178Sarchie			if ((so->so_state & SS_ISCONNECTING) != 0) {
75283186Sjulian				/* We will notify the sender when we connect */
75383186Sjulian				priv->response_token = msg->header.token;
754103205Sbenno				raddr = priv->response_addr = NGI_RETADDR(item);
75583186Sjulian				priv->flags |= KSF_CONNECTING;
75697658Stanimura				ERROUT(EINPROGRESS);
757114178Sarchie			}
75853246Sarchie			break;
75953246Sarchie		    }
76053246Sarchie
76153246Sarchie		case NGM_KSOCKET_GETNAME:
76253913Sarchie		case NGM_KSOCKET_GETPEERNAME:
76353246Sarchie		    {
76453913Sarchie			int (*func)(struct socket *so, struct sockaddr **nam);
76553913Sarchie			struct sockaddr *sa = NULL;
76653913Sarchie			int len;
76753246Sarchie
76853913Sarchie			/* Sanity check */
76953913Sarchie			if (msg->header.arglen != 0)
77053913Sarchie				ERROUT(EINVAL);
77153913Sarchie			if (so == NULL)
77253913Sarchie				ERROUT(ENXIO);
77353913Sarchie
77453913Sarchie			/* Get function */
77553913Sarchie			if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
77653913Sarchie				if ((so->so_state
77753913Sarchie				    & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
77897658Stanimura					ERROUT(ENOTCONN);
77953913Sarchie				func = so->so_proto->pr_usrreqs->pru_peeraddr;
78053913Sarchie			} else
78153913Sarchie				func = so->so_proto->pr_usrreqs->pru_sockaddr;
78253913Sarchie
78353913Sarchie			/* Get local or peer address */
78453913Sarchie			if ((error = (*func)(so, &sa)) != 0)
78553913Sarchie				goto bail;
78653913Sarchie			len = (sa == NULL) ? 0 : sa->sa_len;
78753913Sarchie
78853913Sarchie			/* Send it back in a response */
78953913Sarchie			NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
79053913Sarchie			if (resp == NULL) {
79153913Sarchie				error = ENOMEM;
79253913Sarchie				goto bail;
79353913Sarchie			}
79453913Sarchie			bcopy(sa, resp->data, len);
79553913Sarchie
79653913Sarchie		bail:
79753913Sarchie			/* Cleanup */
79853913Sarchie			if (sa != NULL)
79953913Sarchie				FREE(sa, M_SONAME);
80053246Sarchie			break;
80153246Sarchie		    }
80253246Sarchie
80353246Sarchie		case NGM_KSOCKET_GETOPT:
80453246Sarchie		    {
80553913Sarchie			struct ng_ksocket_sockopt *ksopt =
80653913Sarchie			    (struct ng_ksocket_sockopt *)msg->data;
80753913Sarchie			struct sockopt sopt;
80853913Sarchie
80953913Sarchie			/* Sanity check */
81053913Sarchie			if (msg->header.arglen != sizeof(*ksopt))
81153913Sarchie				ERROUT(EINVAL);
81253913Sarchie			if (so == NULL)
81353913Sarchie				ERROUT(ENXIO);
81453913Sarchie
81553913Sarchie			/* Get response with room for option value */
81653913Sarchie			NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
81753913Sarchie			    + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
81853913Sarchie			if (resp == NULL)
81953913Sarchie				ERROUT(ENOMEM);
82053913Sarchie
82153913Sarchie			/* Get socket option, and put value in the response */
82253913Sarchie			sopt.sopt_dir = SOPT_GET;
82353913Sarchie			sopt.sopt_level = ksopt->level;
82453913Sarchie			sopt.sopt_name = ksopt->name;
82583366Sjulian			sopt.sopt_td = NULL;
82653913Sarchie			sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
82753913Sarchie			ksopt = (struct ng_ksocket_sockopt *)resp->data;
82853913Sarchie			sopt.sopt_val = ksopt->value;
82953913Sarchie			if ((error = sogetopt(so, &sopt)) != 0) {
83070700Sjulian				NG_FREE_MSG(resp);
83153913Sarchie				break;
83253913Sarchie			}
83353913Sarchie
83453913Sarchie			/* Set actual value length */
83553913Sarchie			resp->header.arglen = sizeof(*ksopt)
83653913Sarchie			    + sopt.sopt_valsize;
83753246Sarchie			break;
83853246Sarchie		    }
83953246Sarchie
84053246Sarchie		case NGM_KSOCKET_SETOPT:
84153246Sarchie		    {
84253913Sarchie			struct ng_ksocket_sockopt *const ksopt =
84353913Sarchie			    (struct ng_ksocket_sockopt *)msg->data;
84453913Sarchie			const int valsize = msg->header.arglen - sizeof(*ksopt);
84553913Sarchie			struct sockopt sopt;
84653913Sarchie
84753913Sarchie			/* Sanity check */
84853913Sarchie			if (valsize < 0)
84953913Sarchie				ERROUT(EINVAL);
85053913Sarchie			if (so == NULL)
85153913Sarchie				ERROUT(ENXIO);
85253913Sarchie
85353913Sarchie			/* Set socket option */
85453913Sarchie			sopt.sopt_dir = SOPT_SET;
85553913Sarchie			sopt.sopt_level = ksopt->level;
85653913Sarchie			sopt.sopt_name = ksopt->name;
85753913Sarchie			sopt.sopt_val = ksopt->value;
85853913Sarchie			sopt.sopt_valsize = valsize;
85983366Sjulian			sopt.sopt_td = NULL;
86053913Sarchie			error = sosetopt(so, &sopt);
86153246Sarchie			break;
86253246Sarchie		    }
86353246Sarchie
86453246Sarchie		default:
86553246Sarchie			error = EINVAL;
86653246Sarchie			break;
86753246Sarchie		}
86853246Sarchie		break;
86953246Sarchie	default:
87053246Sarchie		error = EINVAL;
87153246Sarchie		break;
87253246Sarchie	}
87353246Sarchiedone:
87470700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
87570700Sjulian	NG_FREE_MSG(msg);
87653246Sarchie	return (error);
87753246Sarchie}
87853246Sarchie
87953246Sarchie/*
88053246Sarchie * Receive incoming data on our hook.  Send it out the socket.
88153246Sarchie */
88253246Sarchiestatic int
88370700Sjulianng_ksocket_rcvdata(hook_p hook, item_p item)
88453246Sarchie{
88590361Sjulian	struct thread *td = curthread ? curthread : &thread0;	/* XXX broken */
88670784Sjulian	const node_p node = NG_HOOK_NODE(hook);
88770784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
88853246Sarchie	struct socket *const so = priv->so;
88987070Sarchie	struct sockaddr *sa = NULL;
89087070Sarchie	meta_p meta;
89153246Sarchie	int error;
89270700Sjulian	struct mbuf *m;
89353246Sarchie
89488945Sarchie	/* Avoid reentrantly sending on the socket */
89588945Sarchie	if ((priv->flags & KSF_SENDING) != 0) {
89688945Sarchie		NG_FREE_ITEM(item);
89788945Sarchie		return (EDEADLK);
89888945Sarchie	}
89988945Sarchie
90087070Sarchie	/* Extract data and meta information */
90170700Sjulian	NGI_GET_M(item, m);
90287070Sarchie	NGI_GET_META(item, meta);
90370700Sjulian	NG_FREE_ITEM(item);
90487070Sarchie
90587070Sarchie	/* If any meta info, look for peer socket address */
90687070Sarchie	if (meta != NULL) {
90787070Sarchie		struct meta_field_header *field;
90887070Sarchie
90987070Sarchie		/* Look for peer socket address */
91087070Sarchie		for (field = &meta->options[0];
91187070Sarchie		    (caddr_t)field < (caddr_t)meta + meta->used_len;
91287070Sarchie		    field = (struct meta_field_header *)
91387070Sarchie		      ((caddr_t)field + field->len)) {
91487070Sarchie			if (field->cookie != NGM_KSOCKET_COOKIE
91587070Sarchie			    || field->type != NG_KSOCKET_META_SOCKADDR)
91687070Sarchie				continue;
91787070Sarchie			sa = (struct sockaddr *)field->data;
91887070Sarchie			break;
91987070Sarchie		}
92087070Sarchie	}
92187070Sarchie
92287070Sarchie	/* Send packet */
92388945Sarchie	priv->flags |= KSF_SENDING;
92487070Sarchie	error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, sa, 0, m, 0, 0, td);
92588945Sarchie	priv->flags &= ~KSF_SENDING;
92687070Sarchie
92787070Sarchie	/* Clean up and exit */
92887070Sarchie	NG_FREE_META(meta);
92953246Sarchie	return (error);
93053246Sarchie}
93153246Sarchie
93253246Sarchie/*
93353246Sarchie * Destroy node
93453246Sarchie */
93553246Sarchiestatic int
93670700Sjulianng_ksocket_shutdown(node_p node)
93753246Sarchie{
93870784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
93983186Sjulian	priv_p embryo;
94053246Sarchie
94153404Sarchie	/* Close our socket (if any) */
94253404Sarchie	if (priv->so != NULL) {
94353913Sarchie		priv->so->so_upcall = NULL;
94453913Sarchie		priv->so->so_rcv.sb_flags &= ~SB_UPCALL;
94583186Sjulian		priv->so->so_snd.sb_flags &= ~SB_UPCALL;
94653404Sarchie		soclose(priv->so);
94753404Sarchie		priv->so = NULL;
94853404Sarchie	}
94953404Sarchie
95083186Sjulian	/* If we are an embryo, take ourselves out of the parent's list */
95183186Sjulian	if (priv->flags & KSF_EMBRYONIC) {
95283186Sjulian		LIST_REMOVE(priv, siblings);
95383186Sjulian		priv->flags &= ~KSF_EMBRYONIC;
95483186Sjulian	}
95583186Sjulian
95683186Sjulian	/* Remove any embryonic children we have */
95783186Sjulian	while (!LIST_EMPTY(&priv->embryos)) {
95883186Sjulian		embryo = LIST_FIRST(&priv->embryos);
95983186Sjulian		ng_rmnode_self(embryo->node);
96083186Sjulian	}
96183186Sjulian
96253246Sarchie	/* Take down netgraph node */
96353246Sarchie	bzero(priv, sizeof(*priv));
96470870Sjulian	FREE(priv, M_NETGRAPH_KSOCKET);
96570784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
96670784Sjulian	NG_NODE_UNREF(node);		/* let the node escape */
96753246Sarchie	return (0);
96853246Sarchie}
96953246Sarchie
97053246Sarchie/*
97153246Sarchie * Hook disconnection
97253246Sarchie */
97353246Sarchiestatic int
97453246Sarchieng_ksocket_disconnect(hook_p hook)
97553246Sarchie{
97670784Sjulian	KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0,
97787599Sobrien	    ("%s: numhooks=%d?", __func__,
97872545Sarchie	    NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook))));
97970784Sjulian	if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))
98070784Sjulian		ng_rmnode_self(NG_HOOK_NODE(hook));
98153246Sarchie	return (0);
98253246Sarchie}
98353246Sarchie
98453246Sarchie/************************************************************************
98553246Sarchie			HELPER STUFF
98653246Sarchie ************************************************************************/
98783186Sjulian/*
98883186Sjulian * You should no-longer "just call" a netgraph node function
98983186Sjulian * from an external asynchronous event.
99083186Sjulian * This is because in doing so you are ignoring the locking on the netgraph
99183186Sjulian * nodes. Instead call your function via
99283186Sjulian * "int ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn,
99383186Sjulian *	 void *arg1, int arg2);"
99483186Sjulian * this will call the function you chose, but will first do all the
99583186Sjulian * locking rigmarole. Your function MAY only be called at some distant future
99683186Sjulian * time (several millisecs away) so don't give it any arguments
99783186Sjulian * that may be revoked soon (e.g. on your stack).
99883186Sjulian * In this case even the 'so' argument is doubtful.
99983186Sjulian * While the function request is being processed the node
100083186Sjulian * has an extra reference and as such will not disappear until
100183186Sjulian * the request has at least been done, but the 'so' may not be so lucky.
100283186Sjulian * handle this by checking the validity of the node in the target function
100383186Sjulian * before dereferencing the socket pointer.
100483186Sjulian */
100553246Sarchie
100683186Sjulianstatic void
100783186Sjulianng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
100883186Sjulian{
100983186Sjulian	const node_p node = arg;
101083186Sjulian
101183186Sjulian	ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, waitflag);
101283186Sjulian}
101383186Sjulian
101483186Sjulian
101553246Sarchie/*
101653246Sarchie * When incoming data is appended to the socket, we get notified here.
101783186Sjulian * This is also called whenever a significant event occurs for the socket.
101883186Sjulian * We know that HOOK is NULL. Because of how we were called we know we have a
101983186Sjulian * lock on this node an are participating inthe netgraph locking.
102083186Sjulian * Our original caller may have queued this even some time ago and
102183186Sjulian * we cannot trust that he even still exists. The node however is being
102283186Sjulian * held with a reference by the queueing code, at least until we finish,
102383186Sjulian * even if it has been zapped, so first check it's validiy
102483186Sjulian * before we trust the socket (which was derived from it).
102553246Sarchie */
102653246Sarchiestatic void
102783186Sjulianng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int waitflag)
102853246Sarchie{
102983186Sjulian	struct socket *so = arg1;
103070784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
103153246Sarchie	struct mbuf *m;
103283186Sjulian	struct ng_mesg *response;
103353246Sarchie	struct uio auio;
103453404Sarchie	int s, flags, error;
103553246Sarchie
103653404Sarchie	s = splnet();
103753404Sarchie
103853246Sarchie	/* Sanity check */
103970784Sjulian	if (NG_NODE_NOT_VALID(node)) {
104053404Sarchie		splx(s);
104153246Sarchie		return;
104253404Sarchie	}
104383186Sjulian	/* so = priv->so; *//* XXX could have derived this like so */
104487599Sobrien	KASSERT(so == priv->so, ("%s: wrong socket", __func__));
104553246Sarchie
104683186Sjulian	/* Check whether a pending connect operation has completed */
104783186Sjulian	if (priv->flags & KSF_CONNECTING) {
104883186Sjulian		if ((error = so->so_error) != 0) {
104983186Sjulian			so->so_error = 0;
105083186Sjulian			so->so_state &= ~SS_ISCONNECTING;
105183186Sjulian		}
105283186Sjulian		if (!(so->so_state & SS_ISCONNECTING)) {
105383186Sjulian			NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE,
105483186Sjulian			    NGM_KSOCKET_CONNECT, sizeof(int32_t), waitflag);
105583186Sjulian			if (response != NULL) {
105683186Sjulian				response->header.flags |= NGF_RESP;
105783186Sjulian				response->header.token = priv->response_token;
105883186Sjulian				*(int32_t *)response->data = error;
105983186Sjulian				/*
106083186Sjulian				 * send an async "response" message
106183186Sjulian				 * to the node that set us up
106283186Sjulian				 * (if it still exists)
106383186Sjulian				 */
1064102244Sarchie				NG_SEND_MSG_ID(error, node,
1065102244Sarchie				    response, priv->response_addr, 0);
106683186Sjulian			}
106783186Sjulian			priv->flags &= ~KSF_CONNECTING;
106897658Stanimura		}
106983186Sjulian	}
107083186Sjulian
107183186Sjulian	/* Check whether a pending accept operation has completed */
107283186Sjulian	if (priv->flags & KSF_ACCEPTING) {
107383186Sjulian		error = ng_ksocket_check_accept(priv);
107483186Sjulian		if (error != EWOULDBLOCK)
107583186Sjulian			priv->flags &= ~KSF_ACCEPTING;
107683186Sjulian		if (error == 0)
107783186Sjulian			ng_ksocket_finish_accept(priv);
107883186Sjulian	}
107983186Sjulian
108083186Sjulian	/*
108183186Sjulian	 * If we don't have a hook, we must handle data events later.  When
108283186Sjulian	 * the hook gets created and is connected, this upcall function
108383186Sjulian	 * will be called again.
108483186Sjulian	 */
108583186Sjulian	if (priv->hook == NULL) {
108683186Sjulian		splx(s);
108783186Sjulian		return;
108883186Sjulian	}
108983186Sjulian
109053246Sarchie	/* Read and forward available mbuf's */
109183366Sjulian	auio.uio_td = NULL;
109253246Sarchie	auio.uio_resid = 1000000000;
109353246Sarchie	flags = MSG_DONTWAIT;
109487070Sarchie	while (1) {
109587070Sarchie		struct sockaddr *sa = NULL;
109687070Sarchie		meta_p meta = NULL;
109787070Sarchie		struct mbuf *n;
109887070Sarchie
109987070Sarchie		/* Try to get next packet from socket */
110053246Sarchie		if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
110197658Stanimura		    (so, (so->so_state & SS_ISCONNECTED) ? NULL : &sa,
110287070Sarchie		    &auio, &m, (struct mbuf **)0, &flags)) != 0)
110387070Sarchie			break;
110453913Sarchie
110587070Sarchie		/* See if we got anything */
110687070Sarchie		if (m == NULL) {
110787070Sarchie			if (sa != NULL)
110887070Sarchie				FREE(sa, M_SONAME);
110987070Sarchie			break;
111053913Sarchie		}
111183186Sjulian
111287070Sarchie		/* Don't trust the various socket layers to get the
111387070Sarchie		   packet header and length correct (eg. kern/15175) */
111487070Sarchie		for (n = m, m->m_pkthdr.len = 0; n != NULL; n = n->m_next)
111587070Sarchie			m->m_pkthdr.len += n->m_len;
111687070Sarchie
111787070Sarchie		/* Put peer's socket address (if any) into a meta info blob */
111887070Sarchie		if (sa != NULL) {
111987070Sarchie			struct meta_field_header *mhead;
112087070Sarchie			u_int len;
112187070Sarchie
112287070Sarchie			len = sizeof(*meta) + sizeof(*mhead) + sa->sa_len;
1123123599Sru			MALLOC(meta, meta_p, len, M_NETGRAPH_META,
1124123599Sru			    M_NOWAIT | M_ZERO);
112587070Sarchie			if (meta == NULL) {
112687070Sarchie				FREE(sa, M_SONAME);
112787070Sarchie				goto sendit;
112887070Sarchie			}
112987070Sarchie			mhead = &meta->options[0];
113087070Sarchie			meta->allocated_len = len;
113187070Sarchie			meta->used_len = len;
113287070Sarchie			mhead->cookie = NGM_KSOCKET_COOKIE;
113387070Sarchie			mhead->type = NG_KSOCKET_META_SOCKADDR;
113487070Sarchie			mhead->len = sizeof(*mhead) + sa->sa_len;
113587070Sarchie			bcopy(sa, mhead->data, sa->sa_len);
113687070Sarchie			FREE(sa, M_SONAME);
113787070Sarchie		}
113887070Sarchie
113987070Sarchiesendit:		/* Forward data with optional peer sockaddr as meta info */
114087070Sarchie		NG_SEND_DATA(error, priv->hook, m, meta);
114187070Sarchie	}
114287070Sarchie
114383186Sjulian	/*
114483186Sjulian	 * If the peer has closed the connection, forward a 0-length mbuf
114583186Sjulian	 * to indicate end-of-file.
114683186Sjulian	 */
1147130480Srwatson	if (so->so_rcv.sb_state & SBS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) {
114883186Sjulian		MGETHDR(m, waitflag, MT_DATA);
114983186Sjulian		if (m != NULL) {
115083186Sjulian			m->m_len = m->m_pkthdr.len = 0;
115183186Sjulian			NG_SEND_DATA_ONLY(error, priv->hook, m);
115283186Sjulian		}
115383186Sjulian		priv->flags |= KSF_EOFSEEN;
115497658Stanimura	}
115553404Sarchie	splx(s);
115653246Sarchie}
115753246Sarchie
115853246Sarchie/*
115983186Sjulian * Check for a completed incoming connection and return 0 if one is found.
116083186Sjulian * Otherwise return the appropriate error code.
116183186Sjulian */
116283186Sjulianstatic int
116383186Sjulianng_ksocket_check_accept(priv_p priv)
116483186Sjulian{
116583186Sjulian	struct socket *const head = priv->so;
116683186Sjulian	int error;
116783186Sjulian
116883186Sjulian	if ((error = head->so_error) != 0) {
116983186Sjulian		head->so_error = 0;
117083186Sjulian		return error;
117183186Sjulian	}
1172129979Srwatson	/* Unlocked read. */
117383186Sjulian	if (TAILQ_EMPTY(&head->so_comp)) {
1174130480Srwatson		if (head->so_rcv.sb_state & SBS_CANTRCVMORE)
117583186Sjulian			return ECONNABORTED;
117683186Sjulian		return EWOULDBLOCK;
117783186Sjulian	}
117883186Sjulian	return 0;
117983186Sjulian}
118083186Sjulian
118183186Sjulian/*
118283186Sjulian * Handle the first completed incoming connection, assumed to be already
118383186Sjulian * on the socket's so_comp queue.
118483186Sjulian */
118583186Sjulianstatic void
118683186Sjulianng_ksocket_finish_accept(priv_p priv)
118783186Sjulian{
118883186Sjulian	struct socket *const head = priv->so;
118983186Sjulian	struct socket *so;
119083186Sjulian	struct sockaddr *sa = NULL;
119183186Sjulian	struct ng_mesg *resp;
119283186Sjulian	struct ng_ksocket_accept *resp_data;
119383186Sjulian	node_p node;
119483186Sjulian	priv_p priv2;
119583186Sjulian	int len;
119683186Sjulian	int error;
119783186Sjulian
1198129979Srwatson	ACCEPT_LOCK();
119983186Sjulian	so = TAILQ_FIRST(&head->so_comp);
1200129979Srwatson	if (so == NULL) {	/* Should never happen */
1201129979Srwatson		ACCEPT_UNLOCK();
120283186Sjulian		return;
1203129979Srwatson	}
120483186Sjulian	TAILQ_REMOVE(&head->so_comp, so, so_list);
120583186Sjulian	head->so_qlen--;
1206129979Srwatson	so->so_qstate &= ~SQ_COMP;
1207129979Srwatson	so->so_head = NULL;
1208130387Srwatson	SOCK_LOCK(so);
1209129979Srwatson	soref(so);
1210129979Srwatson	so->so_state |= SS_NBIO;
1211130387Srwatson	SOCK_UNLOCK(so);
1212129979Srwatson	ACCEPT_UNLOCK();
121383186Sjulian
121483186Sjulian	/* XXX KNOTE(&head->so_rcv.sb_sel.si_note, 0); */
121583186Sjulian
121683186Sjulian	soaccept(so, &sa);
121783186Sjulian
121883186Sjulian	len = OFFSETOF(struct ng_ksocket_accept, addr);
121983186Sjulian	if (sa != NULL)
122083186Sjulian		len += sa->sa_len;
122183186Sjulian
122283186Sjulian	NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len,
122383186Sjulian	    M_NOWAIT);
122483186Sjulian	if (resp == NULL) {
122583186Sjulian		soclose(so);
122683186Sjulian		goto out;
122783186Sjulian	}
122883186Sjulian	resp->header.flags |= NGF_RESP;
122983186Sjulian	resp->header.token = priv->response_token;
123083186Sjulian
123183186Sjulian	/* Clone a ksocket node to wrap the new socket */
123283186Sjulian        error = ng_make_node_common(&ng_ksocket_typestruct, &node);
123383186Sjulian        if (error) {
123483186Sjulian		FREE(resp, M_NETGRAPH);
123583186Sjulian		soclose(so);
123683186Sjulian		goto out;
123783186Sjulian	}
123883186Sjulian
123983186Sjulian	if (ng_ksocket_constructor(node) != 0) {
124083186Sjulian		NG_NODE_UNREF(node);
124183186Sjulian		FREE(resp, M_NETGRAPH);
124283186Sjulian		soclose(so);
124383186Sjulian		goto out;
124483186Sjulian	}
124583186Sjulian
124683186Sjulian	priv2 = NG_NODE_PRIVATE(node);
124783186Sjulian	priv2->so = so;
124883186Sjulian	priv2->flags |= KSF_CLONED | KSF_EMBRYONIC;
124983186Sjulian
125083186Sjulian	/*
125183186Sjulian	 * Insert the cloned node into a list of embryonic children
125283186Sjulian	 * on the parent node.  When a hook is created on the cloned
125383186Sjulian	 * node it will be removed from this list.  When the parent
125483186Sjulian	 * is destroyed it will destroy any embryonic children it has.
125583186Sjulian	 */
125683186Sjulian	LIST_INSERT_HEAD(&priv->embryos, priv2, siblings);
125783186Sjulian
125883186Sjulian	so->so_upcallarg = (caddr_t)node;
125983186Sjulian	so->so_upcall = ng_ksocket_incoming;
126083186Sjulian	so->so_rcv.sb_flags |= SB_UPCALL;
126183186Sjulian	so->so_snd.sb_flags |= SB_UPCALL;
126283186Sjulian
126383186Sjulian	/* Fill in the response data and send it or return it to the caller */
126483186Sjulian	resp_data = (struct ng_ksocket_accept *)resp->data;
126583186Sjulian	resp_data->nodeid = NG_NODE_ID(node);
126683186Sjulian	if (sa != NULL)
126783186Sjulian		bcopy(sa, &resp_data->addr, sa->sa_len);
1268102244Sarchie	NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0);
126983186Sjulian
127083186Sjulianout:
127183186Sjulian	if (sa != NULL)
127283186Sjulian		FREE(sa, M_SONAME);
127383186Sjulian}
127483186Sjulian
127583186Sjulian/*
127653246Sarchie * Parse out either an integer value or an alias.
127753246Sarchie */
127853246Sarchiestatic int
127953246Sarchieng_ksocket_parse(const struct ng_ksocket_alias *aliases,
128053246Sarchie	const char *s, int family)
128153246Sarchie{
128253246Sarchie	int k, val;
128353648Sarchie	char *eptr;
128453246Sarchie
128553246Sarchie	/* Try aliases */
128653246Sarchie	for (k = 0; aliases[k].name != NULL; k++) {
128753246Sarchie		if (strcmp(s, aliases[k].name) == 0
128853246Sarchie		    && aliases[k].family == family)
128953246Sarchie			return aliases[k].value;
129053246Sarchie	}
129153246Sarchie
129253246Sarchie	/* Try parsing as a number */
129353246Sarchie	val = (int)strtoul(s, &eptr, 10);
129453913Sarchie	if (val < 0 || *eptr != '\0')
129553246Sarchie		return (-1);
129653246Sarchie	return (val);
129753246Sarchie}
129853246Sarchie
1299