ng_ksocket.c revision 119187
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 119187 2003-08-20 22:11:58Z hsu $
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 = {
49570159Sjulian	NG_ABI_VERSION,
49653913Sarchie	NG_KSOCKET_NODE_TYPE,
49753913Sarchie	NULL,
49853913Sarchie	ng_ksocket_constructor,
49953913Sarchie	ng_ksocket_rcvmsg,
50070700Sjulian	ng_ksocket_shutdown,
50153913Sarchie	ng_ksocket_newhook,
50253913Sarchie	NULL,
50383186Sjulian	ng_ksocket_connect,
50453913Sarchie	ng_ksocket_rcvdata,
50553913Sarchie	ng_ksocket_disconnect,
50653913Sarchie	ng_ksocket_cmds
50753913Sarchie};
50853913SarchieNETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
50953913Sarchie
51097658Stanimura#define ERROUT(x)	do { error = (x); goto done; } while (0)
51153246Sarchie
51253246Sarchie/************************************************************************
51353246Sarchie			NETGRAPH NODE STUFF
51453246Sarchie ************************************************************************/
51553246Sarchie
51653246Sarchie/*
51753246Sarchie * Node type constructor
51883186Sjulian * The NODE part is assumed to be all set up.
51983186Sjulian * There is already a reference to the node for us.
52053246Sarchie */
52153246Sarchiestatic int
52270700Sjulianng_ksocket_constructor(node_p node)
52353246Sarchie{
52453246Sarchie	priv_p priv;
52553246Sarchie
52653246Sarchie	/* Allocate private structure */
52772545Sarchie	MALLOC(priv, priv_p, sizeof(*priv),
52872545Sarchie	    M_NETGRAPH_KSOCKET, M_NOWAIT | M_ZERO);
52953246Sarchie	if (priv == NULL)
53053246Sarchie		return (ENOMEM);
53153246Sarchie
53283186Sjulian	LIST_INIT(&priv->embryos);
53383186Sjulian	/* cross link them */
53483186Sjulian	priv->node = node;
53570784Sjulian	NG_NODE_SET_PRIVATE(node, priv);
53653246Sarchie
53753246Sarchie	/* Done */
53853246Sarchie	return (0);
53953246Sarchie}
54053246Sarchie
54153246Sarchie/*
54253246Sarchie * Give our OK for a hook to be added. The hook name is of the
54372545Sarchie * form "<family>/<type>/<proto>" where the three components may
54453246Sarchie * be decimal numbers or else aliases from the above lists.
54553246Sarchie *
54653246Sarchie * Connecting a hook amounts to opening the socket.  Disconnecting
54753246Sarchie * the hook closes the socket and destroys the node as well.
54853246Sarchie */
54953246Sarchiestatic int
55053246Sarchieng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
55153246Sarchie{
55290361Sjulian	struct thread *td = curthread ? curthread : &thread0;	/* XXX broken */
55370784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
55453246Sarchie	char *s1, *s2, name[NG_HOOKLEN+1];
55553246Sarchie	int family, type, protocol, error;
55653246Sarchie
55753246Sarchie	/* Check if we're already connected */
55853246Sarchie	if (priv->hook != NULL)
55953246Sarchie		return (EISCONN);
56053246Sarchie
56183186Sjulian	if (priv->flags & KSF_CLONED) {
56283186Sjulian		if (priv->flags & KSF_EMBRYONIC) {
56383186Sjulian			/* Remove ourselves from our parent's embryo list */
56483186Sjulian			LIST_REMOVE(priv, siblings);
56583186Sjulian			priv->flags &= ~KSF_EMBRYONIC;
56683186Sjulian		}
56783186Sjulian	} else {
56883186Sjulian		/* Extract family, type, and protocol from hook name */
56983186Sjulian		snprintf(name, sizeof(name), "%s", name0);
57083186Sjulian		s1 = name;
57183186Sjulian		if ((s2 = index(s1, '/')) == NULL)
57283186Sjulian			return (EINVAL);
57383186Sjulian		*s2++ = '\0';
57483186Sjulian		family = ng_ksocket_parse(ng_ksocket_families, s1, 0);
57583186Sjulian		if (family == -1)
57683186Sjulian			return (EINVAL);
57783186Sjulian		s1 = s2;
57883186Sjulian		if ((s2 = index(s1, '/')) == NULL)
57983186Sjulian			return (EINVAL);
58083186Sjulian		*s2++ = '\0';
58183186Sjulian		type = ng_ksocket_parse(ng_ksocket_types, s1, 0);
58283186Sjulian		if (type == -1)
58383186Sjulian			return (EINVAL);
58483186Sjulian		s1 = s2;
58583186Sjulian		protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family);
58683186Sjulian		if (protocol == -1)
58783186Sjulian			return (EINVAL);
58853246Sarchie
58983186Sjulian		/* Create the socket */
59088739Srwatson		error = socreate(family, &priv->so, type, protocol,
59191406Sjhb		   td->td_ucred, td);
59283186Sjulian		if (error != 0)
59383186Sjulian			return (error);
59453246Sarchie
59583186Sjulian		/* XXX call soreserve() ? */
59653246Sarchie
59783186Sjulian	}
59883186Sjulian
59983186Sjulian	/* OK */
60083186Sjulian	priv->hook = hook;
60183186Sjulian	return(0);
60283186Sjulian}
60383186Sjulian
60483186Sjulianstatic int
60583186Sjulianng_ksocket_connect(hook_p hook)
60683186Sjulian{
60783186Sjulian	node_p node = NG_HOOK_NODE(hook);
60883186Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
60983186Sjulian	struct socket *const so = priv->so;
61083186Sjulian
61183186Sjulian	/* Add our hook for incoming data and other events */
61253246Sarchie	priv->so->so_upcallarg = (caddr_t)node;
61353246Sarchie	priv->so->so_upcall = ng_ksocket_incoming;
61453246Sarchie	priv->so->so_rcv.sb_flags |= SB_UPCALL;
61583186Sjulian	priv->so->so_snd.sb_flags |= SB_UPCALL;
61683186Sjulian	priv->so->so_state |= SS_NBIO;
61783186Sjulian	/*
61883186Sjulian	 * --Original comment--
61983186Sjulian	 * On a cloned socket we may have already received one or more
62083186Sjulian	 * upcalls which we couldn't handle without a hook.  Handle
62183186Sjulian	 * those now.
62283186Sjulian	 * We cannot call the upcall function directly
62383186Sjulian	 * from here, because until this function has returned our
62483186Sjulian	 * hook isn't connected.
62583186Sjulian	 *
62683186Sjulian	 * ---meta comment for -current ---
62783186Sjulian	 * XXX This is dubius.
62883186Sjulian	 * Upcalls between the time that the hook was
62983186Sjulian	 * first created and now (on another processesor) will
63083186Sjulian	 * be earlier on the queue than the request to finalise the hook.
63183186Sjulian	 * By the time the hook is finalised,
63283186Sjulian	 * The queued upcalls will have happenned and the code
63383186Sjulian	 * will have discarded them because of a lack of a hook.
63483186Sjulian	 * (socket not open).
63583186Sjulian	 *
63683186Sjulian	 * This is a bad byproduct of the complicated way in which hooks
63783186Sjulian	 * are now created (3 daisy chained async events).
63883186Sjulian	 *
63983186Sjulian	 * Since we are a netgraph operation
64083186Sjulian	 * We know that we hold a lock on this node. This forces the
64183186Sjulian	 * request we make below to be queued rather than implemented
64283186Sjulian	 * immediatly which will cause the upcall function to be called a bit
64383186Sjulian	 * later.
64483186Sjulian	 * However, as we will run any waiting queued operations immediatly
64583186Sjulian	 * after doing this one, if we have not finalised the other end
64683186Sjulian	 * of the hook, those queued operations will fail.
64783186Sjulian	 */
64883186Sjulian	if (priv->flags & KSF_CLONED) {
64983186Sjulian		ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_NOWAIT);
65083186Sjulian	}
65153246Sarchie
65253246Sarchie	return (0);
65353246Sarchie}
65453246Sarchie
65553246Sarchie/*
65653246Sarchie * Receive a control message
65753246Sarchie */
65853246Sarchiestatic int
65970700Sjulianng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook)
66053246Sarchie{
66190361Sjulian	struct thread *td = curthread ? curthread : &thread0;	/* XXX broken */
66270784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
66353913Sarchie	struct socket *const so = priv->so;
66453246Sarchie	struct ng_mesg *resp = NULL;
66553246Sarchie	int error = 0;
66670700Sjulian	struct ng_mesg *msg;
66783186Sjulian	ng_ID_t raddr;
66853246Sarchie
66970700Sjulian	NGI_GET_MSG(item, msg);
67053246Sarchie	switch (msg->header.typecookie) {
67153246Sarchie	case NGM_KSOCKET_COOKIE:
67253246Sarchie		switch (msg->header.cmd) {
67353246Sarchie		case NGM_KSOCKET_BIND:
67453246Sarchie		    {
67553913Sarchie			struct sockaddr *const sa
67653913Sarchie			    = (struct sockaddr *)msg->data;
67753246Sarchie
67853913Sarchie			/* Sanity check */
67953913Sarchie			if (msg->header.arglen < SADATA_OFFSET
68053913Sarchie			    || msg->header.arglen < sa->sa_len)
68153913Sarchie				ERROUT(EINVAL);
68253913Sarchie			if (so == NULL)
68353913Sarchie				ERROUT(ENXIO);
68453246Sarchie
68553913Sarchie			/* Bind */
68683366Sjulian			error = sobind(so, sa, td);
68753246Sarchie			break;
68853246Sarchie		    }
68953246Sarchie		case NGM_KSOCKET_LISTEN:
69053246Sarchie		    {
69153913Sarchie			/* Sanity check */
69283186Sjulian			if (msg->header.arglen != sizeof(int32_t))
69353246Sarchie				ERROUT(EINVAL);
69453913Sarchie			if (so == NULL)
69553913Sarchie				ERROUT(ENXIO);
69653246Sarchie
69753913Sarchie			/* Listen */
69883366Sjulian			error = solisten(so, *((int32_t *)msg->data), td);
69953246Sarchie			break;
70053246Sarchie		    }
70153246Sarchie
70253246Sarchie		case NGM_KSOCKET_ACCEPT:
70353246Sarchie		    {
70453913Sarchie			/* Sanity check */
70553913Sarchie			if (msg->header.arglen != 0)
70653913Sarchie				ERROUT(EINVAL);
70753913Sarchie			if (so == NULL)
70853913Sarchie				ERROUT(ENXIO);
70953913Sarchie
71083186Sjulian			/* Make sure the socket is capable of accepting */
71183186Sjulian			if (!(so->so_options & SO_ACCEPTCONN))
71297658Stanimura				ERROUT(EINVAL);
71383186Sjulian			if (priv->flags & KSF_ACCEPTING)
71483186Sjulian				ERROUT(EALREADY);
71553913Sarchie
71683186Sjulian			error = ng_ksocket_check_accept(priv);
71783186Sjulian			if (error != 0 && error != EWOULDBLOCK)
71883186Sjulian				ERROUT(error);
71983186Sjulian
72083186Sjulian			/*
72183186Sjulian			 * If a connection is already complete, take it.
72283186Sjulian			 * Otherwise let the upcall function deal with
72383186Sjulian			 * the connection when it comes in.
72483186Sjulian			 */
72583186Sjulian			priv->response_token = msg->header.token;
726103205Sbenno			raddr = priv->response_addr = NGI_RETADDR(item);
72783186Sjulian			if (error == 0) {
72883186Sjulian				ng_ksocket_finish_accept(priv);
72983186Sjulian			} else
73083186Sjulian				priv->flags |= KSF_ACCEPTING;
73153246Sarchie			break;
73253246Sarchie		    }
73353246Sarchie
73453246Sarchie		case NGM_KSOCKET_CONNECT:
73553246Sarchie		    {
73653913Sarchie			struct sockaddr *const sa
73753913Sarchie			    = (struct sockaddr *)msg->data;
73853246Sarchie
73953913Sarchie			/* Sanity check */
74053913Sarchie			if (msg->header.arglen < SADATA_OFFSET
74153913Sarchie			    || msg->header.arglen < sa->sa_len)
74253913Sarchie				ERROUT(EINVAL);
74353913Sarchie			if (so == NULL)
74453913Sarchie				ERROUT(ENXIO);
74553246Sarchie
74653246Sarchie			/* Do connect */
74753246Sarchie			if ((so->so_state & SS_ISCONNECTING) != 0)
74897658Stanimura				ERROUT(EALREADY);
74983366Sjulian			if ((error = soconnect(so, sa, td)) != 0) {
75053246Sarchie				so->so_state &= ~SS_ISCONNECTING;
75197658Stanimura				ERROUT(error);
75253246Sarchie			}
753114178Sarchie			if ((so->so_state & SS_ISCONNECTING) != 0) {
75483186Sjulian				/* We will notify the sender when we connect */
75583186Sjulian				priv->response_token = msg->header.token;
756103205Sbenno				raddr = priv->response_addr = NGI_RETADDR(item);
75783186Sjulian				priv->flags |= KSF_CONNECTING;
75897658Stanimura				ERROUT(EINPROGRESS);
759114178Sarchie			}
76053246Sarchie			break;
76153246Sarchie		    }
76253246Sarchie
76353246Sarchie		case NGM_KSOCKET_GETNAME:
76453913Sarchie		case NGM_KSOCKET_GETPEERNAME:
76553246Sarchie		    {
76653913Sarchie			int (*func)(struct socket *so, struct sockaddr **nam);
76753913Sarchie			struct sockaddr *sa = NULL;
76853913Sarchie			int len;
76953246Sarchie
77053913Sarchie			/* Sanity check */
77153913Sarchie			if (msg->header.arglen != 0)
77253913Sarchie				ERROUT(EINVAL);
77353913Sarchie			if (so == NULL)
77453913Sarchie				ERROUT(ENXIO);
77553913Sarchie
77653913Sarchie			/* Get function */
77753913Sarchie			if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
77853913Sarchie				if ((so->so_state
77953913Sarchie				    & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
78097658Stanimura					ERROUT(ENOTCONN);
78153913Sarchie				func = so->so_proto->pr_usrreqs->pru_peeraddr;
78253913Sarchie			} else
78353913Sarchie				func = so->so_proto->pr_usrreqs->pru_sockaddr;
78453913Sarchie
78553913Sarchie			/* Get local or peer address */
78653913Sarchie			if ((error = (*func)(so, &sa)) != 0)
78753913Sarchie				goto bail;
78853913Sarchie			len = (sa == NULL) ? 0 : sa->sa_len;
78953913Sarchie
79053913Sarchie			/* Send it back in a response */
79153913Sarchie			NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
79253913Sarchie			if (resp == NULL) {
79353913Sarchie				error = ENOMEM;
79453913Sarchie				goto bail;
79553913Sarchie			}
79653913Sarchie			bcopy(sa, resp->data, len);
79753913Sarchie
79853913Sarchie		bail:
79953913Sarchie			/* Cleanup */
80053913Sarchie			if (sa != NULL)
80153913Sarchie				FREE(sa, M_SONAME);
80253246Sarchie			break;
80353246Sarchie		    }
80453246Sarchie
80553246Sarchie		case NGM_KSOCKET_GETOPT:
80653246Sarchie		    {
80753913Sarchie			struct ng_ksocket_sockopt *ksopt =
80853913Sarchie			    (struct ng_ksocket_sockopt *)msg->data;
80953913Sarchie			struct sockopt sopt;
81053913Sarchie
81153913Sarchie			/* Sanity check */
81253913Sarchie			if (msg->header.arglen != sizeof(*ksopt))
81353913Sarchie				ERROUT(EINVAL);
81453913Sarchie			if (so == NULL)
81553913Sarchie				ERROUT(ENXIO);
81653913Sarchie
81753913Sarchie			/* Get response with room for option value */
81853913Sarchie			NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
81953913Sarchie			    + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
82053913Sarchie			if (resp == NULL)
82153913Sarchie				ERROUT(ENOMEM);
82253913Sarchie
82353913Sarchie			/* Get socket option, and put value in the response */
82453913Sarchie			sopt.sopt_dir = SOPT_GET;
82553913Sarchie			sopt.sopt_level = ksopt->level;
82653913Sarchie			sopt.sopt_name = ksopt->name;
82783366Sjulian			sopt.sopt_td = NULL;
82853913Sarchie			sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
82953913Sarchie			ksopt = (struct ng_ksocket_sockopt *)resp->data;
83053913Sarchie			sopt.sopt_val = ksopt->value;
83153913Sarchie			if ((error = sogetopt(so, &sopt)) != 0) {
83270700Sjulian				NG_FREE_MSG(resp);
83353913Sarchie				break;
83453913Sarchie			}
83553913Sarchie
83653913Sarchie			/* Set actual value length */
83753913Sarchie			resp->header.arglen = sizeof(*ksopt)
83853913Sarchie			    + sopt.sopt_valsize;
83953246Sarchie			break;
84053246Sarchie		    }
84153246Sarchie
84253246Sarchie		case NGM_KSOCKET_SETOPT:
84353246Sarchie		    {
84453913Sarchie			struct ng_ksocket_sockopt *const ksopt =
84553913Sarchie			    (struct ng_ksocket_sockopt *)msg->data;
84653913Sarchie			const int valsize = msg->header.arglen - sizeof(*ksopt);
84753913Sarchie			struct sockopt sopt;
84853913Sarchie
84953913Sarchie			/* Sanity check */
85053913Sarchie			if (valsize < 0)
85153913Sarchie				ERROUT(EINVAL);
85253913Sarchie			if (so == NULL)
85353913Sarchie				ERROUT(ENXIO);
85453913Sarchie
85553913Sarchie			/* Set socket option */
85653913Sarchie			sopt.sopt_dir = SOPT_SET;
85753913Sarchie			sopt.sopt_level = ksopt->level;
85853913Sarchie			sopt.sopt_name = ksopt->name;
85953913Sarchie			sopt.sopt_val = ksopt->value;
86053913Sarchie			sopt.sopt_valsize = valsize;
86183366Sjulian			sopt.sopt_td = NULL;
86253913Sarchie			error = sosetopt(so, &sopt);
86353246Sarchie			break;
86453246Sarchie		    }
86553246Sarchie
86653246Sarchie		default:
86753246Sarchie			error = EINVAL;
86853246Sarchie			break;
86953246Sarchie		}
87053246Sarchie		break;
87153246Sarchie	default:
87253246Sarchie		error = EINVAL;
87353246Sarchie		break;
87453246Sarchie	}
87553246Sarchiedone:
87670700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
87770700Sjulian	NG_FREE_MSG(msg);
87853246Sarchie	return (error);
87953246Sarchie}
88053246Sarchie
88153246Sarchie/*
88253246Sarchie * Receive incoming data on our hook.  Send it out the socket.
88353246Sarchie */
88453246Sarchiestatic int
88570700Sjulianng_ksocket_rcvdata(hook_p hook, item_p item)
88653246Sarchie{
88790361Sjulian	struct thread *td = curthread ? curthread : &thread0;	/* XXX broken */
88870784Sjulian	const node_p node = NG_HOOK_NODE(hook);
88970784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
89053246Sarchie	struct socket *const so = priv->so;
89187070Sarchie	struct sockaddr *sa = NULL;
89287070Sarchie	meta_p meta;
89353246Sarchie	int error;
89470700Sjulian	struct mbuf *m;
89553246Sarchie
89688945Sarchie	/* Avoid reentrantly sending on the socket */
89788945Sarchie	if ((priv->flags & KSF_SENDING) != 0) {
89888945Sarchie		NG_FREE_ITEM(item);
89988945Sarchie		return (EDEADLK);
90088945Sarchie	}
90188945Sarchie
90287070Sarchie	/* Extract data and meta information */
90370700Sjulian	NGI_GET_M(item, m);
90487070Sarchie	NGI_GET_META(item, meta);
90570700Sjulian	NG_FREE_ITEM(item);
90687070Sarchie
90787070Sarchie	/* If any meta info, look for peer socket address */
90887070Sarchie	if (meta != NULL) {
90987070Sarchie		struct meta_field_header *field;
91087070Sarchie
91187070Sarchie		/* Look for peer socket address */
91287070Sarchie		for (field = &meta->options[0];
91387070Sarchie		    (caddr_t)field < (caddr_t)meta + meta->used_len;
91487070Sarchie		    field = (struct meta_field_header *)
91587070Sarchie		      ((caddr_t)field + field->len)) {
91687070Sarchie			if (field->cookie != NGM_KSOCKET_COOKIE
91787070Sarchie			    || field->type != NG_KSOCKET_META_SOCKADDR)
91887070Sarchie				continue;
91987070Sarchie			sa = (struct sockaddr *)field->data;
92087070Sarchie			break;
92187070Sarchie		}
92287070Sarchie	}
92387070Sarchie
92487070Sarchie	/* Send packet */
92588945Sarchie	priv->flags |= KSF_SENDING;
92687070Sarchie	error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, sa, 0, m, 0, 0, td);
92788945Sarchie	priv->flags &= ~KSF_SENDING;
92887070Sarchie
92987070Sarchie	/* Clean up and exit */
93087070Sarchie	NG_FREE_META(meta);
93153246Sarchie	return (error);
93253246Sarchie}
93353246Sarchie
93453246Sarchie/*
93553246Sarchie * Destroy node
93653246Sarchie */
93753246Sarchiestatic int
93870700Sjulianng_ksocket_shutdown(node_p node)
93953246Sarchie{
94070784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
94183186Sjulian	priv_p embryo;
94253246Sarchie
94353404Sarchie	/* Close our socket (if any) */
94453404Sarchie	if (priv->so != NULL) {
94553913Sarchie		priv->so->so_upcall = NULL;
94653913Sarchie		priv->so->so_rcv.sb_flags &= ~SB_UPCALL;
94783186Sjulian		priv->so->so_snd.sb_flags &= ~SB_UPCALL;
94853404Sarchie		soclose(priv->so);
94953404Sarchie		priv->so = NULL;
95053404Sarchie	}
95153404Sarchie
95283186Sjulian	/* If we are an embryo, take ourselves out of the parent's list */
95383186Sjulian	if (priv->flags & KSF_EMBRYONIC) {
95483186Sjulian		LIST_REMOVE(priv, siblings);
95583186Sjulian		priv->flags &= ~KSF_EMBRYONIC;
95683186Sjulian	}
95783186Sjulian
95883186Sjulian	/* Remove any embryonic children we have */
95983186Sjulian	while (!LIST_EMPTY(&priv->embryos)) {
96083186Sjulian		embryo = LIST_FIRST(&priv->embryos);
96183186Sjulian		ng_rmnode_self(embryo->node);
96283186Sjulian	}
96383186Sjulian
96453246Sarchie	/* Take down netgraph node */
96553246Sarchie	bzero(priv, sizeof(*priv));
96670870Sjulian	FREE(priv, M_NETGRAPH_KSOCKET);
96770784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
96870784Sjulian	NG_NODE_UNREF(node);		/* let the node escape */
96953246Sarchie	return (0);
97053246Sarchie}
97153246Sarchie
97253246Sarchie/*
97353246Sarchie * Hook disconnection
97453246Sarchie */
97553246Sarchiestatic int
97653246Sarchieng_ksocket_disconnect(hook_p hook)
97753246Sarchie{
97870784Sjulian	KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0,
97987599Sobrien	    ("%s: numhooks=%d?", __func__,
98072545Sarchie	    NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook))));
98170784Sjulian	if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))
98270784Sjulian		ng_rmnode_self(NG_HOOK_NODE(hook));
98353246Sarchie	return (0);
98453246Sarchie}
98553246Sarchie
98653246Sarchie/************************************************************************
98753246Sarchie			HELPER STUFF
98853246Sarchie ************************************************************************/
98983186Sjulian/*
99083186Sjulian * You should no-longer "just call" a netgraph node function
99183186Sjulian * from an external asynchronous event.
99283186Sjulian * This is because in doing so you are ignoring the locking on the netgraph
99383186Sjulian * nodes. Instead call your function via
99483186Sjulian * "int ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn,
99583186Sjulian *	 void *arg1, int arg2);"
99683186Sjulian * this will call the function you chose, but will first do all the
99783186Sjulian * locking rigmarole. Your function MAY only be called at some distant future
99883186Sjulian * time (several millisecs away) so don't give it any arguments
99983186Sjulian * that may be revoked soon (e.g. on your stack).
100083186Sjulian * In this case even the 'so' argument is doubtful.
100183186Sjulian * While the function request is being processed the node
100283186Sjulian * has an extra reference and as such will not disappear until
100383186Sjulian * the request has at least been done, but the 'so' may not be so lucky.
100483186Sjulian * handle this by checking the validity of the node in the target function
100583186Sjulian * before dereferencing the socket pointer.
100683186Sjulian */
100753246Sarchie
100883186Sjulianstatic void
100983186Sjulianng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
101083186Sjulian{
101183186Sjulian	const node_p node = arg;
101283186Sjulian
101383186Sjulian	ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, waitflag);
101483186Sjulian}
101583186Sjulian
101683186Sjulian
101753246Sarchie/*
101853246Sarchie * When incoming data is appended to the socket, we get notified here.
101983186Sjulian * This is also called whenever a significant event occurs for the socket.
102083186Sjulian * We know that HOOK is NULL. Because of how we were called we know we have a
102183186Sjulian * lock on this node an are participating inthe netgraph locking.
102283186Sjulian * Our original caller may have queued this even some time ago and
102383186Sjulian * we cannot trust that he even still exists. The node however is being
102483186Sjulian * held with a reference by the queueing code, at least until we finish,
102583186Sjulian * even if it has been zapped, so first check it's validiy
102683186Sjulian * before we trust the socket (which was derived from it).
102753246Sarchie */
102853246Sarchiestatic void
102983186Sjulianng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int waitflag)
103053246Sarchie{
103183186Sjulian	struct socket *so = arg1;
103270784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
103353246Sarchie	struct mbuf *m;
103483186Sjulian	struct ng_mesg *response;
103553246Sarchie	struct uio auio;
103653404Sarchie	int s, flags, error;
103753246Sarchie
103853404Sarchie	s = splnet();
103953404Sarchie
104053246Sarchie	/* Sanity check */
104170784Sjulian	if (NG_NODE_NOT_VALID(node)) {
104253404Sarchie		splx(s);
104353246Sarchie		return;
104453404Sarchie	}
104583186Sjulian	/* so = priv->so; *//* XXX could have derived this like so */
104687599Sobrien	KASSERT(so == priv->so, ("%s: wrong socket", __func__));
104753246Sarchie
104883186Sjulian	/* Check whether a pending connect operation has completed */
104983186Sjulian	if (priv->flags & KSF_CONNECTING) {
105083186Sjulian		if ((error = so->so_error) != 0) {
105183186Sjulian			so->so_error = 0;
105283186Sjulian			so->so_state &= ~SS_ISCONNECTING;
105383186Sjulian		}
105483186Sjulian		if (!(so->so_state & SS_ISCONNECTING)) {
105583186Sjulian			NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE,
105683186Sjulian			    NGM_KSOCKET_CONNECT, sizeof(int32_t), waitflag);
105783186Sjulian			if (response != NULL) {
105883186Sjulian				response->header.flags |= NGF_RESP;
105983186Sjulian				response->header.token = priv->response_token;
106083186Sjulian				*(int32_t *)response->data = error;
106183186Sjulian				/*
106283186Sjulian				 * send an async "response" message
106383186Sjulian				 * to the node that set us up
106483186Sjulian				 * (if it still exists)
106583186Sjulian				 */
1066102244Sarchie				NG_SEND_MSG_ID(error, node,
1067102244Sarchie				    response, priv->response_addr, 0);
106883186Sjulian			}
106983186Sjulian			priv->flags &= ~KSF_CONNECTING;
107097658Stanimura		}
107183186Sjulian	}
107283186Sjulian
107383186Sjulian	/* Check whether a pending accept operation has completed */
107483186Sjulian	if (priv->flags & KSF_ACCEPTING) {
107583186Sjulian		error = ng_ksocket_check_accept(priv);
107683186Sjulian		if (error != EWOULDBLOCK)
107783186Sjulian			priv->flags &= ~KSF_ACCEPTING;
107883186Sjulian		if (error == 0)
107983186Sjulian			ng_ksocket_finish_accept(priv);
108083186Sjulian	}
108183186Sjulian
108283186Sjulian	/*
108383186Sjulian	 * If we don't have a hook, we must handle data events later.  When
108483186Sjulian	 * the hook gets created and is connected, this upcall function
108583186Sjulian	 * will be called again.
108683186Sjulian	 */
108783186Sjulian	if (priv->hook == NULL) {
108883186Sjulian		splx(s);
108983186Sjulian		return;
109083186Sjulian	}
109183186Sjulian
109253246Sarchie	/* Read and forward available mbuf's */
109383366Sjulian	auio.uio_td = NULL;
109453246Sarchie	auio.uio_resid = 1000000000;
109553246Sarchie	flags = MSG_DONTWAIT;
109687070Sarchie	while (1) {
109787070Sarchie		struct sockaddr *sa = NULL;
109887070Sarchie		meta_p meta = NULL;
109987070Sarchie		struct mbuf *n;
110087070Sarchie
110187070Sarchie		/* Try to get next packet from socket */
110253246Sarchie		if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
110397658Stanimura		    (so, (so->so_state & SS_ISCONNECTED) ? NULL : &sa,
110487070Sarchie		    &auio, &m, (struct mbuf **)0, &flags)) != 0)
110587070Sarchie			break;
110653913Sarchie
110787070Sarchie		/* See if we got anything */
110887070Sarchie		if (m == NULL) {
110987070Sarchie			if (sa != NULL)
111087070Sarchie				FREE(sa, M_SONAME);
111187070Sarchie			break;
111253913Sarchie		}
111383186Sjulian
111487070Sarchie		/* Don't trust the various socket layers to get the
111587070Sarchie		   packet header and length correct (eg. kern/15175) */
111687070Sarchie		for (n = m, m->m_pkthdr.len = 0; n != NULL; n = n->m_next)
111787070Sarchie			m->m_pkthdr.len += n->m_len;
111887070Sarchie
111987070Sarchie		/* Put peer's socket address (if any) into a meta info blob */
112087070Sarchie		if (sa != NULL) {
112187070Sarchie			struct meta_field_header *mhead;
112287070Sarchie			u_int len;
112387070Sarchie
112487070Sarchie			len = sizeof(*meta) + sizeof(*mhead) + sa->sa_len;
112587070Sarchie			MALLOC(meta, meta_p, len, M_NETGRAPH_META, M_NOWAIT);
112687070Sarchie			if (meta == NULL) {
112787070Sarchie				FREE(sa, M_SONAME);
112887070Sarchie				goto sendit;
112987070Sarchie			}
113087070Sarchie			mhead = &meta->options[0];
113187070Sarchie			bzero(meta, sizeof(*meta));
113287070Sarchie			bzero(mhead, sizeof(*mhead));
113387070Sarchie			meta->allocated_len = len;
113487070Sarchie			meta->used_len = len;
113587070Sarchie			mhead->cookie = NGM_KSOCKET_COOKIE;
113687070Sarchie			mhead->type = NG_KSOCKET_META_SOCKADDR;
113787070Sarchie			mhead->len = sizeof(*mhead) + sa->sa_len;
113887070Sarchie			bcopy(sa, mhead->data, sa->sa_len);
113987070Sarchie			FREE(sa, M_SONAME);
114087070Sarchie		}
114187070Sarchie
114287070Sarchiesendit:		/* Forward data with optional peer sockaddr as meta info */
114387070Sarchie		NG_SEND_DATA(error, priv->hook, m, meta);
114487070Sarchie	}
114587070Sarchie
114683186Sjulian	/*
114783186Sjulian	 * If the peer has closed the connection, forward a 0-length mbuf
114883186Sjulian	 * to indicate end-of-file.
114983186Sjulian	 */
115083186Sjulian	if (so->so_state & SS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) {
115183186Sjulian		MGETHDR(m, waitflag, MT_DATA);
115283186Sjulian		if (m != NULL) {
115383186Sjulian			m->m_len = m->m_pkthdr.len = 0;
115483186Sjulian			NG_SEND_DATA_ONLY(error, priv->hook, m);
115583186Sjulian		}
115683186Sjulian		priv->flags |= KSF_EOFSEEN;
115797658Stanimura	}
115853404Sarchie	splx(s);
115953246Sarchie}
116053246Sarchie
116153246Sarchie/*
116283186Sjulian * Check for a completed incoming connection and return 0 if one is found.
116383186Sjulian * Otherwise return the appropriate error code.
116483186Sjulian */
116583186Sjulianstatic int
116683186Sjulianng_ksocket_check_accept(priv_p priv)
116783186Sjulian{
116883186Sjulian	struct socket *const head = priv->so;
116983186Sjulian	int error;
117083186Sjulian
117183186Sjulian	if ((error = head->so_error) != 0) {
117283186Sjulian		head->so_error = 0;
117383186Sjulian		return error;
117483186Sjulian	}
117583186Sjulian	if (TAILQ_EMPTY(&head->so_comp)) {
117697658Stanimura		if (head->so_state & SS_CANTRCVMORE)
117783186Sjulian			return ECONNABORTED;
117883186Sjulian		return EWOULDBLOCK;
117983186Sjulian	}
118083186Sjulian	return 0;
118183186Sjulian}
118283186Sjulian
118383186Sjulian/*
118483186Sjulian * Handle the first completed incoming connection, assumed to be already
118583186Sjulian * on the socket's so_comp queue.
118683186Sjulian */
118783186Sjulianstatic void
118883186Sjulianng_ksocket_finish_accept(priv_p priv)
118983186Sjulian{
119083186Sjulian	struct socket *const head = priv->so;
119183186Sjulian	struct socket *so;
119283186Sjulian	struct sockaddr *sa = NULL;
119383186Sjulian	struct ng_mesg *resp;
119483186Sjulian	struct ng_ksocket_accept *resp_data;
119583186Sjulian	node_p node;
119683186Sjulian	priv_p priv2;
119783186Sjulian	int len;
119883186Sjulian	int error;
119983186Sjulian
120083186Sjulian	so = TAILQ_FIRST(&head->so_comp);
120183186Sjulian	if (so == NULL)		/* Should never happen */
120283186Sjulian		return;
120383186Sjulian	TAILQ_REMOVE(&head->so_comp, so, so_list);
120483186Sjulian	head->so_qlen--;
120583186Sjulian
120683186Sjulian	/* XXX KNOTE(&head->so_rcv.sb_sel.si_note, 0); */
120783186Sjulian
1208103313Sbenno	soref(so);
1209103313Sbenno
121083186Sjulian	so->so_state &= ~SS_COMP;
121183186Sjulian	so->so_state |= SS_NBIO;
121283186Sjulian	so->so_head = NULL;
121383186Sjulian
121483186Sjulian	soaccept(so, &sa);
121583186Sjulian
121683186Sjulian	len = OFFSETOF(struct ng_ksocket_accept, addr);
121783186Sjulian	if (sa != NULL)
121883186Sjulian		len += sa->sa_len;
121983186Sjulian
122083186Sjulian	NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len,
122183186Sjulian	    M_NOWAIT);
122283186Sjulian	if (resp == NULL) {
122383186Sjulian		soclose(so);
122483186Sjulian		goto out;
122583186Sjulian	}
122683186Sjulian	resp->header.flags |= NGF_RESP;
122783186Sjulian	resp->header.token = priv->response_token;
122883186Sjulian
122983186Sjulian	/* Clone a ksocket node to wrap the new socket */
123083186Sjulian        error = ng_make_node_common(&ng_ksocket_typestruct, &node);
123183186Sjulian        if (error) {
123283186Sjulian		FREE(resp, M_NETGRAPH);
123383186Sjulian		soclose(so);
123483186Sjulian		goto out;
123583186Sjulian	}
123683186Sjulian
123783186Sjulian	if (ng_ksocket_constructor(node) != 0) {
123883186Sjulian		NG_NODE_UNREF(node);
123983186Sjulian		FREE(resp, M_NETGRAPH);
124083186Sjulian		soclose(so);
124183186Sjulian		goto out;
124283186Sjulian	}
124383186Sjulian
124483186Sjulian	priv2 = NG_NODE_PRIVATE(node);
124583186Sjulian	priv2->so = so;
124683186Sjulian	priv2->flags |= KSF_CLONED | KSF_EMBRYONIC;
124783186Sjulian
124883186Sjulian	/*
124983186Sjulian	 * Insert the cloned node into a list of embryonic children
125083186Sjulian	 * on the parent node.  When a hook is created on the cloned
125183186Sjulian	 * node it will be removed from this list.  When the parent
125283186Sjulian	 * is destroyed it will destroy any embryonic children it has.
125383186Sjulian	 */
125483186Sjulian	LIST_INSERT_HEAD(&priv->embryos, priv2, siblings);
125583186Sjulian
125683186Sjulian	so->so_upcallarg = (caddr_t)node;
125783186Sjulian	so->so_upcall = ng_ksocket_incoming;
125883186Sjulian	so->so_rcv.sb_flags |= SB_UPCALL;
125983186Sjulian	so->so_snd.sb_flags |= SB_UPCALL;
126083186Sjulian
126183186Sjulian	/* Fill in the response data and send it or return it to the caller */
126283186Sjulian	resp_data = (struct ng_ksocket_accept *)resp->data;
126383186Sjulian	resp_data->nodeid = NG_NODE_ID(node);
126483186Sjulian	if (sa != NULL)
126583186Sjulian		bcopy(sa, &resp_data->addr, sa->sa_len);
1266102244Sarchie	NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0);
126783186Sjulian
126883186Sjulianout:
126983186Sjulian	if (sa != NULL)
127083186Sjulian		FREE(sa, M_SONAME);
127183186Sjulian}
127283186Sjulian
127383186Sjulian/*
127453246Sarchie * Parse out either an integer value or an alias.
127553246Sarchie */
127653246Sarchiestatic int
127753246Sarchieng_ksocket_parse(const struct ng_ksocket_alias *aliases,
127853246Sarchie	const char *s, int family)
127953246Sarchie{
128053246Sarchie	int k, val;
128153648Sarchie	char *eptr;
128253246Sarchie
128353246Sarchie	/* Try aliases */
128453246Sarchie	for (k = 0; aliases[k].name != NULL; k++) {
128553246Sarchie		if (strcmp(s, aliases[k].name) == 0
128653246Sarchie		    && aliases[k].family == family)
128753246Sarchie			return aliases[k].value;
128853246Sarchie	}
128953246Sarchie
129053246Sarchie	/* Try parsing as a number */
129153246Sarchie	val = (int)strtoul(s, &eptr, 10);
129253913Sarchie	if (val < 0 || *eptr != '\0')
129353246Sarchie		return (-1);
129453246Sarchie	return (val);
129553246Sarchie}
129653246Sarchie
1297