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