ng_socket.c revision 83366
152419Sjulian
252419Sjulian/*
352419Sjulian * ng_socket.c
452419Sjulian *
552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc.
652419Sjulian * All rights reserved.
770784Sjulian *
852419Sjulian * Subject to the following obligations and disclaimer of warranty, use and
952419Sjulian * redistribution of this software, in source or object code forms, with or
1052419Sjulian * without modifications are expressly permitted by Whistle Communications;
1152419Sjulian * provided, however, that:
1252419Sjulian * 1. Any and all reproductions of the source or object code must include the
1352419Sjulian *    copyright notice above and the following disclaimer of warranties; and
1452419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle
1552419Sjulian *    Communications, Inc. trademarks, including the mark "WHISTLE
1652419Sjulian *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1752419Sjulian *    such appears in the above copyright notice or in the software.
1870784Sjulian *
1952419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2052419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2152419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2252419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2352419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2452419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2552419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2652419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2752419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2852419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2952419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3052419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3152419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3252419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3352419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3452419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3552419Sjulian * OF SUCH DAMAGE.
3652419Sjulian *
3767506Sjulian * Author: Julian Elischer <julian@freebsd.org>
3852419Sjulian *
3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_socket.c 83366 2001-09-12 08:38:13Z julian $
4052752Sjulian * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $
4152419Sjulian */
4252419Sjulian
4352419Sjulian/*
4452419Sjulian * Netgraph socket nodes
4552419Sjulian *
4652419Sjulian * There are two types of netgraph sockets, control and data.
4752419Sjulian * Control sockets have a netgraph node, but data sockets are
4852419Sjulian * parasitic on control sockets, and have no node of their own.
4952419Sjulian */
5052419Sjulian
5152419Sjulian#include <sys/param.h>
5252419Sjulian#include <sys/systm.h>
5352419Sjulian#include <sys/domain.h>
5452419Sjulian#include <sys/errno.h>
5552419Sjulian#include <sys/kernel.h>
5652419Sjulian#include <sys/filedesc.h>
5752419Sjulian#include <sys/malloc.h>
5852419Sjulian#include <sys/queue.h>
5952419Sjulian#include <sys/mbuf.h>
6052419Sjulian#include <sys/protosw.h>
6152419Sjulian#include <sys/socket.h>
6252419Sjulian#include <sys/socketvar.h>
6352419Sjulian#include <sys/sysctl.h>
6452419Sjulian#ifdef NOTYET
6552419Sjulian#include <sys/vnode.h>
6652419Sjulian#endif
6752419Sjulian#include <netgraph/ng_message.h>
6852419Sjulian#include <netgraph/netgraph.h>
6952919Sjulian#include <netgraph/ng_socketvar.h>
7052419Sjulian#include <netgraph/ng_socket.h>
7152419Sjulian
7270870Sjulian#ifdef NG_SEPARATE_MALLOC
7370870SjulianMALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info ");
7470870SjulianMALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info ");
7570870Sjulian#else
7670870Sjulian#define M_NETGRAPH_PATH M_NETGRAPH
7770870Sjulian#define M_NETGRAPH_SOCK M_NETGRAPH
7870870Sjulian#endif
7970870Sjulian
8052419Sjulian/*
8152419Sjulian * It's Ascii-art time!
8252419Sjulian *   +-------------+   +-------------+
8352419Sjulian *   |socket  (ctl)|   |socket (data)|
8452419Sjulian *   +-------------+   +-------------+
8552419Sjulian *          ^                 ^
8652419Sjulian *          |                 |
8752419Sjulian *          v                 v
8852419Sjulian *    +-----------+     +-----------+
8952419Sjulian *    |pcb   (ctl)|     |pcb  (data)|
9052419Sjulian *    +-----------+     +-----------+
9152419Sjulian *          ^                 ^
9252419Sjulian *          |                 |
9352419Sjulian *          v                 v
9452419Sjulian *      +--------------------------+
9552419Sjulian *      |   Socket type private    |
9652419Sjulian *      |       data               |
9752419Sjulian *      +--------------------------+
9852419Sjulian *                   ^
9952419Sjulian *                   |
10052419Sjulian *                   v
10152419Sjulian *           +----------------+
10252419Sjulian *           | struct ng_node |
10352419Sjulian *           +----------------+
10452419Sjulian */
10552419Sjulian
10652419Sjulian/* Netgraph node methods */
10752752Sjulianstatic ng_constructor_t	ngs_constructor;
10852752Sjulianstatic ng_rcvmsg_t	ngs_rcvmsg;
10970700Sjulianstatic ng_shutdown_t	ngs_shutdown;
11052752Sjulianstatic ng_newhook_t	ngs_newhook;
11172053Sjulianstatic ng_connect_t	ngs_connect;
11252752Sjulianstatic ng_rcvdata_t	ngs_rcvdata;
11352885Sjulianstatic ng_disconnect_t	ngs_disconnect;
11452419Sjulian
11552419Sjulian/* Internal methods */
11652419Sjulianstatic int	ng_attach_data(struct socket *so);
11752419Sjulianstatic int	ng_attach_cntl(struct socket *so);
11852419Sjulianstatic int	ng_attach_common(struct socket *so, int type);
11952419Sjulianstatic void	ng_detach_common(struct ngpcb *pcbp, int type);
12083366Sjulian/*static int	ng_internalize(struct mbuf *m, struct thread *p); */
12152419Sjulian
12252419Sjulianstatic int	ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
12352419Sjulianstatic int	ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
12452419Sjulian
12552419Sjulianstatic int	ngs_mod_event(module_t mod, int event, void *data);
12652419Sjulianstatic int	ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg,
12752419Sjulian			struct sockaddr_ng *addr);
12852419Sjulian
12952419Sjulian/* Netgraph type descriptor */
13052419Sjulianstatic struct ng_type typestruct = {
13170159Sjulian	NG_ABI_VERSION,
13252419Sjulian	NG_SOCKET_NODE_TYPE,
13352419Sjulian	ngs_mod_event,
13452419Sjulian	ngs_constructor,
13552419Sjulian	ngs_rcvmsg,
13670700Sjulian	ngs_shutdown,
13752419Sjulian	ngs_newhook,
13852419Sjulian	NULL,
13972053Sjulian	ngs_connect,
14052419Sjulian	ngs_rcvdata,
14153913Sarchie	ngs_disconnect,
14253913Sarchie	NULL
14352419Sjulian};
14452419SjulianNETGRAPH_INIT(socket, &typestruct);
14552419Sjulian
14652419Sjulian/* Buffer space */
14764512Sarchiestatic u_long ngpdg_sendspace = 20 * 1024;	/* really max datagram size */
14852419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024;
14952419Sjulian
15052419Sjulian/* List of all sockets */
15160938SjakeLIST_HEAD(, ngpcb) ngsocklist;
15252419Sjulian
15353526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb)
15452419Sjulian
15552419Sjulian/* If getting unexplained errors returned, set this to "Debugger("X"); */
15652419Sjulian#ifndef TRAP_ERROR
15752419Sjulian#define TRAP_ERROR
15852419Sjulian#endif
15952419Sjulian
16052419Sjulian/***************************************************************
16152419Sjulian	Control sockets
16252419Sjulian***************************************************************/
16352419Sjulian
16452419Sjulianstatic int
16583366Sjulianngc_attach(struct socket *so, int proto, struct thread *td)
16652419Sjulian{
16752419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
16852419Sjulian
16983366Sjulian	if (suser_td(td))
17053530Sjulian		return (EPERM);
17152419Sjulian	if (pcbp != NULL)
17252419Sjulian		return (EISCONN);
17352419Sjulian	return (ng_attach_cntl(so));
17452419Sjulian}
17552419Sjulian
17652419Sjulianstatic int
17752419Sjulianngc_detach(struct socket *so)
17852419Sjulian{
17952419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
18052419Sjulian
18152419Sjulian	if (pcbp == NULL)
18252419Sjulian		return (EINVAL);
18352419Sjulian	ng_detach_common(pcbp, NG_CONTROL);
18452419Sjulian	return (0);
18552419Sjulian}
18652419Sjulian
18752419Sjulianstatic int
18852419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
18983366Sjulian	 struct mbuf *control, struct thread *td)
19052419Sjulian{
19152419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
19252419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
19370700Sjulian	struct ng_mesg *msg;
19452419Sjulian	struct mbuf *m0;
19570700Sjulian	char *path = NULL;
19652419Sjulian	int len, error = 0;
19752419Sjulian
19852419Sjulian	if (pcbp == NULL) {
19952419Sjulian		error = EINVAL;
20052419Sjulian		goto release;
20152419Sjulian	}
20252419Sjulian#ifdef	NOTYET
20383366Sjulian	if (control && (error = ng_internalize(control, td))) {
20452419Sjulian		if (pcbp->sockdata == NULL) {
20552419Sjulian			error = ENOTCONN;
20652419Sjulian			goto release;
20752419Sjulian		}
20852419Sjulian	}
20952419Sjulian#else	/* NOTYET */
21052419Sjulian	if (control) {
21152419Sjulian		error = EINVAL;
21252419Sjulian		goto release;
21352419Sjulian	}
21452419Sjulian#endif	/* NOTYET */
21552419Sjulian
21652419Sjulian	/* Require destination as there may be >= 1 hooks on this node */
21752419Sjulian	if (addr == NULL) {
21852419Sjulian		error = EDESTADDRREQ;
21952419Sjulian		goto release;
22052419Sjulian	}
22152419Sjulian
22252419Sjulian	/* Allocate an expendable buffer for the path, chop off
22352419Sjulian	 * the sockaddr header, and make sure it's NUL terminated */
22452419Sjulian	len = sap->sg_len - 2;
22570870Sjulian	MALLOC(path, char *, len + 1, M_NETGRAPH_PATH, M_WAITOK);
22652419Sjulian	if (path == NULL) {
22752419Sjulian		error = ENOMEM;
22852419Sjulian		goto release;
22952419Sjulian	}
23052419Sjulian	bcopy(sap->sg_data, path, len);
23152419Sjulian	path[len] = '\0';
23252419Sjulian
23352419Sjulian	/* Move the actual message out of mbufs into a linear buffer.
23452419Sjulian	 * Start by adding up the size of the data. (could use mh_len?) */
23552419Sjulian	for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
23652419Sjulian		len += m0->m_len;
23752419Sjulian
23852419Sjulian	/* Move the data into a linear buffer as well. Messages are not
23952419Sjulian	 * delivered in mbufs. */
24070700Sjulian	MALLOC(msg, struct ng_mesg *, len + 1, M_NETGRAPH_MSG, M_WAITOK);
24152419Sjulian	if (msg == NULL) {
24252419Sjulian		error = ENOMEM;
24352419Sjulian		goto release;
24452419Sjulian	}
24570700Sjulian	m_copydata(m, 0, len, (char *)msg);
24652419Sjulian
24770784Sjulian#ifdef TRACE_MESSAGES
24870784Sjulian	do {
24970784Sjulian		item_p item;
25070784Sjulian		if ((item = ng_package_msg(msg)) == NULL) {
25170784Sjulian			(msg) = NULL;
25270784Sjulian			(error) = ENOMEM;
25370784Sjulianprintf("err=%d\n",error);
25470784Sjulian			break;
25570784Sjulian		}
25670784Sjulian		if (((error) = ng_address_path((pcbp->sockdata->node), (item),
25770784Sjulian					(path), (NULL))) == 0) {
25870784Sjulianprintf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n",
25970784Sjulianitem->el_dest->nd_ID,
26070784Sjulianmsg->header.typecookie,
26170784Sjulianmsg->header.cmd,
26270784Sjulianmsg->header.cmdstr,
26370784Sjulianmsg->header.flags,
26470784Sjulianmsg->header.token,
26570784Sjulianitem->el_dest->nd_type->name);
26670784Sjulian			SAVE_LINE(item);
26770784Sjulian			(error) = ng_snd_item((item), 0);
26870784Sjulian		}
26970784Sjulianelse {
27070784Sjulianprintf("errx=%d\n",error);
27170784Sjulian}
27270784Sjulian		(msg) = NULL;
27370784Sjulian	} while (0);
27470784Sjulian
27570784Sjulian#else
27670700Sjulian	/* The callee will free the msg when done. The path is our business. */
27770700Sjulian	NG_SEND_MSG_PATH(error, pcbp->sockdata->node, msg, path, NULL);
27870784Sjulian#endif
27952419Sjulianrelease:
28052419Sjulian	if (path != NULL)
28170870Sjulian		FREE(path, M_NETGRAPH_PATH);
28252419Sjulian	if (control != NULL)
28352419Sjulian		m_freem(control);
28452419Sjulian	if (m != NULL)
28552419Sjulian		m_freem(m);
28652419Sjulian	return (error);
28752419Sjulian}
28852419Sjulian
28952419Sjulianstatic int
29083366Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
29152419Sjulian{
29252419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
29352419Sjulian
29452419Sjulian	if (pcbp == 0)
29552419Sjulian		return (EINVAL);
29652419Sjulian	return (ng_bind(nam, pcbp));
29752419Sjulian}
29852419Sjulian
29952419Sjulianstatic int
30083366Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
30152419Sjulian{
30270784Sjulianprintf(" program tried to connect control socket to remote node\n ");
30370700Sjulian	/*
30470784Sjulian	 * At this time refuse to do this.. it used to
30570700Sjulian	 * do something but it was undocumented and not used.
30670700Sjulian	 */
30770700Sjulian	return (EINVAL);
30852419Sjulian}
30952419Sjulian
31052419Sjulian/***************************************************************
31152419Sjulian	Data sockets
31252419Sjulian***************************************************************/
31352419Sjulian
31452419Sjulianstatic int
31583366Sjulianngd_attach(struct socket *so, int proto, struct thread *td)
31652419Sjulian{
31752419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
31852419Sjulian
31952419Sjulian	if (pcbp != NULL)
32052419Sjulian		return (EISCONN);
32152419Sjulian	return (ng_attach_data(so));
32252419Sjulian}
32352419Sjulian
32452419Sjulianstatic int
32552419Sjulianngd_detach(struct socket *so)
32652419Sjulian{
32752419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
32852419Sjulian
32952419Sjulian	if (pcbp == NULL)
33052419Sjulian		return (EINVAL);
33152419Sjulian	ng_detach_common(pcbp, NG_DATA);
33252419Sjulian	return (0);
33352419Sjulian}
33452419Sjulian
33552419Sjulianstatic int
33652419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
33783366Sjulian	 struct mbuf *control, struct thread *td)
33852419Sjulian{
33952419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
34052419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
34152419Sjulian	int     len, error;
34253498Sjulian	hook_p  hook = NULL;
34353498Sjulian	char	hookname[NG_HOOKLEN + 1];
34452419Sjulian
34552419Sjulian	if ((pcbp == NULL) || (control != NULL)) {
34652419Sjulian		error = EINVAL;
34752419Sjulian		goto release;
34852419Sjulian	}
34952419Sjulian	if (pcbp->sockdata == NULL) {
35052419Sjulian		error = ENOTCONN;
35152419Sjulian		goto release;
35252419Sjulian	}
35353498Sjulian	/*
35453498Sjulian	 * If the user used any of these ways to not specify an address
35553498Sjulian	 * then handle specially.
35653498Sjulian	 */
35753498Sjulian	if ((sap == NULL)
35853498Sjulian	|| ((len = sap->sg_len) <= 2)
35953498Sjulian	|| (*sap->sg_data == '\0')) {
36070784Sjulian		if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) {
36153498Sjulian			error = EDESTADDRREQ;
36253498Sjulian			goto release;
36353498Sjulian		}
36453498Sjulian		/*
36553498Sjulian		 * if exactly one hook exists, just use it.
36653498Sjulian		 * Special case to allow write(2) to work on an ng_socket.
36753498Sjulian		 */
36870784Sjulian		hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks);
36953498Sjulian	} else {
37053498Sjulian		if (len > NG_HOOKLEN) {
37153498Sjulian			error = EINVAL;
37253498Sjulian			goto release;
37353498Sjulian		}
37452419Sjulian
37553498Sjulian		/*
37653498Sjulian		 * chop off the sockaddr header, and make sure it's NUL
37753498Sjulian		 * terminated
37853498Sjulian		 */
37953498Sjulian		bcopy(sap->sg_data, hookname, len);
38053498Sjulian		hookname[len] = '\0';
38152419Sjulian
38253498Sjulian		/* Find the correct hook from 'hookname' */
38370784Sjulian		LIST_FOREACH(hook, &pcbp->sockdata->node->nd_hooks, hk_hooks) {
38472053Sjulian			if (strcmp(hookname, NG_HOOK_NAME(hook)) == 0) {
38553498Sjulian				break;
38672053Sjulian			}
38753498Sjulian		}
38872053Sjulian		if (hook == NULL) {
38953498Sjulian			error = EHOSTUNREACH;
39072053Sjulian		}
39152419Sjulian	}
39252419Sjulian
39352419Sjulian	/* Send data (OK if hook is NULL) */
39469922Sjulian	NG_SEND_DATA_ONLY(error, hook, m);	/* makes m NULL */
39552419Sjulian
39652419Sjulianrelease:
39752419Sjulian	if (control != NULL)
39852419Sjulian		m_freem(control);
39952419Sjulian	if (m != NULL)
40052419Sjulian		m_freem(m);
40152419Sjulian	return (error);
40252419Sjulian}
40352419Sjulian
40452419Sjulianstatic int
40583366Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
40652419Sjulian{
40752419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
40852419Sjulian
40952419Sjulian	if (pcbp == 0)
41052419Sjulian		return (EINVAL);
41152419Sjulian	return (ng_connect_data(nam, pcbp));
41252419Sjulian}
41352419Sjulian
41452419Sjulian/*
41552419Sjulian * Used for both data and control sockets
41652419Sjulian */
41752419Sjulianstatic int
41852419Sjulianng_setsockaddr(struct socket *so, struct sockaddr **addr)
41952419Sjulian{
42053098Sbrian	struct ngpcb *pcbp;
42153098Sbrian	struct sockaddr_ng *sg;
42253098Sbrian	int sg_len, namelen, s;
42352419Sjulian
42453098Sbrian	/* Why isn't sg_data a `char[1]' ? :-( */
42553098Sbrian	sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1;
42653098Sbrian
42753098Sbrian	s = splnet();
42853098Sbrian	pcbp = sotongpcb(so);
42969922Sjulian	if ((pcbp == NULL) || (pcbp->sockdata == NULL)) {
43053098Sbrian		splx(s);
43152419Sjulian		return (EINVAL);
43253098Sbrian	}
43353098Sbrian
43453098Sbrian	namelen = 0;		/* silence compiler ! */
43570784Sjulian	if ( NG_NODE_HAS_NAME(pcbp->sockdata->node))
43670784Sjulian		sg_len += namelen = strlen(NG_NODE_NAME(pcbp->sockdata->node));
43753098Sbrian
43868876Sdwmalone	MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK | M_ZERO);
43953098Sbrian
44070784Sjulian	if (NG_NODE_HAS_NAME(pcbp->sockdata->node))
44170784Sjulian		bcopy(NG_NODE_NAME(pcbp->sockdata->node), sg->sg_data, namelen);
44253098Sbrian	splx(s);
44353098Sbrian
44453098Sbrian	sg->sg_len = sg_len;
44553098Sbrian	sg->sg_family = AF_NETGRAPH;
44653098Sbrian	*addr = (struct sockaddr *)sg;
44753098Sbrian
44852419Sjulian	return (0);
44952419Sjulian}
45052419Sjulian
45152419Sjulian/*
45252419Sjulian * Attach a socket to it's protocol specific partner.
45352419Sjulian * For a control socket, actually create a netgraph node and attach
45452419Sjulian * to it as well.
45552419Sjulian */
45652419Sjulian
45752419Sjulianstatic int
45852419Sjulianng_attach_cntl(struct socket *so)
45952419Sjulian{
46052419Sjulian	struct ngsock *privdata;
46152419Sjulian	struct ngpcb *pcbp;
46252419Sjulian	int error;
46352419Sjulian
46452419Sjulian	/* Setup protocol control block */
46552419Sjulian	if ((error = ng_attach_common(so, NG_CONTROL)) != 0)
46652419Sjulian		return (error);
46753526Sjulian	pcbp = sotongpcb(so);
46852419Sjulian
46952419Sjulian	/* Allocate node private info */
47052419Sjulian	MALLOC(privdata, struct ngsock *,
47170870Sjulian	    sizeof(*privdata), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO);
47252419Sjulian	if (privdata == NULL) {
47352419Sjulian		ng_detach_common(pcbp, NG_CONTROL);
47452419Sjulian		return (ENOMEM);
47552419Sjulian	}
47652419Sjulian
47752419Sjulian	/* Make the generic node components */
47852419Sjulian	if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) {
47970870Sjulian		FREE(privdata, M_NETGRAPH_SOCK);
48052419Sjulian		ng_detach_common(pcbp, NG_CONTROL);
48152419Sjulian		return (error);
48252419Sjulian	}
48370784Sjulian	NG_NODE_SET_PRIVATE(privdata->node, privdata);
48452419Sjulian
48552419Sjulian	/* Link the pcb and the node private data */
48652419Sjulian	privdata->ctlsock = pcbp;
48752419Sjulian	pcbp->sockdata = privdata;
48852419Sjulian	privdata->refs++;
48952419Sjulian	return (0);
49052419Sjulian}
49152419Sjulian
49252419Sjulianstatic int
49352419Sjulianng_attach_data(struct socket *so)
49452419Sjulian{
49552419Sjulian	return(ng_attach_common(so, NG_DATA));
49652419Sjulian}
49752419Sjulian
49852419Sjulian/*
49952419Sjulian * Set up a socket protocol control block.
50052419Sjulian * This code is shared between control and data sockets.
50152419Sjulian */
50252419Sjulianstatic int
50352419Sjulianng_attach_common(struct socket *so, int type)
50452419Sjulian{
50552419Sjulian	struct ngpcb *pcbp;
50652419Sjulian	int error;
50752419Sjulian
50852419Sjulian	/* Standard socket setup stuff */
50952419Sjulian	error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
51052419Sjulian	if (error)
51152419Sjulian		return (error);
51252419Sjulian
51352419Sjulian	/* Allocate the pcb */
51468876Sdwmalone	MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK | M_ZERO);
51552419Sjulian	if (pcbp == NULL)
51652419Sjulian		return (ENOMEM);
51752419Sjulian	pcbp->type = type;
51852419Sjulian
51952419Sjulian	/* Link the pcb and the socket */
52052419Sjulian	so->so_pcb = (caddr_t) pcbp;
52152419Sjulian	pcbp->ng_socket = so;
52252419Sjulian
52352419Sjulian	/* Add the socket to linked list */
52452419Sjulian	LIST_INSERT_HEAD(&ngsocklist, pcbp, socks);
52552419Sjulian	return (0);
52652419Sjulian}
52752419Sjulian
52852419Sjulian/*
52952419Sjulian * Disassociate the socket from it's protocol specific
53052419Sjulian * partner. If it's attached to a node's private data structure,
53152419Sjulian * then unlink from that too. If we were the last socket attached to it,
53252419Sjulian * then shut down the entire node. Shared code for control and data sockets.
53352419Sjulian */
53452419Sjulianstatic void
53552419Sjulianng_detach_common(struct ngpcb *pcbp, int which)
53652419Sjulian{
53772053Sjulian	struct ngsock *priv;
53852419Sjulian
53952419Sjulian	if (pcbp->sockdata) {
54072053Sjulian		priv = pcbp->sockdata;
54152419Sjulian		pcbp->sockdata = NULL;
54252419Sjulian		switch (which) {
54352419Sjulian		case NG_CONTROL:
54472053Sjulian			priv->ctlsock = NULL;
54552419Sjulian			break;
54652419Sjulian		case NG_DATA:
54772053Sjulian			priv->datasock = NULL;
54852419Sjulian			break;
54952419Sjulian		default:
55052419Sjulian			panic(__FUNCTION__);
55152419Sjulian		}
55272053Sjulian		if ((--priv->refs == 0) && (priv->node != NULL))
55372053Sjulian			ng_rmnode_self(priv->node);
55452419Sjulian	}
55552419Sjulian	pcbp->ng_socket->so_pcb = NULL;
55652419Sjulian	pcbp->ng_socket = NULL;
55752419Sjulian	LIST_REMOVE(pcbp, socks);
55852419Sjulian	FREE(pcbp, M_PCB);
55952419Sjulian}
56052419Sjulian
56152419Sjulian#ifdef NOTYET
56252419Sjulian/*
56352419Sjulian * File descriptors can be passed into a AF_NETGRAPH socket.
56452419Sjulian * Note, that file descriptors cannot be passed OUT.
56552419Sjulian * Only character device descriptors are accepted.
56652419Sjulian * Character devices are useful to connect a graph to a device,
56752419Sjulian * which after all is the purpose of this whole system.
56852419Sjulian */
56952419Sjulianstatic int
57083366Sjulianng_internalize(struct mbuf *control, struct thread *td)
57152419Sjulian{
57283366Sjulian	struct filedesc *fdp = td->td_proc->p_fd;
57352419Sjulian	struct cmsghdr *cm = mtod(control, struct cmsghdr *);
57452419Sjulian	struct file *fp;
57552419Sjulian	struct vnode *vn;
57652419Sjulian	int oldfds;
57752419Sjulian	int fd;
57852419Sjulian
57952419Sjulian	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
58052419Sjulian	    cm->cmsg_len != control->m_len) {
58152419Sjulian		TRAP_ERROR;
58252419Sjulian		return (EINVAL);
58352419Sjulian	}
58452419Sjulian
58552419Sjulian	/* Check there is only one FD. XXX what would more than one signify? */
58652419Sjulian	oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int);
58752419Sjulian	if (oldfds != 1) {
58852419Sjulian		TRAP_ERROR;
58952419Sjulian		return (EINVAL);
59052419Sjulian	}
59152419Sjulian
59252419Sjulian	/* Check that the FD given is legit. and change it to a pointer to a
59352419Sjulian	 * struct file. */
59452419Sjulian	fd = *(int *) (cm + 1);
59552419Sjulian	if ((unsigned) fd >= fdp->fd_nfiles
59652419Sjulian	    || (fp = fdp->fd_ofiles[fd]) == NULL) {
59752419Sjulian		return (EBADF);
59852419Sjulian	}
59952419Sjulian
60052419Sjulian	/* Depending on what kind of resource it is, act differently. For
60152419Sjulian	 * devices, we treat it as a file. For a AF_NETGRAPH socket,
60252419Sjulian	 * shortcut straight to the node. */
60352419Sjulian	switch (fp->f_type) {
60452419Sjulian	case DTYPE_VNODE:
60552419Sjulian		vn = (struct vnode *) fp->f_data;
60652419Sjulian		if (vn && (vn->v_type == VCHR)) {
60752419Sjulian			/* for a VCHR, actually reference the FILE */
60852419Sjulian			fp->f_count++;
60952419Sjulian			/* XXX then what :) */
61052419Sjulian			/* how to pass on to other modules? */
61152419Sjulian		} else {
61252419Sjulian			TRAP_ERROR;
61352419Sjulian			return (EINVAL);
61452419Sjulian		}
61552419Sjulian		break;
61652419Sjulian	default:
61752419Sjulian		TRAP_ERROR;
61852419Sjulian		return (EINVAL);
61952419Sjulian	}
62052419Sjulian	return (0);
62152419Sjulian}
62252419Sjulian#endif	/* NOTYET */
62352419Sjulian
62452419Sjulian/*
62552419Sjulian * Connect the data socket to a named control socket node.
62652419Sjulian */
62752419Sjulianstatic int
62852419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
62952419Sjulian{
63052419Sjulian	struct sockaddr_ng *sap;
63152419Sjulian	node_p farnode;
63272053Sjulian	struct ngsock *priv;
63352419Sjulian	int error;
63470700Sjulian	item_p item;
63552419Sjulian
63652419Sjulian	/* If we are already connected, don't do it again */
63752419Sjulian	if (pcbp->sockdata != NULL)
63852419Sjulian		return (EISCONN);
63952419Sjulian
64052419Sjulian	/* Find the target (victim) and check it doesn't already have a data
64170700Sjulian	 * socket. Also check it is a 'socket' type node.
64270700Sjulian	 * Use ng_package_data() and address_path() to do this.
64370700Sjulian	 */
64470700Sjulian
64552419Sjulian	sap = (struct sockaddr_ng *) nam;
64670700Sjulian	/* The item will hold the node reference */
64770700Sjulian	item = ng_package_data(NULL, NULL);
64870700Sjulian	if (item == NULL) {
64970700Sjulian		return (ENOMEM);
65070700Sjulian	}
65170700Sjulian	if ((error = ng_address_path(NULL, item,  sap->sg_data, NULL)))
65270700Sjulian		return (error); /* item is freed on failure */
65352419Sjulian
65470700Sjulian	/*
65570784Sjulian	 * Extract node from item and free item. Remember we now have
65670700Sjulian	 * a reference on the node. The item holds it for us.
65770700Sjulian	 * when we free the item we release the reference.
65870700Sjulian	 */
65970700Sjulian	farnode = item->el_dest; /* shortcut */
66070784Sjulian	if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) {
66170700Sjulian		NG_FREE_ITEM(item); /* drop the reference to the node */
66252419Sjulian		return (EINVAL);
66370700Sjulian	}
66472053Sjulian	priv = NG_NODE_PRIVATE(farnode);
66572053Sjulian	if (priv->datasock != NULL) {
66670700Sjulian		NG_FREE_ITEM(item);	/* drop the reference to the node */
66752419Sjulian		return (EADDRINUSE);
66870700Sjulian	}
66952419Sjulian
67070700Sjulian	/*
67170700Sjulian	 * Link the PCB and the private data struct. and note the extra
67270700Sjulian	 * reference. Drop the extra reference on the node.
67370700Sjulian	 */
67472053Sjulian	priv->datasock = pcbp;
67572053Sjulian	pcbp->sockdata = priv;
67672053Sjulian	priv->refs++; /* XXX possible race if it's being freed */
67770700Sjulian	NG_FREE_ITEM(item);	/* drop the reference to the node */
67852419Sjulian	return (0);
67952419Sjulian}
68052419Sjulian
68152419Sjulian/*
68252419Sjulian * Binding a socket means giving the corresponding node a name
68352419Sjulian */
68452419Sjulianstatic int
68552419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
68652419Sjulian{
68772053Sjulian	struct ngsock *const priv = pcbp->sockdata;
68852419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
68952419Sjulian
69072053Sjulian	if (priv == NULL) {
69152419Sjulian		TRAP_ERROR;
69252419Sjulian		return (EINVAL);
69352419Sjulian	}
69469922Sjulian	if ((sap->sg_len < 4)
69569922Sjulian	||  (sap->sg_len > (NG_NODELEN + 3))
69669922Sjulian	||  (sap->sg_data[0] == '\0')
69769922Sjulian	||  (sap->sg_data[sap->sg_len - 3] != '\0')) {
69852419Sjulian		TRAP_ERROR;
69952419Sjulian		return (EINVAL);
70052419Sjulian	}
70172053Sjulian	return (ng_name_node(priv->node, sap->sg_data));
70252419Sjulian}
70352419Sjulian
70452419Sjulian/*
70552419Sjulian * Take a message and pass it up to the control socket associated
70652419Sjulian * with the node.
70752419Sjulian */
70852419Sjulianstatic int
70952419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr)
71052419Sjulian{
71152419Sjulian	struct socket *const so = pcbp->ng_socket;
71252419Sjulian	struct mbuf *mdata;
71352419Sjulian	int msglen;
71452419Sjulian
71552419Sjulian	/* Copy the message itself into an mbuf chain */
71652419Sjulian	msglen = sizeof(struct ng_mesg) + msg->header.arglen;
71752419Sjulian	mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL);
71852419Sjulian
71952419Sjulian	/* Here we free the message, as we are the end of the line.
72052419Sjulian	 * We need to do that regardless of whether we got mbufs. */
72170700Sjulian	NG_FREE_MSG(msg);
72252419Sjulian
72352419Sjulian	if (mdata == NULL) {
72452419Sjulian		TRAP_ERROR;
72552419Sjulian		return (ENOBUFS);
72652419Sjulian	}
72752419Sjulian
72852419Sjulian	/* Send it up to the socket */
72952419Sjulian	if (sbappendaddr(&so->so_rcv,
73052419Sjulian	    (struct sockaddr *) addr, mdata, NULL) == 0) {
73152419Sjulian		TRAP_ERROR;
73252419Sjulian		m_freem(mdata);
73352419Sjulian		return (ENOBUFS);
73452419Sjulian	}
73552419Sjulian	sorwakeup(so);
73652419Sjulian	return (0);
73752419Sjulian}
73852419Sjulian
73952419Sjulian/*
74052419Sjulian * You can only create new nodes from the socket end of things.
74152419Sjulian */
74252419Sjulianstatic int
74370700Sjulianngs_constructor(node_p nodep)
74452419Sjulian{
74552419Sjulian	return (EINVAL);
74652419Sjulian}
74752419Sjulian
74852419Sjulian/*
74952419Sjulian * We allow any hook to be connected to the node.
75052419Sjulian * There is no per-hook private information though.
75152419Sjulian */
75252419Sjulianstatic int
75352419Sjulianngs_newhook(node_p node, hook_p hook, const char *name)
75452419Sjulian{
75570784Sjulian	NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node));
75652419Sjulian	return (0);
75752419Sjulian}
75852419Sjulian
75972053Sjulian/*
76072053Sjulian * if only one hook, allow read(2) and write(2) to work.
76172053Sjulian */
76272053Sjulianstatic int
76372053Sjulianngs_connect(hook_p hook)
76472053Sjulian{
76572053Sjulian	node_p node = NG_HOOK_NODE(hook);
76672053Sjulian	struct ngsock *priv = NG_NODE_PRIVATE(node);
76772053Sjulian
76872053Sjulian	if ((priv->datasock)
76972053Sjulian	&&  (priv->datasock->ng_socket)) {
77072053Sjulian		if (NG_NODE_NUMHOOKS(node) == 1) {
77172053Sjulian			priv->datasock->ng_socket->so_state |= SS_ISCONNECTED;
77272053Sjulian		} else {
77372053Sjulian			priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED;
77472053Sjulian		}
77572053Sjulian	}
77672053Sjulian	return (0);
77772053Sjulian}
77872053Sjulian
77952419Sjulian/*
78052419Sjulian * Incoming messages get passed up to the control socket.
78152885Sjulian * Unless they are for us specifically (socket_type)
78252419Sjulian */
78352419Sjulianstatic int
78470700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook)
78552419Sjulian{
78672053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
78772053Sjulian	struct ngpcb *const pcbp = priv->ctlsock;
78852419Sjulian	struct sockaddr_ng *addr;
78952419Sjulian	int addrlen;
79052419Sjulian	int error = 0;
79170700Sjulian	struct	ng_mesg *msg;
79270700Sjulian	ng_ID_t	retaddr = NGI_RETADDR(item);
79370700Sjulian	char	retabuf[32];
79452419Sjulian
79570700Sjulian	NGI_GET_MSG(item, msg);
79670700Sjulian	NG_FREE_ITEM(item); /* we have all we need */
79770700Sjulian
79852419Sjulian	/* Only allow mesgs to be passed if we have the control socket.
79952419Sjulian	 * Data sockets can only support the generic messages. */
80052419Sjulian	if (pcbp == NULL) {
80152419Sjulian		TRAP_ERROR;
80252419Sjulian		return (EINVAL);
80352419Sjulian	}
80470784Sjulian#ifdef TRACE_MESSAGES
80570784Sjulianprintf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n",
80670784Sjulianretaddr,
80770784Sjulianmsg->header.typecookie,
80870784Sjulianmsg->header.cmd,
80970784Sjulianmsg->header.cmdstr,
81070784Sjulianmsg->header.flags,
81170784Sjulianmsg->header.token);
81252419Sjulian
81370784Sjulian#endif
81470784Sjulian
81552885Sjulian	if (msg->header.typecookie == NGM_SOCKET_COOKIE) {
81652885Sjulian		switch (msg->header.cmd) {
81752885Sjulian		case NGM_SOCK_CMD_NOLINGER:
81872053Sjulian			priv->flags |= NGS_FLAG_NOLINGER;
81952885Sjulian			break;
82052885Sjulian		case NGM_SOCK_CMD_LINGER:
82172053Sjulian			priv->flags &= ~NGS_FLAG_NOLINGER;
82252885Sjulian			break;
82352885Sjulian		default:
82452885Sjulian			error = EINVAL;		/* unknown command */
82552885Sjulian		}
82652885Sjulian		/* Free the message and return */
82770700Sjulian		NG_FREE_MSG(msg);
82852885Sjulian		return(error);
82952885Sjulian
83052885Sjulian	}
83152419Sjulian	/* Get the return address into a sockaddr */
83270700Sjulian	sprintf(retabuf,"[%x]:", retaddr);
83370700Sjulian	addrlen = strlen(retabuf);
83470870Sjulian	MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH_PATH, M_NOWAIT);
83552419Sjulian	if (addr == NULL) {
83652419Sjulian		TRAP_ERROR;
83752419Sjulian		return (ENOMEM);
83852419Sjulian	}
83952419Sjulian	addr->sg_len = addrlen + 3;
84052419Sjulian	addr->sg_family = AF_NETGRAPH;
84170700Sjulian	bcopy(retabuf, addr->sg_data, addrlen);
84252419Sjulian	addr->sg_data[addrlen] = '\0';
84352419Sjulian
84452419Sjulian	/* Send it up */
84552419Sjulian	error = ship_msg(pcbp, msg, addr);
84670870Sjulian	FREE(addr, M_NETGRAPH_PATH);
84752419Sjulian	return (error);
84852419Sjulian}
84952419Sjulian
85052419Sjulian/*
85152419Sjulian * Receive data on a hook
85252419Sjulian */
85352419Sjulianstatic int
85470700Sjulianngs_rcvdata(hook_p hook, item_p item)
85552419Sjulian{
85672053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
85772053Sjulian	struct ngpcb *const pcbp = priv->datasock;
85852419Sjulian	struct socket *so;
85952419Sjulian	struct sockaddr_ng *addr;
86052419Sjulian	char *addrbuf[NG_HOOKLEN + 1 + 4];
86152419Sjulian	int addrlen;
86270700Sjulian	struct mbuf *m;
86352419Sjulian
86470700Sjulian	NGI_GET_M(item, m);
86570700Sjulian	NG_FREE_ITEM(item);
86652419Sjulian	/* If there is no data socket, black-hole it */
86752419Sjulian	if (pcbp == NULL) {
86870700Sjulian		NG_FREE_M(m);
86952419Sjulian		return (0);
87052419Sjulian	}
87152419Sjulian	so = pcbp->ng_socket;
87252419Sjulian
87352419Sjulian	/* Get the return address into a sockaddr. */
87470784Sjulian	addrlen = strlen(NG_HOOK_NAME(hook));	/* <= NG_HOOKLEN */
87552419Sjulian	addr = (struct sockaddr_ng *) addrbuf;
87652419Sjulian	addr->sg_len = addrlen + 3;
87752419Sjulian	addr->sg_family = AF_NETGRAPH;
87870784Sjulian	bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen);
87952419Sjulian	addr->sg_data[addrlen] = '\0';
88052419Sjulian
88152419Sjulian	/* Try to tell the socket which hook it came in on */
88252419Sjulian	if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) {
88352419Sjulian		m_freem(m);
88452419Sjulian		TRAP_ERROR;
88552419Sjulian		return (ENOBUFS);
88652419Sjulian	}
88752419Sjulian	sorwakeup(so);
88852419Sjulian	return (0);
88952419Sjulian}
89052419Sjulian
89152419Sjulian/*
89253498Sjulian * Hook disconnection
89352885Sjulian *
89452885Sjulian * For this type, removal of the last link destroys the node
89552885Sjulian * if the NOLINGER flag is set.
89652885Sjulian */
89752885Sjulianstatic int
89852885Sjulianngs_disconnect(hook_p hook)
89952885Sjulian{
90072053Sjulian	node_p node = NG_HOOK_NODE(hook);
90172053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
90252885Sjulian
90372053Sjulian	if ((priv->datasock)
90472053Sjulian	&&  (priv->datasock->ng_socket)) {
90572053Sjulian		if (NG_NODE_NUMHOOKS(node) == 1) {
90672053Sjulian			priv->datasock->ng_socket->so_state |= SS_ISCONNECTED;
90772053Sjulian		} else {
90872053Sjulian			priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED;
90972053Sjulian		}
91052885Sjulian	}
91172053Sjulian
91272053Sjulian	if ((priv->flags & NGS_FLAG_NOLINGER )
91372053Sjulian	&& (NG_NODE_NUMHOOKS(node) == 0)
91472053Sjulian	&& (NG_NODE_IS_VALID(node))) {
91572053Sjulian		ng_rmnode_self(node);
91672053Sjulian	}
91752885Sjulian	return (0);
91852885Sjulian}
91952885Sjulian
92052885Sjulian/*
92152419Sjulian * Do local shutdown processing.
92252419Sjulian * In this case, that involves making sure the socket
92352419Sjulian * knows we should be shutting down.
92452419Sjulian */
92552419Sjulianstatic int
92670700Sjulianngs_shutdown(node_p node)
92752419Sjulian{
92872053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
92972053Sjulian	struct ngpcb *const dpcbp = priv->datasock;
93072053Sjulian	struct ngpcb *const pcbp = priv->ctlsock;
93152419Sjulian
93252419Sjulian	if (dpcbp != NULL) {
93352419Sjulian		soisdisconnected(dpcbp->ng_socket);
93452419Sjulian		dpcbp->sockdata = NULL;
93572053Sjulian		priv->datasock = NULL;
93672053Sjulian		priv->refs--;
93752419Sjulian	}
93852419Sjulian	if (pcbp != NULL) {
93952419Sjulian		soisdisconnected(pcbp->ng_socket);
94052419Sjulian		pcbp->sockdata = NULL;
94172053Sjulian		priv->ctlsock = NULL;
94272053Sjulian		priv->refs--;
94352419Sjulian	}
94470784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
94570784Sjulian	NG_NODE_UNREF(node);
94672053Sjulian	FREE(priv, M_NETGRAPH_SOCK);
94752419Sjulian	return (0);
94852419Sjulian}
94952419Sjulian
95072055Sjulianstatic	int
95172055Sjuliandummy_disconnect(struct socket *so)
95272055Sjulian{
95372055Sjulian	return (0);
95472055Sjulian}
95552419Sjulian/*
95652419Sjulian * Control and data socket type descriptors
95752419Sjulian */
95852419Sjulian
95952419Sjulianstatic struct pr_usrreqs ngc_usrreqs = {
96052419Sjulian	NULL,			/* abort */
96152419Sjulian	pru_accept_notsupp,
96252419Sjulian	ngc_attach,
96352419Sjulian	ngc_bind,
96452419Sjulian	ngc_connect,
96552419Sjulian	pru_connect2_notsupp,
96652419Sjulian	pru_control_notsupp,
96752419Sjulian	ngc_detach,
96872055Sjulian	dummy_disconnect,	/* disconnect */
96952419Sjulian	pru_listen_notsupp,
97052419Sjulian	NULL,			/* setpeeraddr */
97152419Sjulian	pru_rcvd_notsupp,
97252419Sjulian	pru_rcvoob_notsupp,
97352419Sjulian	ngc_send,
97452419Sjulian	pru_sense_null,
97552419Sjulian	NULL,			/* shutdown */
97652419Sjulian	ng_setsockaddr,
97752419Sjulian	sosend,
97852419Sjulian	soreceive,
97952419Sjulian	sopoll
98052419Sjulian};
98152419Sjulian
98252419Sjulianstatic struct pr_usrreqs ngd_usrreqs = {
98352419Sjulian	NULL,			/* abort */
98452419Sjulian	pru_accept_notsupp,
98552419Sjulian	ngd_attach,
98652419Sjulian	NULL,			/* bind */
98752419Sjulian	ngd_connect,
98852419Sjulian	pru_connect2_notsupp,
98952419Sjulian	pru_control_notsupp,
99052419Sjulian	ngd_detach,
99172055Sjulian	dummy_disconnect,	/* disconnect */
99252419Sjulian	pru_listen_notsupp,
99352419Sjulian	NULL,			/* setpeeraddr */
99452419Sjulian	pru_rcvd_notsupp,
99552419Sjulian	pru_rcvoob_notsupp,
99652419Sjulian	ngd_send,
99752419Sjulian	pru_sense_null,
99852419Sjulian	NULL,			/* shutdown */
99952419Sjulian	ng_setsockaddr,
100052419Sjulian	sosend,
100152419Sjulian	soreceive,
100252419Sjulian	sopoll
100352419Sjulian};
100452419Sjulian
100552419Sjulian/*
100652419Sjulian * Definitions of protocols supported in the NETGRAPH domain.
100752419Sjulian */
100852419Sjulian
100952419Sjulianextern struct domain ngdomain;		/* stop compiler warnings */
101052419Sjulian
101152419Sjulianstatic struct protosw ngsw[] = {
101252419Sjulian	{
101370700Sjulian		SOCK_DGRAM,		/* protocol type */
101470700Sjulian		&ngdomain,		/* backpointer to domain */
101552419Sjulian		NG_CONTROL,
101670700Sjulian		PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,	/* flags */
101770700Sjulian		0, 0, 0, 0,		/* input, output, ctlinput, ctloutput */
101870700Sjulian		NULL,			/* ousrreq */
101970700Sjulian		0, 0, 0, 0,		/* init, fasttimeo, slowtimo, drain */
102070700Sjulian		&ngc_usrreqs,		/* usrreq table (above) */
102170700Sjulian		/*{NULL}*/		/* pffh (protocol filter head?) */
102252419Sjulian	},
102352419Sjulian	{
102470700Sjulian		SOCK_DGRAM,		/* protocol type */
102570700Sjulian		&ngdomain,		/* backpointer to domain */
102652419Sjulian		NG_DATA,
102770700Sjulian		PR_ATOMIC | PR_ADDR,	/* flags */
102870700Sjulian		0, 0, 0, 0,		/* input, output, ctlinput, ctloutput */
102970700Sjulian		NULL,			/* ousrreq() */
103070700Sjulian		0, 0, 0, 0,		/* init, fasttimeo, slowtimo, drain */
103170700Sjulian		&ngd_usrreqs,		/* usrreq table (above) */
103270700Sjulian		/*{NULL}*/		/* pffh (protocol filter head?) */
103352419Sjulian	}
103452419Sjulian};
103552419Sjulian
103652419Sjulianstruct domain ngdomain = {
103752419Sjulian	AF_NETGRAPH,
103852419Sjulian	"netgraph",
103970700Sjulian	NULL,					/* init() */
104070700Sjulian	NULL,					/* externalise() */
104170700Sjulian	NULL,					/* dispose() */
104270700Sjulian	ngsw,					/* protosw entry */
104370700Sjulian	&ngsw[sizeof(ngsw) / sizeof(ngsw[0])], 	/* Number of protosw entries */
104470700Sjulian	NULL,					/* next domain in list */
104570700Sjulian	NULL,					/* rtattach() */
104670700Sjulian	0,					/* arg to rtattach in bits */
104770700Sjulian	0					/* maxrtkey */
104852419Sjulian};
104952419Sjulian
105052419Sjulian/*
105152419Sjulian * Handle loading and unloading for this node type
105252419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition).
105352419Sjulian */
105452419Sjulianstatic int
105552419Sjulianngs_mod_event(module_t mod, int event, void *data)
105652419Sjulian{
105752419Sjulian	int error = 0;
105852419Sjulian
105952419Sjulian	switch (event) {
106052419Sjulian	case MOD_LOAD:
106152419Sjulian		/* Register protocol domain */
106252419Sjulian		net_add_domain(&ngdomain);
106352419Sjulian		break;
106452419Sjulian	case MOD_UNLOAD:
106552419Sjulian		/* Insure there are no open netgraph sockets */
106652419Sjulian		if (!LIST_EMPTY(&ngsocklist)) {
106752419Sjulian			error = EBUSY;
106852419Sjulian			break;
106952419Sjulian		}
107052419Sjulian
107152419Sjulian#ifdef NOTYET
107270700Sjulian		if ((LIST_EMPTY(&ngsocklist)) && (typestruct.refs == 0)) {
107352419Sjulian		/* Unregister protocol domain XXX can't do this yet.. */
107470700Sjulian			if ((error = net_rm_domain(&ngdomain)) != 0)
107570700Sjulian				break;
107670700Sjulian		} else
107752419Sjulian#endif
107870700Sjulian			error = EBUSY;
107952419Sjulian		break;
108052419Sjulian	default:
108152419Sjulian		error = EOPNOTSUPP;
108252419Sjulian		break;
108352419Sjulian	}
108452419Sjulian	return (error);
108552419Sjulian}
108652419Sjulian
108752419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, "");
108852419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA");
108952419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, "");
109052419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL");
109152419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, "");
109252419Sjulian
1093