xref: /freebsd/sys/netgraph/ng_ksocket.c (revision 19bff684a4a3f6432b47e778d9ae73c5b4db5f2b)
1cb3c7a5dSArchie Cobbs 
2cb3c7a5dSArchie Cobbs /*
3cb3c7a5dSArchie Cobbs  * ng_ksocket.c
4cb3c7a5dSArchie Cobbs  *
5cb3c7a5dSArchie Cobbs  * Copyright (c) 1996-1999 Whistle Communications, Inc.
6cb3c7a5dSArchie Cobbs  * All rights reserved.
7cb3c7a5dSArchie Cobbs  *
8cb3c7a5dSArchie Cobbs  * Subject to the following obligations and disclaimer of warranty, use and
9cb3c7a5dSArchie Cobbs  * redistribution of this software, in source or object code forms, with or
10cb3c7a5dSArchie Cobbs  * without modifications are expressly permitted by Whistle Communications;
11cb3c7a5dSArchie Cobbs  * provided, however, that:
12cb3c7a5dSArchie Cobbs  * 1. Any and all reproductions of the source or object code must include the
13cb3c7a5dSArchie Cobbs  *    copyright notice above and the following disclaimer of warranties; and
14cb3c7a5dSArchie Cobbs  * 2. No rights are granted, in any manner or form, to use Whistle
15cb3c7a5dSArchie Cobbs  *    Communications, Inc. trademarks, including the mark "WHISTLE
16cb3c7a5dSArchie Cobbs  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17cb3c7a5dSArchie Cobbs  *    such appears in the above copyright notice or in the software.
18cb3c7a5dSArchie Cobbs  *
19cb3c7a5dSArchie Cobbs  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20cb3c7a5dSArchie Cobbs  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21cb3c7a5dSArchie Cobbs  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22cb3c7a5dSArchie Cobbs  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23cb3c7a5dSArchie Cobbs  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24cb3c7a5dSArchie Cobbs  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25cb3c7a5dSArchie Cobbs  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26cb3c7a5dSArchie Cobbs  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27cb3c7a5dSArchie Cobbs  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28cb3c7a5dSArchie Cobbs  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29cb3c7a5dSArchie Cobbs  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30cb3c7a5dSArchie Cobbs  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31cb3c7a5dSArchie Cobbs  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32cb3c7a5dSArchie Cobbs  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33cb3c7a5dSArchie Cobbs  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34cb3c7a5dSArchie Cobbs  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35cb3c7a5dSArchie Cobbs  * OF SUCH DAMAGE.
36cb3c7a5dSArchie Cobbs  *
37cb3c7a5dSArchie Cobbs  * Author: Archie Cobbs <archie@whistle.com>
38cb3c7a5dSArchie Cobbs  *
39cb3c7a5dSArchie Cobbs  * $FreeBSD$
40cb3c7a5dSArchie Cobbs  * $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $
41cb3c7a5dSArchie Cobbs  */
42cb3c7a5dSArchie Cobbs 
43cb3c7a5dSArchie Cobbs /*
44cb3c7a5dSArchie Cobbs  * Kernel socket node type.  This node type is basically a kernel-mode
45cb3c7a5dSArchie Cobbs  * version of a socket... kindof like the reverse of the socket node type.
46cb3c7a5dSArchie Cobbs  */
47cb3c7a5dSArchie Cobbs 
48cb3c7a5dSArchie Cobbs #include <sys/param.h>
49cb3c7a5dSArchie Cobbs #include <sys/systm.h>
50cb3c7a5dSArchie Cobbs #include <sys/kernel.h>
51cb3c7a5dSArchie Cobbs #include <sys/conf.h>
52cb3c7a5dSArchie Cobbs #include <sys/mbuf.h>
53cb3c7a5dSArchie Cobbs #include <sys/proc.h>
54cb3c7a5dSArchie Cobbs #include <sys/malloc.h>
55cb3c7a5dSArchie Cobbs #include <sys/protosw.h>
56cb3c7a5dSArchie Cobbs #include <sys/errno.h>
57cb3c7a5dSArchie Cobbs #include <sys/socket.h>
58cb3c7a5dSArchie Cobbs #include <sys/socketvar.h>
59cb3c7a5dSArchie Cobbs #include <sys/syslog.h>
60cb3c7a5dSArchie Cobbs #include <sys/uio.h>
61cb3c7a5dSArchie Cobbs 
62cb3c7a5dSArchie Cobbs #include <netgraph/ng_message.h>
63cb3c7a5dSArchie Cobbs #include <netgraph/netgraph.h>
64cb3c7a5dSArchie Cobbs #include <netgraph/ng_ksocket.h>
65cb3c7a5dSArchie Cobbs 
66cb3c7a5dSArchie Cobbs #include <netinet/in.h>
67cb3c7a5dSArchie Cobbs #include <netatalk/at.h>
68cb3c7a5dSArchie Cobbs 
69cb3c7a5dSArchie Cobbs /* Node private data */
7019bff684SArchie Cobbs struct ng_ksocket_private {
71cb3c7a5dSArchie Cobbs 	hook_p		hook;
72cb3c7a5dSArchie Cobbs 	struct socket	*so;
73cb3c7a5dSArchie Cobbs };
7419bff684SArchie Cobbs typedef struct ng_ksocket_private *priv_p;
75cb3c7a5dSArchie Cobbs 
76cb3c7a5dSArchie Cobbs /* Netgraph node methods */
77cb3c7a5dSArchie Cobbs static ng_constructor_t	ng_ksocket_constructor;
78cb3c7a5dSArchie Cobbs static ng_rcvmsg_t	ng_ksocket_rcvmsg;
79cb3c7a5dSArchie Cobbs static ng_shutdown_t	ng_ksocket_rmnode;
80cb3c7a5dSArchie Cobbs static ng_newhook_t	ng_ksocket_newhook;
81cb3c7a5dSArchie Cobbs static ng_rcvdata_t	ng_ksocket_rcvdata;
82cb3c7a5dSArchie Cobbs static ng_disconnect_t	ng_ksocket_disconnect;
83cb3c7a5dSArchie Cobbs 
84cb3c7a5dSArchie Cobbs /* Alias structure */
85cb3c7a5dSArchie Cobbs struct ng_ksocket_alias {
86cb3c7a5dSArchie Cobbs 	const char	*name;
87cb3c7a5dSArchie Cobbs 	const int	value;
88cb3c7a5dSArchie Cobbs 	const int	family;
89cb3c7a5dSArchie Cobbs };
90cb3c7a5dSArchie Cobbs 
91cb3c7a5dSArchie Cobbs /* Helper functions */
92cb3c7a5dSArchie Cobbs static void	ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
93cb3c7a5dSArchie Cobbs static int	ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
94cb3c7a5dSArchie Cobbs 			const char *s, int family);
95cb3c7a5dSArchie Cobbs 
96cb3c7a5dSArchie Cobbs /* Node type descriptor */
97cb3c7a5dSArchie Cobbs static struct ng_type ng_ksocket_typestruct = {
98cb3c7a5dSArchie Cobbs 	NG_VERSION,
99cb3c7a5dSArchie Cobbs 	NG_KSOCKET_NODE_TYPE,
100cb3c7a5dSArchie Cobbs 	NULL,
101cb3c7a5dSArchie Cobbs 	ng_ksocket_constructor,
102cb3c7a5dSArchie Cobbs 	ng_ksocket_rcvmsg,
103cb3c7a5dSArchie Cobbs 	ng_ksocket_rmnode,
104cb3c7a5dSArchie Cobbs 	ng_ksocket_newhook,
105cb3c7a5dSArchie Cobbs 	NULL,
106cb3c7a5dSArchie Cobbs 	NULL,
107cb3c7a5dSArchie Cobbs 	ng_ksocket_rcvdata,
108cb3c7a5dSArchie Cobbs 	ng_ksocket_rcvdata,
109cb3c7a5dSArchie Cobbs 	ng_ksocket_disconnect
110cb3c7a5dSArchie Cobbs };
111cb3c7a5dSArchie Cobbs NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
112cb3c7a5dSArchie Cobbs 
113cb3c7a5dSArchie Cobbs /* Protocol family aliases */
114cb3c7a5dSArchie Cobbs static const struct ng_ksocket_alias ng_ksocket_families[] = {
115cb3c7a5dSArchie Cobbs 	{ "local",	PF_LOCAL	},
116cb3c7a5dSArchie Cobbs 	{ "inet",	PF_INET		},
117cb3c7a5dSArchie Cobbs 	{ "inet6",	PF_INET6	},
118cb3c7a5dSArchie Cobbs 	{ "atalk",	PF_APPLETALK	},
119cb3c7a5dSArchie Cobbs 	{ "ipx",	PF_IPX		},
120cb3c7a5dSArchie Cobbs 	{ "atm",	PF_ATM		},
121cb3c7a5dSArchie Cobbs 	{ NULL,		-1		},
122cb3c7a5dSArchie Cobbs };
123cb3c7a5dSArchie Cobbs 
124cb3c7a5dSArchie Cobbs /* Socket type aliases */
125cb3c7a5dSArchie Cobbs static const struct ng_ksocket_alias ng_ksocket_types[] = {
126cb3c7a5dSArchie Cobbs 	{ "stream",	SOCK_STREAM	},
127cb3c7a5dSArchie Cobbs 	{ "dgram",	SOCK_DGRAM	},
128cb3c7a5dSArchie Cobbs 	{ "raw",	SOCK_RAW	},
129cb3c7a5dSArchie Cobbs 	{ "rdm",	SOCK_RDM	},
130cb3c7a5dSArchie Cobbs 	{ "seqpacket",	SOCK_SEQPACKET	},
131cb3c7a5dSArchie Cobbs 	{ NULL,		-1		},
132cb3c7a5dSArchie Cobbs };
133cb3c7a5dSArchie Cobbs 
134cb3c7a5dSArchie Cobbs /* Protocol aliases */
135cb3c7a5dSArchie Cobbs static const struct ng_ksocket_alias ng_ksocket_protos[] = {
136cb3c7a5dSArchie Cobbs 	{ "ip",		IPPROTO_IP,		PF_INET		},
137cb3c7a5dSArchie Cobbs 	{ "raw",	IPPROTO_IP,		PF_INET		},
138cb3c7a5dSArchie Cobbs 	{ "icmp",	IPPROTO_ICMP,		PF_INET		},
139cb3c7a5dSArchie Cobbs 	{ "igmp",	IPPROTO_IGMP,		PF_INET		},
140cb3c7a5dSArchie Cobbs 	{ "tcp",	IPPROTO_TCP,		PF_INET		},
141cb3c7a5dSArchie Cobbs 	{ "udp",	IPPROTO_UDP,		PF_INET		},
142cb3c7a5dSArchie Cobbs 	{ "gre",	IPPROTO_GRE,		PF_INET		},
143cb3c7a5dSArchie Cobbs 	{ "esp",	IPPROTO_ESP,		PF_INET		},
144cb3c7a5dSArchie Cobbs 	{ "ah",		IPPROTO_AH,		PF_INET		},
145cb3c7a5dSArchie Cobbs 	{ "swipe",	IPPROTO_SWIPE,		PF_INET		},
146cb3c7a5dSArchie Cobbs 	{ "encap",	IPPROTO_ENCAP,		PF_INET		},
147cb3c7a5dSArchie Cobbs 	{ "divert",	IPPROTO_DIVERT,		PF_INET		},
148cb3c7a5dSArchie Cobbs 	{ "ddp",	ATPROTO_DDP,		PF_APPLETALK	},
149cb3c7a5dSArchie Cobbs 	{ "aarp",	ATPROTO_AARP,		PF_APPLETALK	},
150cb3c7a5dSArchie Cobbs 	{ NULL,		-1					},
151cb3c7a5dSArchie Cobbs };
152cb3c7a5dSArchie Cobbs 
153cb3c7a5dSArchie Cobbs #define ERROUT(x)	do { error = (x); goto done; } while (0)
154cb3c7a5dSArchie Cobbs 
155cb3c7a5dSArchie Cobbs /************************************************************************
156cb3c7a5dSArchie Cobbs 			NETGRAPH NODE STUFF
157cb3c7a5dSArchie Cobbs  ************************************************************************/
158cb3c7a5dSArchie Cobbs 
159cb3c7a5dSArchie Cobbs /*
160cb3c7a5dSArchie Cobbs  * Node type constructor
161cb3c7a5dSArchie Cobbs  */
162cb3c7a5dSArchie Cobbs static int
163cb3c7a5dSArchie Cobbs ng_ksocket_constructor(node_p *nodep)
164cb3c7a5dSArchie Cobbs {
165cb3c7a5dSArchie Cobbs 	priv_p priv;
166cb3c7a5dSArchie Cobbs 	int error;
167cb3c7a5dSArchie Cobbs 
168cb3c7a5dSArchie Cobbs 	/* Allocate private structure */
169cb3c7a5dSArchie Cobbs 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
170cb3c7a5dSArchie Cobbs 	if (priv == NULL)
171cb3c7a5dSArchie Cobbs 		return (ENOMEM);
172cb3c7a5dSArchie Cobbs 	bzero(priv, sizeof(*priv));
173cb3c7a5dSArchie Cobbs 
174cb3c7a5dSArchie Cobbs 	/* Call generic node constructor */
175cb3c7a5dSArchie Cobbs 	if ((error = ng_make_node_common(&ng_ksocket_typestruct, nodep))) {
176cb3c7a5dSArchie Cobbs 		FREE(priv, M_NETGRAPH);
177cb3c7a5dSArchie Cobbs 		return (error);
178cb3c7a5dSArchie Cobbs 	}
179cb3c7a5dSArchie Cobbs 	(*nodep)->private = priv;
180cb3c7a5dSArchie Cobbs 
181cb3c7a5dSArchie Cobbs 	/* Done */
182cb3c7a5dSArchie Cobbs 	return (0);
183cb3c7a5dSArchie Cobbs }
184cb3c7a5dSArchie Cobbs 
185cb3c7a5dSArchie Cobbs /*
186cb3c7a5dSArchie Cobbs  * Give our OK for a hook to be added. The hook name is of the
187cb3c7a5dSArchie Cobbs  * form "<family>:<type>:<proto>" where the three components may
188cb3c7a5dSArchie Cobbs  * be decimal numbers or else aliases from the above lists.
189cb3c7a5dSArchie Cobbs  *
190cb3c7a5dSArchie Cobbs  * Connecting a hook amounts to opening the socket.  Disconnecting
191cb3c7a5dSArchie Cobbs  * the hook closes the socket and destroys the node as well.
192cb3c7a5dSArchie Cobbs  */
193cb3c7a5dSArchie Cobbs static int
194cb3c7a5dSArchie Cobbs ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
195cb3c7a5dSArchie Cobbs {
196cb3c7a5dSArchie Cobbs 	const priv_p priv = node->private;
197cb3c7a5dSArchie Cobbs 	char *s1, *s2, name[NG_HOOKLEN+1];
198cb3c7a5dSArchie Cobbs 	int family, type, protocol, error;
199cb3c7a5dSArchie Cobbs 	struct proc *p = &proc0;		/* XXX help what to do here */
200cb3c7a5dSArchie Cobbs 
201cb3c7a5dSArchie Cobbs 	/* Check if we're already connected */
202cb3c7a5dSArchie Cobbs 	if (priv->hook != NULL)
203cb3c7a5dSArchie Cobbs 		return (EISCONN);
204cb3c7a5dSArchie Cobbs 
205cb3c7a5dSArchie Cobbs 	/* Extract family, type, and protocol from hook name */
206cb3c7a5dSArchie Cobbs 	snprintf(name, sizeof(name), "%s", name0);
207cb3c7a5dSArchie Cobbs 	s1 = name;
208cb3c7a5dSArchie Cobbs 	if ((s2 = index(s1, '/')) == NULL)
209cb3c7a5dSArchie Cobbs 		return (EINVAL);
210cb3c7a5dSArchie Cobbs 	*s2++ = '\0';
211cb3c7a5dSArchie Cobbs 	if ((family = ng_ksocket_parse(ng_ksocket_families, s1, 0)) == -1)
212cb3c7a5dSArchie Cobbs 		return (EINVAL);
213cb3c7a5dSArchie Cobbs 	s1 = s2;
214cb3c7a5dSArchie Cobbs 	if ((s2 = index(s1, '/')) == NULL)
215cb3c7a5dSArchie Cobbs 		return (EINVAL);
216cb3c7a5dSArchie Cobbs 	*s2++ = '\0';
217cb3c7a5dSArchie Cobbs 	if ((type = ng_ksocket_parse(ng_ksocket_types, s1, 0)) == -1)
218cb3c7a5dSArchie Cobbs 		return (EINVAL);
219cb3c7a5dSArchie Cobbs 	s1 = s2;
220cb3c7a5dSArchie Cobbs 	if ((protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family)) == -1)
221cb3c7a5dSArchie Cobbs 		return (EINVAL);
222cb3c7a5dSArchie Cobbs 
223cb3c7a5dSArchie Cobbs 	/* Create the socket */
224cb3c7a5dSArchie Cobbs 	if ((error = socreate(family, &priv->so, type, protocol, p)) != 0)
225cb3c7a5dSArchie Cobbs 		return (error);
226cb3c7a5dSArchie Cobbs 
227cb3c7a5dSArchie Cobbs 	/* XXX call soreserve() ? */
228cb3c7a5dSArchie Cobbs 
229cb3c7a5dSArchie Cobbs 	/* Add our hook for incoming data */
230cb3c7a5dSArchie Cobbs 	priv->so->so_upcallarg = (caddr_t)node;
231cb3c7a5dSArchie Cobbs 	priv->so->so_upcall = ng_ksocket_incoming;
232cb3c7a5dSArchie Cobbs 	priv->so->so_rcv.sb_flags |= SB_UPCALL;
233cb3c7a5dSArchie Cobbs 
234cb3c7a5dSArchie Cobbs 	/* OK */
235cb3c7a5dSArchie Cobbs 	priv->hook = hook;
236cb3c7a5dSArchie Cobbs 	return (0);
237cb3c7a5dSArchie Cobbs }
238cb3c7a5dSArchie Cobbs 
239cb3c7a5dSArchie Cobbs /*
240cb3c7a5dSArchie Cobbs  * Receive a control message
241cb3c7a5dSArchie Cobbs  */
242cb3c7a5dSArchie Cobbs static int
243cb3c7a5dSArchie Cobbs ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
244cb3c7a5dSArchie Cobbs 	      const char *raddr, struct ng_mesg **rptr)
245cb3c7a5dSArchie Cobbs {
246cb3c7a5dSArchie Cobbs 	const priv_p priv = node->private;
247cb3c7a5dSArchie Cobbs 	struct ng_mesg *resp = NULL;
248cb3c7a5dSArchie Cobbs 	struct proc *p = &proc0;
249cb3c7a5dSArchie Cobbs 	int error = 0;
250cb3c7a5dSArchie Cobbs 
251cb3c7a5dSArchie Cobbs 	switch (msg->header.typecookie) {
252cb3c7a5dSArchie Cobbs 	case NGM_KSOCKET_COOKIE:
253cb3c7a5dSArchie Cobbs 		switch (msg->header.cmd) {
254cb3c7a5dSArchie Cobbs 		case NGM_KSOCKET_BIND:
255cb3c7a5dSArchie Cobbs 		    {
256cb3c7a5dSArchie Cobbs 			struct sockaddr *sa = (struct sockaddr *)msg->data;
257cb3c7a5dSArchie Cobbs 			struct socket *const so = priv->so;
258cb3c7a5dSArchie Cobbs 
259cb3c7a5dSArchie Cobbs 			/* Must have a connected hook first */
260cb3c7a5dSArchie Cobbs 			if (priv->hook == NULL)
261cb3c7a5dSArchie Cobbs 				ERROUT(ENETDOWN);
262cb3c7a5dSArchie Cobbs 
263cb3c7a5dSArchie Cobbs 			/* Set and sanity check sockaddr length */
264cb3c7a5dSArchie Cobbs 			if (msg->header.arglen > SOCK_MAXADDRLEN)
265cb3c7a5dSArchie Cobbs 				ERROUT(ENAMETOOLONG);
266cb3c7a5dSArchie Cobbs 			sa->sa_len = msg->header.arglen;
267cb3c7a5dSArchie Cobbs 			error = sobind(so, sa, p);
268cb3c7a5dSArchie Cobbs 			break;
269cb3c7a5dSArchie Cobbs 		    }
270cb3c7a5dSArchie Cobbs 		case NGM_KSOCKET_LISTEN:
271cb3c7a5dSArchie Cobbs 		    {
272cb3c7a5dSArchie Cobbs 			struct socket *const so = priv->so;
273cb3c7a5dSArchie Cobbs 			int backlog;
274cb3c7a5dSArchie Cobbs 
275cb3c7a5dSArchie Cobbs 			/* Must have a connected hook first */
276cb3c7a5dSArchie Cobbs 			if (priv->hook == NULL)
277cb3c7a5dSArchie Cobbs 				ERROUT(ENETDOWN);
278cb3c7a5dSArchie Cobbs 
279cb3c7a5dSArchie Cobbs 			/* Get backlog argument */
280cb3c7a5dSArchie Cobbs 			if (msg->header.arglen != sizeof(int))
281cb3c7a5dSArchie Cobbs 				ERROUT(EINVAL);
282cb3c7a5dSArchie Cobbs 			backlog = *((int *)msg->data);
283cb3c7a5dSArchie Cobbs 
284cb3c7a5dSArchie Cobbs 			/* Do listen */
285cb3c7a5dSArchie Cobbs 			if ((error = solisten(so, backlog, p)) != 0)
286cb3c7a5dSArchie Cobbs 				break;
287cb3c7a5dSArchie Cobbs 
288cb3c7a5dSArchie Cobbs 			/* Notify sender when we get a connection attempt */
289cb3c7a5dSArchie Cobbs 				/* XXX implement me */
290cb3c7a5dSArchie Cobbs 			break;
291cb3c7a5dSArchie Cobbs 		    }
292cb3c7a5dSArchie Cobbs 
293cb3c7a5dSArchie Cobbs 		case NGM_KSOCKET_ACCEPT:
294cb3c7a5dSArchie Cobbs 		    {
295cb3c7a5dSArchie Cobbs 			ERROUT(ENODEV);		/* XXX implement me */
296cb3c7a5dSArchie Cobbs 			break;
297cb3c7a5dSArchie Cobbs 		    }
298cb3c7a5dSArchie Cobbs 
299cb3c7a5dSArchie Cobbs 		case NGM_KSOCKET_CONNECT:
300cb3c7a5dSArchie Cobbs 		    {
301cb3c7a5dSArchie Cobbs 			struct socket *const so = priv->so;
302cb3c7a5dSArchie Cobbs 			struct sockaddr *sa = (struct sockaddr *)msg->data;
303cb3c7a5dSArchie Cobbs 
304cb3c7a5dSArchie Cobbs 			/* Must have a connected hook first */
305cb3c7a5dSArchie Cobbs 			if (priv->hook == NULL)
306cb3c7a5dSArchie Cobbs 				ERROUT(ENETDOWN);
307cb3c7a5dSArchie Cobbs 
308cb3c7a5dSArchie Cobbs 			/* Set and sanity check sockaddr length */
309cb3c7a5dSArchie Cobbs 			if (msg->header.arglen > SOCK_MAXADDRLEN)
310cb3c7a5dSArchie Cobbs 				ERROUT(ENAMETOOLONG);
311cb3c7a5dSArchie Cobbs 			sa->sa_len = msg->header.arglen;
312cb3c7a5dSArchie Cobbs 
313cb3c7a5dSArchie Cobbs 			/* Do connect */
314cb3c7a5dSArchie Cobbs 			if ((so->so_state & SS_ISCONNECTING) != 0)
315cb3c7a5dSArchie Cobbs 				ERROUT(EALREADY);
316cb3c7a5dSArchie Cobbs 			if ((error = soconnect(so, sa, p)) != 0) {
317cb3c7a5dSArchie Cobbs 				so->so_state &= ~SS_ISCONNECTING;
318cb3c7a5dSArchie Cobbs 				ERROUT(error);
319cb3c7a5dSArchie Cobbs 			}
320cb3c7a5dSArchie Cobbs 			if ((so->so_state & SS_ISCONNECTING) != 0)
321cb3c7a5dSArchie Cobbs 				/* Notify sender when we connect */
322cb3c7a5dSArchie Cobbs 				/* XXX implement me */
323cb3c7a5dSArchie Cobbs 				ERROUT(EINPROGRESS);
324cb3c7a5dSArchie Cobbs 			break;
325cb3c7a5dSArchie Cobbs 		    }
326cb3c7a5dSArchie Cobbs 
327cb3c7a5dSArchie Cobbs 		case NGM_KSOCKET_GETNAME:
328cb3c7a5dSArchie Cobbs 		    {
329cb3c7a5dSArchie Cobbs 			ERROUT(ENODEV);		/* XXX implement me */
330cb3c7a5dSArchie Cobbs 			break;
331cb3c7a5dSArchie Cobbs 		    }
332cb3c7a5dSArchie Cobbs 
333cb3c7a5dSArchie Cobbs 		case NGM_KSOCKET_GETPEERNAME:
334cb3c7a5dSArchie Cobbs 		    {
335cb3c7a5dSArchie Cobbs 			ERROUT(ENODEV);		/* XXX implement me */
336cb3c7a5dSArchie Cobbs 			break;
337cb3c7a5dSArchie Cobbs 		    }
338cb3c7a5dSArchie Cobbs 
339cb3c7a5dSArchie Cobbs 		case NGM_KSOCKET_GETOPT:
340cb3c7a5dSArchie Cobbs 		    {
341cb3c7a5dSArchie Cobbs 			ERROUT(ENODEV);		/* XXX implement me */
342cb3c7a5dSArchie Cobbs 			break;
343cb3c7a5dSArchie Cobbs 		    }
344cb3c7a5dSArchie Cobbs 
345cb3c7a5dSArchie Cobbs 		case NGM_KSOCKET_SETOPT:
346cb3c7a5dSArchie Cobbs 		    {
347cb3c7a5dSArchie Cobbs 			ERROUT(ENODEV);		/* XXX implement me */
348cb3c7a5dSArchie Cobbs 			break;
349cb3c7a5dSArchie Cobbs 		    }
350cb3c7a5dSArchie Cobbs 
351cb3c7a5dSArchie Cobbs 		default:
352cb3c7a5dSArchie Cobbs 			error = EINVAL;
353cb3c7a5dSArchie Cobbs 			break;
354cb3c7a5dSArchie Cobbs 		}
355cb3c7a5dSArchie Cobbs 		break;
356cb3c7a5dSArchie Cobbs 	default:
357cb3c7a5dSArchie Cobbs 		error = EINVAL;
358cb3c7a5dSArchie Cobbs 		break;
359cb3c7a5dSArchie Cobbs 	}
360cb3c7a5dSArchie Cobbs 	if (rptr)
361cb3c7a5dSArchie Cobbs 		*rptr = resp;
362cb3c7a5dSArchie Cobbs 	else if (resp)
363cb3c7a5dSArchie Cobbs 		FREE(resp, M_NETGRAPH);
364cb3c7a5dSArchie Cobbs 
365cb3c7a5dSArchie Cobbs done:
366cb3c7a5dSArchie Cobbs 	FREE(msg, M_NETGRAPH);
367cb3c7a5dSArchie Cobbs 	return (error);
368cb3c7a5dSArchie Cobbs }
369cb3c7a5dSArchie Cobbs 
370cb3c7a5dSArchie Cobbs /*
371cb3c7a5dSArchie Cobbs  * Receive incoming data on our hook.  Send it out the socket.
372cb3c7a5dSArchie Cobbs  */
373cb3c7a5dSArchie Cobbs static int
374cb3c7a5dSArchie Cobbs ng_ksocket_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
375cb3c7a5dSArchie Cobbs {
376cb3c7a5dSArchie Cobbs 	const node_p node = hook->node;
377cb3c7a5dSArchie Cobbs 	const priv_p priv = node->private;
378cb3c7a5dSArchie Cobbs 	struct socket *const so = priv->so;
379cb3c7a5dSArchie Cobbs 	struct proc *p = &proc0;
380cb3c7a5dSArchie Cobbs 	int error;
381cb3c7a5dSArchie Cobbs 
382cb3c7a5dSArchie Cobbs 	NG_FREE_META(meta);
383cb3c7a5dSArchie Cobbs 	error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, 0, 0, m, 0, 0, p);
384cb3c7a5dSArchie Cobbs 	return (error);
385cb3c7a5dSArchie Cobbs }
386cb3c7a5dSArchie Cobbs 
387cb3c7a5dSArchie Cobbs /*
388cb3c7a5dSArchie Cobbs  * Destroy node
389cb3c7a5dSArchie Cobbs  */
390cb3c7a5dSArchie Cobbs static int
391cb3c7a5dSArchie Cobbs ng_ksocket_rmnode(node_p node)
392cb3c7a5dSArchie Cobbs {
393cb3c7a5dSArchie Cobbs 	const priv_p priv = node->private;
394cb3c7a5dSArchie Cobbs 
39519bff684SArchie Cobbs 	/* Close our socket (if any) */
39619bff684SArchie Cobbs 	if (priv->so != NULL) {
39719bff684SArchie Cobbs 		soclose(priv->so);
39819bff684SArchie Cobbs 		priv->so = NULL;
39919bff684SArchie Cobbs 	}
40019bff684SArchie Cobbs 
401cb3c7a5dSArchie Cobbs 	/* Take down netgraph node */
402cb3c7a5dSArchie Cobbs 	node->flags |= NG_INVALID;
403cb3c7a5dSArchie Cobbs 	ng_cutlinks(node);
404cb3c7a5dSArchie Cobbs 	ng_unname(node);
405cb3c7a5dSArchie Cobbs 	bzero(priv, sizeof(*priv));
406cb3c7a5dSArchie Cobbs 	FREE(priv, M_NETGRAPH);
407cb3c7a5dSArchie Cobbs 	node->private = NULL;
408cb3c7a5dSArchie Cobbs 	ng_unref(node);		/* let the node escape */
409cb3c7a5dSArchie Cobbs 	return (0);
410cb3c7a5dSArchie Cobbs }
411cb3c7a5dSArchie Cobbs 
412cb3c7a5dSArchie Cobbs /*
413cb3c7a5dSArchie Cobbs  * Hook disconnection
414cb3c7a5dSArchie Cobbs  */
415cb3c7a5dSArchie Cobbs static int
416cb3c7a5dSArchie Cobbs ng_ksocket_disconnect(hook_p hook)
417cb3c7a5dSArchie Cobbs {
41819bff684SArchie Cobbs 	KASSERT(hook->node->numhooks == 0,
41919bff684SArchie Cobbs 	    ("%s: numhooks=%d?", __FUNCTION__, hook->node->numhooks));
420cb3c7a5dSArchie Cobbs 	ng_rmnode(hook->node);
421cb3c7a5dSArchie Cobbs 	return (0);
422cb3c7a5dSArchie Cobbs }
423cb3c7a5dSArchie Cobbs 
424cb3c7a5dSArchie Cobbs /************************************************************************
425cb3c7a5dSArchie Cobbs 			HELPER STUFF
426cb3c7a5dSArchie Cobbs  ************************************************************************/
427cb3c7a5dSArchie Cobbs 
428cb3c7a5dSArchie Cobbs /*
429cb3c7a5dSArchie Cobbs  * When incoming data is appended to the socket, we get notified here.
430cb3c7a5dSArchie Cobbs  */
431cb3c7a5dSArchie Cobbs static void
432cb3c7a5dSArchie Cobbs ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
433cb3c7a5dSArchie Cobbs {
434cb3c7a5dSArchie Cobbs 	const node_p node = arg;
435cb3c7a5dSArchie Cobbs 	const priv_p priv = node->private;
436cb3c7a5dSArchie Cobbs 	meta_p meta = NULL;
437cb3c7a5dSArchie Cobbs 	struct sockaddr *nam;
438cb3c7a5dSArchie Cobbs 	struct mbuf *m;
439cb3c7a5dSArchie Cobbs 	struct uio auio;
44019bff684SArchie Cobbs 	int s, flags, error;
44119bff684SArchie Cobbs 
44219bff684SArchie Cobbs 	s = splnet();
443cb3c7a5dSArchie Cobbs 
444cb3c7a5dSArchie Cobbs 	/* Sanity check */
44519bff684SArchie Cobbs 	if ((node->flags & NG_INVALID) != 0) {
44619bff684SArchie Cobbs 		splx(s);
447cb3c7a5dSArchie Cobbs 		return;
44819bff684SArchie Cobbs 	}
449cb3c7a5dSArchie Cobbs 	KASSERT(so == priv->so, ("%s: wrong socket", __FUNCTION__));
450cb3c7a5dSArchie Cobbs 	KASSERT(priv->hook != NULL, ("%s: no hook", __FUNCTION__));
451cb3c7a5dSArchie Cobbs 
452cb3c7a5dSArchie Cobbs 	/* Read and forward available mbuf's */
453cb3c7a5dSArchie Cobbs 	auio.uio_procp = NULL;
454cb3c7a5dSArchie Cobbs 	auio.uio_resid = 1000000000;
455cb3c7a5dSArchie Cobbs 	flags = MSG_DONTWAIT;
456cb3c7a5dSArchie Cobbs 	do {
457cb3c7a5dSArchie Cobbs 		if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
458cb3c7a5dSArchie Cobbs 		    (so, &nam, &auio, &m, (struct mbuf **)0, &flags)) == 0)
459cb3c7a5dSArchie Cobbs 			NG_SEND_DATA(error, priv->hook, m, meta);
460cb3c7a5dSArchie Cobbs 	} while (error == 0 && m != NULL);
46119bff684SArchie Cobbs 	splx(s);
462cb3c7a5dSArchie Cobbs }
463cb3c7a5dSArchie Cobbs 
464cb3c7a5dSArchie Cobbs /*
465cb3c7a5dSArchie Cobbs  * Parse out either an integer value or an alias.
466cb3c7a5dSArchie Cobbs  */
467cb3c7a5dSArchie Cobbs static int
468cb3c7a5dSArchie Cobbs ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
469cb3c7a5dSArchie Cobbs 	const char *s, int family)
470cb3c7a5dSArchie Cobbs {
471cb3c7a5dSArchie Cobbs 	int k, val;
472cb3c7a5dSArchie Cobbs 	const char *eptr;
473cb3c7a5dSArchie Cobbs 
474cb3c7a5dSArchie Cobbs 	/* Try aliases */
475cb3c7a5dSArchie Cobbs 	for (k = 0; aliases[k].name != NULL; k++) {
476cb3c7a5dSArchie Cobbs 		if (strcmp(s, aliases[k].name) == 0
477cb3c7a5dSArchie Cobbs 		    && aliases[k].family == family)
478cb3c7a5dSArchie Cobbs 			return aliases[k].value;
479cb3c7a5dSArchie Cobbs 	}
480cb3c7a5dSArchie Cobbs 
481cb3c7a5dSArchie Cobbs 	/* Try parsing as a number */
482cb3c7a5dSArchie Cobbs 	val = (int)strtoul(s, &eptr, 10);
483cb3c7a5dSArchie Cobbs 	if (val <= 0 || *eptr != '\0')
484cb3c7a5dSArchie Cobbs 		return (-1);
485cb3c7a5dSArchie Cobbs 	return (val);
486cb3c7a5dSArchie Cobbs }
487cb3c7a5dSArchie Cobbs 
488