ng_socket.c revision 70784
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 70784 2001-01-08 05:34:06Z 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
7252419Sjulian/*
7352419Sjulian * It's Ascii-art time!
7452419Sjulian *   +-------------+   +-------------+
7552419Sjulian *   |socket  (ctl)|   |socket (data)|
7652419Sjulian *   +-------------+   +-------------+
7752419Sjulian *          ^                 ^
7852419Sjulian *          |                 |
7952419Sjulian *          v                 v
8052419Sjulian *    +-----------+     +-----------+
8152419Sjulian *    |pcb   (ctl)|     |pcb  (data)|
8252419Sjulian *    +-----------+     +-----------+
8352419Sjulian *          ^                 ^
8452419Sjulian *          |                 |
8552419Sjulian *          v                 v
8652419Sjulian *      +--------------------------+
8752419Sjulian *      |   Socket type private    |
8852419Sjulian *      |       data               |
8952419Sjulian *      +--------------------------+
9052419Sjulian *                   ^
9152419Sjulian *                   |
9252419Sjulian *                   v
9352419Sjulian *           +----------------+
9452419Sjulian *           | struct ng_node |
9552419Sjulian *           +----------------+
9652419Sjulian */
9752419Sjulian
9852419Sjulian/* Netgraph node methods */
9952752Sjulianstatic ng_constructor_t	ngs_constructor;
10052752Sjulianstatic ng_rcvmsg_t	ngs_rcvmsg;
10170700Sjulianstatic ng_shutdown_t	ngs_shutdown;
10252752Sjulianstatic ng_newhook_t	ngs_newhook;
10352752Sjulianstatic ng_rcvdata_t	ngs_rcvdata;
10452885Sjulianstatic ng_disconnect_t	ngs_disconnect;
10552419Sjulian
10652419Sjulian/* Internal methods */
10752419Sjulianstatic int	ng_attach_data(struct socket *so);
10852419Sjulianstatic int	ng_attach_cntl(struct socket *so);
10952419Sjulianstatic int	ng_attach_common(struct socket *so, int type);
11052419Sjulianstatic void	ng_detach_common(struct ngpcb *pcbp, int type);
11152419Sjulian/*static int	ng_internalize(struct mbuf *m, struct proc *p); */
11252419Sjulian
11352419Sjulianstatic int	ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
11452419Sjulianstatic int	ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
11552419Sjulian
11652419Sjulianstatic int	ngs_mod_event(module_t mod, int event, void *data);
11752419Sjulianstatic int	ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg,
11852419Sjulian			struct sockaddr_ng *addr);
11952419Sjulian
12052419Sjulian/* Netgraph type descriptor */
12152419Sjulianstatic struct ng_type typestruct = {
12270159Sjulian	NG_ABI_VERSION,
12352419Sjulian	NG_SOCKET_NODE_TYPE,
12452419Sjulian	ngs_mod_event,
12552419Sjulian	ngs_constructor,
12652419Sjulian	ngs_rcvmsg,
12770700Sjulian	ngs_shutdown,
12852419Sjulian	ngs_newhook,
12952419Sjulian	NULL,
13052419Sjulian	NULL,
13152419Sjulian	ngs_rcvdata,
13253913Sarchie	ngs_disconnect,
13353913Sarchie	NULL
13452419Sjulian};
13552419SjulianNETGRAPH_INIT(socket, &typestruct);
13652419Sjulian
13752419Sjulian/* Buffer space */
13864512Sarchiestatic u_long ngpdg_sendspace = 20 * 1024;	/* really max datagram size */
13952419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024;
14052419Sjulian
14152419Sjulian/* List of all sockets */
14260938SjakeLIST_HEAD(, ngpcb) ngsocklist;
14352419Sjulian
14453526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb)
14552419Sjulian
14652419Sjulian/* If getting unexplained errors returned, set this to "Debugger("X"); */
14752419Sjulian#ifndef TRAP_ERROR
14852419Sjulian#define TRAP_ERROR
14952419Sjulian#endif
15052419Sjulian
15152419Sjulian/***************************************************************
15252419Sjulian	Control sockets
15352419Sjulian***************************************************************/
15452419Sjulian
15552419Sjulianstatic int
15652419Sjulianngc_attach(struct socket *so, int proto, struct proc *p)
15752419Sjulian{
15852419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
15952419Sjulian
16053532Sjulian	if (suser(p))
16153530Sjulian		return (EPERM);
16252419Sjulian	if (pcbp != NULL)
16352419Sjulian		return (EISCONN);
16452419Sjulian	return (ng_attach_cntl(so));
16552419Sjulian}
16652419Sjulian
16752419Sjulianstatic int
16852419Sjulianngc_detach(struct socket *so)
16952419Sjulian{
17052419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
17152419Sjulian
17252419Sjulian	if (pcbp == NULL)
17352419Sjulian		return (EINVAL);
17452419Sjulian	ng_detach_common(pcbp, NG_CONTROL);
17552419Sjulian	return (0);
17652419Sjulian}
17752419Sjulian
17852419Sjulianstatic int
17952419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
18052419Sjulian	 struct mbuf *control, struct proc *p)
18152419Sjulian{
18252419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
18352419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
18470700Sjulian	struct ng_mesg *msg;
18552419Sjulian	struct mbuf *m0;
18670700Sjulian	char *path = NULL;
18752419Sjulian	int len, error = 0;
18852419Sjulian
18952419Sjulian	if (pcbp == NULL) {
19052419Sjulian		error = EINVAL;
19152419Sjulian		goto release;
19252419Sjulian	}
19352419Sjulian#ifdef	NOTYET
19452419Sjulian	if (control && (error = ng_internalize(control, p))) {
19552419Sjulian		if (pcbp->sockdata == NULL) {
19652419Sjulian			error = ENOTCONN;
19752419Sjulian			goto release;
19852419Sjulian		}
19952419Sjulian	}
20052419Sjulian#else	/* NOTYET */
20152419Sjulian	if (control) {
20252419Sjulian		error = EINVAL;
20352419Sjulian		goto release;
20452419Sjulian	}
20552419Sjulian#endif	/* NOTYET */
20652419Sjulian
20752419Sjulian	/* Require destination as there may be >= 1 hooks on this node */
20852419Sjulian	if (addr == NULL) {
20952419Sjulian		error = EDESTADDRREQ;
21052419Sjulian		goto release;
21152419Sjulian	}
21252419Sjulian
21352419Sjulian	/* Allocate an expendable buffer for the path, chop off
21452419Sjulian	 * the sockaddr header, and make sure it's NUL terminated */
21552419Sjulian	len = sap->sg_len - 2;
21652419Sjulian	MALLOC(path, char *, len + 1, M_NETGRAPH, M_WAITOK);
21752419Sjulian	if (path == NULL) {
21852419Sjulian		error = ENOMEM;
21952419Sjulian		goto release;
22052419Sjulian	}
22152419Sjulian	bcopy(sap->sg_data, path, len);
22252419Sjulian	path[len] = '\0';
22352419Sjulian
22452419Sjulian	/* Move the actual message out of mbufs into a linear buffer.
22552419Sjulian	 * Start by adding up the size of the data. (could use mh_len?) */
22652419Sjulian	for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
22752419Sjulian		len += m0->m_len;
22852419Sjulian
22952419Sjulian	/* Move the data into a linear buffer as well. Messages are not
23052419Sjulian	 * delivered in mbufs. */
23170700Sjulian	MALLOC(msg, struct ng_mesg *, len + 1, M_NETGRAPH_MSG, M_WAITOK);
23252419Sjulian	if (msg == NULL) {
23352419Sjulian		error = ENOMEM;
23452419Sjulian		goto release;
23552419Sjulian	}
23670700Sjulian	m_copydata(m, 0, len, (char *)msg);
23752419Sjulian
23870784Sjulian#ifdef TRACE_MESSAGES
23970784Sjulian	do {
24070784Sjulian		item_p item;
24170784Sjulian		if ((item = ng_package_msg(msg)) == NULL) {
24270784Sjulian			(msg) = NULL;
24370784Sjulian			(error) = ENOMEM;
24470784Sjulianprintf("err=%d\n",error);
24570784Sjulian			break;
24670784Sjulian		}
24770784Sjulian		if (((error) = ng_address_path((pcbp->sockdata->node), (item),
24870784Sjulian					(path), (NULL))) == 0) {
24970784Sjulianprintf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n",
25070784Sjulianitem->el_dest->nd_ID,
25170784Sjulianmsg->header.typecookie,
25270784Sjulianmsg->header.cmd,
25370784Sjulianmsg->header.cmdstr,
25470784Sjulianmsg->header.flags,
25570784Sjulianmsg->header.token,
25670784Sjulianitem->el_dest->nd_type->name);
25770784Sjulian			SAVE_LINE(item);
25870784Sjulian			(error) = ng_snd_item((item), 0);
25970784Sjulian		}
26070784Sjulianelse {
26170784Sjulianprintf("errx=%d\n",error);
26270784Sjulian}
26370784Sjulian		(msg) = NULL;
26470784Sjulian	} while (0);
26570784Sjulian
26670784Sjulian#else
26770700Sjulian	/* The callee will free the msg when done. The path is our business. */
26870700Sjulian	NG_SEND_MSG_PATH(error, pcbp->sockdata->node, msg, path, NULL);
26970784Sjulian#endif
27052419Sjulianrelease:
27152419Sjulian	if (path != NULL)
27252419Sjulian		FREE(path, M_NETGRAPH);
27352419Sjulian	if (control != NULL)
27452419Sjulian		m_freem(control);
27552419Sjulian	if (m != NULL)
27652419Sjulian		m_freem(m);
27752419Sjulian	return (error);
27852419Sjulian}
27952419Sjulian
28052419Sjulianstatic int
28152419Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
28252419Sjulian{
28352419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
28452419Sjulian
28552419Sjulian	if (pcbp == 0)
28652419Sjulian		return (EINVAL);
28752419Sjulian	return (ng_bind(nam, pcbp));
28852419Sjulian}
28952419Sjulian
29052419Sjulianstatic int
29152419Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
29252419Sjulian{
29370784Sjulianprintf(" program tried to connect control socket to remote node\n ");
29470700Sjulian	/*
29570784Sjulian	 * At this time refuse to do this.. it used to
29670700Sjulian	 * do something but it was undocumented and not used.
29770700Sjulian	 */
29870700Sjulian	return (EINVAL);
29952419Sjulian}
30052419Sjulian
30152419Sjulian/***************************************************************
30252419Sjulian	Data sockets
30352419Sjulian***************************************************************/
30452419Sjulian
30552419Sjulianstatic int
30652419Sjulianngd_attach(struct socket *so, int proto, struct proc *p)
30752419Sjulian{
30852419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
30952419Sjulian
31052419Sjulian	if (pcbp != NULL)
31152419Sjulian		return (EISCONN);
31252419Sjulian	return (ng_attach_data(so));
31352419Sjulian}
31452419Sjulian
31552419Sjulianstatic int
31652419Sjulianngd_detach(struct socket *so)
31752419Sjulian{
31852419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
31952419Sjulian
32052419Sjulian	if (pcbp == NULL)
32152419Sjulian		return (EINVAL);
32252419Sjulian	ng_detach_common(pcbp, NG_DATA);
32352419Sjulian	return (0);
32452419Sjulian}
32552419Sjulian
32652419Sjulianstatic int
32752419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
32852419Sjulian	 struct mbuf *control, struct proc *p)
32952419Sjulian{
33052419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
33152419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
33252419Sjulian	int     len, error;
33353498Sjulian	hook_p  hook = NULL;
33453498Sjulian	char	hookname[NG_HOOKLEN + 1];
33552419Sjulian
33652419Sjulian	if ((pcbp == NULL) || (control != NULL)) {
33752419Sjulian		error = EINVAL;
33852419Sjulian		goto release;
33952419Sjulian	}
34052419Sjulian	if (pcbp->sockdata == NULL) {
34152419Sjulian		error = ENOTCONN;
34252419Sjulian		goto release;
34352419Sjulian	}
34453498Sjulian	/*
34553498Sjulian	 * If the user used any of these ways to not specify an address
34653498Sjulian	 * then handle specially.
34753498Sjulian	 */
34853498Sjulian	if ((sap == NULL)
34953498Sjulian	|| ((len = sap->sg_len) <= 2)
35053498Sjulian	|| (*sap->sg_data == '\0')) {
35170784Sjulian		if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) {
35253498Sjulian			error = EDESTADDRREQ;
35353498Sjulian			goto release;
35453498Sjulian		}
35553498Sjulian		/*
35653498Sjulian		 * if exactly one hook exists, just use it.
35753498Sjulian		 * Special case to allow write(2) to work on an ng_socket.
35853498Sjulian		 */
35970784Sjulian		hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks);
36053498Sjulian	} else {
36153498Sjulian		if (len > NG_HOOKLEN) {
36253498Sjulian			error = EINVAL;
36353498Sjulian			goto release;
36453498Sjulian		}
36552419Sjulian
36653498Sjulian		/*
36753498Sjulian		 * chop off the sockaddr header, and make sure it's NUL
36853498Sjulian		 * terminated
36953498Sjulian		 */
37053498Sjulian		bcopy(sap->sg_data, hookname, len);
37153498Sjulian		hookname[len] = '\0';
37252419Sjulian
37353498Sjulian		/* Find the correct hook from 'hookname' */
37470784Sjulian		LIST_FOREACH(hook, &pcbp->sockdata->node->nd_hooks, hk_hooks) {
37570784Sjulian			if (strcmp(hookname, NG_HOOK_NAME(hook)) == 0)
37653498Sjulian				break;
37753498Sjulian		}
37853498Sjulian		if (hook == NULL)
37953498Sjulian			error = EHOSTUNREACH;
38052419Sjulian	}
38152419Sjulian
38252419Sjulian	/* Send data (OK if hook is NULL) */
38369922Sjulian	NG_SEND_DATA_ONLY(error, hook, m);	/* makes m NULL */
38452419Sjulian
38552419Sjulianrelease:
38652419Sjulian	if (control != NULL)
38752419Sjulian		m_freem(control);
38852419Sjulian	if (m != NULL)
38952419Sjulian		m_freem(m);
39052419Sjulian	return (error);
39152419Sjulian}
39252419Sjulian
39352419Sjulianstatic int
39452419Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
39552419Sjulian{
39652419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
39752419Sjulian
39852419Sjulian	if (pcbp == 0)
39952419Sjulian		return (EINVAL);
40052419Sjulian	return (ng_connect_data(nam, pcbp));
40152419Sjulian}
40252419Sjulian
40352419Sjulian/*
40452419Sjulian * Used for both data and control sockets
40552419Sjulian */
40652419Sjulianstatic int
40752419Sjulianng_setsockaddr(struct socket *so, struct sockaddr **addr)
40852419Sjulian{
40953098Sbrian	struct ngpcb *pcbp;
41053098Sbrian	struct sockaddr_ng *sg;
41153098Sbrian	int sg_len, namelen, s;
41252419Sjulian
41353098Sbrian	/* Why isn't sg_data a `char[1]' ? :-( */
41453098Sbrian	sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1;
41553098Sbrian
41653098Sbrian	s = splnet();
41753098Sbrian	pcbp = sotongpcb(so);
41869922Sjulian	if ((pcbp == NULL) || (pcbp->sockdata == NULL)) {
41953098Sbrian		splx(s);
42052419Sjulian		return (EINVAL);
42153098Sbrian	}
42253098Sbrian
42353098Sbrian	namelen = 0;		/* silence compiler ! */
42470784Sjulian	if ( NG_NODE_HAS_NAME(pcbp->sockdata->node))
42570784Sjulian		sg_len += namelen = strlen(NG_NODE_NAME(pcbp->sockdata->node));
42653098Sbrian
42768876Sdwmalone	MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK | M_ZERO);
42853098Sbrian
42970784Sjulian	if (NG_NODE_HAS_NAME(pcbp->sockdata->node))
43070784Sjulian		bcopy(NG_NODE_NAME(pcbp->sockdata->node), sg->sg_data, namelen);
43153098Sbrian	splx(s);
43253098Sbrian
43353098Sbrian	sg->sg_len = sg_len;
43453098Sbrian	sg->sg_family = AF_NETGRAPH;
43553098Sbrian	*addr = (struct sockaddr *)sg;
43653098Sbrian
43752419Sjulian	return (0);
43852419Sjulian}
43952419Sjulian
44052419Sjulian/*
44152419Sjulian * Attach a socket to it's protocol specific partner.
44252419Sjulian * For a control socket, actually create a netgraph node and attach
44352419Sjulian * to it as well.
44452419Sjulian */
44552419Sjulian
44652419Sjulianstatic int
44752419Sjulianng_attach_cntl(struct socket *so)
44852419Sjulian{
44952419Sjulian	struct ngsock *privdata;
45052419Sjulian	struct ngpcb *pcbp;
45152419Sjulian	int error;
45252419Sjulian
45352419Sjulian	/* Setup protocol control block */
45452419Sjulian	if ((error = ng_attach_common(so, NG_CONTROL)) != 0)
45552419Sjulian		return (error);
45653526Sjulian	pcbp = sotongpcb(so);
45752419Sjulian
45852419Sjulian	/* Allocate node private info */
45952419Sjulian	MALLOC(privdata, struct ngsock *,
46068876Sdwmalone	    sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO);
46152419Sjulian	if (privdata == NULL) {
46252419Sjulian		ng_detach_common(pcbp, NG_CONTROL);
46352419Sjulian		return (ENOMEM);
46452419Sjulian	}
46552419Sjulian
46652419Sjulian	/* Make the generic node components */
46752419Sjulian	if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) {
46852419Sjulian		FREE(privdata, M_NETGRAPH);
46952419Sjulian		ng_detach_common(pcbp, NG_CONTROL);
47052419Sjulian		return (error);
47152419Sjulian	}
47270784Sjulian	NG_NODE_SET_PRIVATE(privdata->node, privdata);
47352419Sjulian
47452419Sjulian	/* Link the pcb and the node private data */
47552419Sjulian	privdata->ctlsock = pcbp;
47652419Sjulian	pcbp->sockdata = privdata;
47752419Sjulian	privdata->refs++;
47852419Sjulian	return (0);
47952419Sjulian}
48052419Sjulian
48152419Sjulianstatic int
48252419Sjulianng_attach_data(struct socket *so)
48352419Sjulian{
48452419Sjulian	return(ng_attach_common(so, NG_DATA));
48552419Sjulian}
48652419Sjulian
48752419Sjulian/*
48852419Sjulian * Set up a socket protocol control block.
48952419Sjulian * This code is shared between control and data sockets.
49052419Sjulian */
49152419Sjulianstatic int
49252419Sjulianng_attach_common(struct socket *so, int type)
49352419Sjulian{
49452419Sjulian	struct ngpcb *pcbp;
49552419Sjulian	int error;
49652419Sjulian
49752419Sjulian	/* Standard socket setup stuff */
49852419Sjulian	error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
49952419Sjulian	if (error)
50052419Sjulian		return (error);
50152419Sjulian
50252419Sjulian	/* Allocate the pcb */
50368876Sdwmalone	MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK | M_ZERO);
50452419Sjulian	if (pcbp == NULL)
50552419Sjulian		return (ENOMEM);
50652419Sjulian	pcbp->type = type;
50752419Sjulian
50852419Sjulian	/* Link the pcb and the socket */
50952419Sjulian	so->so_pcb = (caddr_t) pcbp;
51052419Sjulian	pcbp->ng_socket = so;
51152419Sjulian
51252419Sjulian	/* Add the socket to linked list */
51352419Sjulian	LIST_INSERT_HEAD(&ngsocklist, pcbp, socks);
51452419Sjulian	return (0);
51552419Sjulian}
51652419Sjulian
51752419Sjulian/*
51852419Sjulian * Disassociate the socket from it's protocol specific
51952419Sjulian * partner. If it's attached to a node's private data structure,
52052419Sjulian * then unlink from that too. If we were the last socket attached to it,
52152419Sjulian * then shut down the entire node. Shared code for control and data sockets.
52252419Sjulian */
52352419Sjulianstatic void
52452419Sjulianng_detach_common(struct ngpcb *pcbp, int which)
52552419Sjulian{
52652419Sjulian	struct ngsock *sockdata;
52752419Sjulian
52852419Sjulian	if (pcbp->sockdata) {
52952419Sjulian		sockdata = pcbp->sockdata;
53052419Sjulian		pcbp->sockdata = NULL;
53152419Sjulian		switch (which) {
53252419Sjulian		case NG_CONTROL:
53352419Sjulian			sockdata->ctlsock = NULL;
53452419Sjulian			break;
53552419Sjulian		case NG_DATA:
53652419Sjulian			sockdata->datasock = NULL;
53752419Sjulian			break;
53852419Sjulian		default:
53952419Sjulian			panic(__FUNCTION__);
54052419Sjulian		}
54152419Sjulian		if ((--sockdata->refs == 0) && (sockdata->node != NULL))
54270700Sjulian			ng_rmnode_self(sockdata->node);
54352419Sjulian	}
54452419Sjulian	pcbp->ng_socket->so_pcb = NULL;
54552419Sjulian	pcbp->ng_socket = NULL;
54652419Sjulian	LIST_REMOVE(pcbp, socks);
54752419Sjulian	FREE(pcbp, M_PCB);
54852419Sjulian}
54952419Sjulian
55052419Sjulian#ifdef NOTYET
55152419Sjulian/*
55252419Sjulian * File descriptors can be passed into a AF_NETGRAPH socket.
55352419Sjulian * Note, that file descriptors cannot be passed OUT.
55452419Sjulian * Only character device descriptors are accepted.
55552419Sjulian * Character devices are useful to connect a graph to a device,
55652419Sjulian * which after all is the purpose of this whole system.
55752419Sjulian */
55852419Sjulianstatic int
55952419Sjulianng_internalize(struct mbuf *control, struct proc *p)
56052419Sjulian{
56152419Sjulian	struct filedesc *fdp = p->p_fd;
56252419Sjulian	struct cmsghdr *cm = mtod(control, struct cmsghdr *);
56352419Sjulian	struct file *fp;
56452419Sjulian	struct vnode *vn;
56552419Sjulian	int oldfds;
56652419Sjulian	int fd;
56752419Sjulian
56852419Sjulian	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
56952419Sjulian	    cm->cmsg_len != control->m_len) {
57052419Sjulian		TRAP_ERROR;
57152419Sjulian		return (EINVAL);
57252419Sjulian	}
57352419Sjulian
57452419Sjulian	/* Check there is only one FD. XXX what would more than one signify? */
57552419Sjulian	oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int);
57652419Sjulian	if (oldfds != 1) {
57752419Sjulian		TRAP_ERROR;
57852419Sjulian		return (EINVAL);
57952419Sjulian	}
58052419Sjulian
58152419Sjulian	/* Check that the FD given is legit. and change it to a pointer to a
58252419Sjulian	 * struct file. */
58352419Sjulian	fd = *(int *) (cm + 1);
58452419Sjulian	if ((unsigned) fd >= fdp->fd_nfiles
58552419Sjulian	    || (fp = fdp->fd_ofiles[fd]) == NULL) {
58652419Sjulian		return (EBADF);
58752419Sjulian	}
58852419Sjulian
58952419Sjulian	/* Depending on what kind of resource it is, act differently. For
59052419Sjulian	 * devices, we treat it as a file. For a AF_NETGRAPH socket,
59152419Sjulian	 * shortcut straight to the node. */
59252419Sjulian	switch (fp->f_type) {
59352419Sjulian	case DTYPE_VNODE:
59452419Sjulian		vn = (struct vnode *) fp->f_data;
59552419Sjulian		if (vn && (vn->v_type == VCHR)) {
59652419Sjulian			/* for a VCHR, actually reference the FILE */
59752419Sjulian			fp->f_count++;
59852419Sjulian			/* XXX then what :) */
59952419Sjulian			/* how to pass on to other modules? */
60052419Sjulian		} else {
60152419Sjulian			TRAP_ERROR;
60252419Sjulian			return (EINVAL);
60352419Sjulian		}
60452419Sjulian		break;
60552419Sjulian	default:
60652419Sjulian		TRAP_ERROR;
60752419Sjulian		return (EINVAL);
60852419Sjulian	}
60952419Sjulian	return (0);
61052419Sjulian}
61152419Sjulian#endif	/* NOTYET */
61252419Sjulian
61352419Sjulian/*
61452419Sjulian * Connect the data socket to a named control socket node.
61552419Sjulian */
61652419Sjulianstatic int
61752419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
61852419Sjulian{
61952419Sjulian	struct sockaddr_ng *sap;
62052419Sjulian	node_p farnode;
62152419Sjulian	struct ngsock *sockdata;
62252419Sjulian	int error;
62370700Sjulian	item_p item;
62452419Sjulian
62552419Sjulian	/* If we are already connected, don't do it again */
62652419Sjulian	if (pcbp->sockdata != NULL)
62752419Sjulian		return (EISCONN);
62852419Sjulian
62952419Sjulian	/* Find the target (victim) and check it doesn't already have a data
63070700Sjulian	 * socket. Also check it is a 'socket' type node.
63170700Sjulian	 * Use ng_package_data() and address_path() to do this.
63270700Sjulian	 */
63370700Sjulian
63452419Sjulian	sap = (struct sockaddr_ng *) nam;
63570700Sjulian	/* The item will hold the node reference */
63670700Sjulian	item = ng_package_data(NULL, NULL);
63770700Sjulian	if (item == NULL) {
63870700Sjulian		return (ENOMEM);
63970700Sjulian	}
64070700Sjulian	if ((error = ng_address_path(NULL, item,  sap->sg_data, NULL)))
64170700Sjulian		return (error); /* item is freed on failure */
64252419Sjulian
64370700Sjulian	/*
64470784Sjulian	 * Extract node from item and free item. Remember we now have
64570700Sjulian	 * a reference on the node. The item holds it for us.
64670700Sjulian	 * when we free the item we release the reference.
64770700Sjulian	 */
64870700Sjulian	farnode = item->el_dest; /* shortcut */
64970784Sjulian	if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) {
65070700Sjulian		NG_FREE_ITEM(item); /* drop the reference to the node */
65152419Sjulian		return (EINVAL);
65270700Sjulian	}
65370784Sjulian	sockdata = NG_NODE_PRIVATE(farnode);
65470700Sjulian	if (sockdata->datasock != NULL) {
65570700Sjulian		NG_FREE_ITEM(item);	/* drop the reference to the node */
65652419Sjulian		return (EADDRINUSE);
65770700Sjulian	}
65852419Sjulian
65970700Sjulian	/*
66070700Sjulian	 * Link the PCB and the private data struct. and note the extra
66170700Sjulian	 * reference. Drop the extra reference on the node.
66270700Sjulian	 */
66352419Sjulian	sockdata->datasock = pcbp;
66452419Sjulian	pcbp->sockdata = sockdata;
66570700Sjulian	sockdata->refs++; /* XXX possible race if it's being freed */
66670700Sjulian	NG_FREE_ITEM(item);	/* drop the reference to the node */
66752419Sjulian	return (0);
66852419Sjulian}
66952419Sjulian
67052419Sjulian/*
67152419Sjulian * Binding a socket means giving the corresponding node a name
67252419Sjulian */
67352419Sjulianstatic int
67452419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
67552419Sjulian{
67652419Sjulian	struct ngsock *const sockdata = pcbp->sockdata;
67752419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
67852419Sjulian
67952419Sjulian	if (sockdata == NULL) {
68052419Sjulian		TRAP_ERROR;
68152419Sjulian		return (EINVAL);
68252419Sjulian	}
68369922Sjulian	if ((sap->sg_len < 4)
68469922Sjulian	||  (sap->sg_len > (NG_NODELEN + 3))
68569922Sjulian	||  (sap->sg_data[0] == '\0')
68669922Sjulian	||  (sap->sg_data[sap->sg_len - 3] != '\0')) {
68752419Sjulian		TRAP_ERROR;
68852419Sjulian		return (EINVAL);
68952419Sjulian	}
69052419Sjulian	return (ng_name_node(sockdata->node, sap->sg_data));
69152419Sjulian}
69252419Sjulian
69352419Sjulian/*
69452419Sjulian * Take a message and pass it up to the control socket associated
69552419Sjulian * with the node.
69652419Sjulian */
69752419Sjulianstatic int
69852419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr)
69952419Sjulian{
70052419Sjulian	struct socket *const so = pcbp->ng_socket;
70152419Sjulian	struct mbuf *mdata;
70252419Sjulian	int msglen;
70352419Sjulian
70452419Sjulian	/* Copy the message itself into an mbuf chain */
70552419Sjulian	msglen = sizeof(struct ng_mesg) + msg->header.arglen;
70652419Sjulian	mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL);
70752419Sjulian
70852419Sjulian	/* Here we free the message, as we are the end of the line.
70952419Sjulian	 * We need to do that regardless of whether we got mbufs. */
71070700Sjulian	NG_FREE_MSG(msg);
71152419Sjulian
71252419Sjulian	if (mdata == NULL) {
71352419Sjulian		TRAP_ERROR;
71452419Sjulian		return (ENOBUFS);
71552419Sjulian	}
71652419Sjulian
71752419Sjulian	/* Send it up to the socket */
71852419Sjulian	if (sbappendaddr(&so->so_rcv,
71952419Sjulian	    (struct sockaddr *) addr, mdata, NULL) == 0) {
72052419Sjulian		TRAP_ERROR;
72152419Sjulian		m_freem(mdata);
72252419Sjulian		return (ENOBUFS);
72352419Sjulian	}
72452419Sjulian	sorwakeup(so);
72552419Sjulian	return (0);
72652419Sjulian}
72752419Sjulian
72852419Sjulian/*
72952419Sjulian * You can only create new nodes from the socket end of things.
73052419Sjulian */
73152419Sjulianstatic int
73270700Sjulianngs_constructor(node_p nodep)
73352419Sjulian{
73452419Sjulian	return (EINVAL);
73552419Sjulian}
73652419Sjulian
73752419Sjulian/*
73852419Sjulian * We allow any hook to be connected to the node.
73952419Sjulian * There is no per-hook private information though.
74052419Sjulian */
74152419Sjulianstatic int
74252419Sjulianngs_newhook(node_p node, hook_p hook, const char *name)
74352419Sjulian{
74470784Sjulian	NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node));
74552419Sjulian	return (0);
74652419Sjulian}
74752419Sjulian
74852419Sjulian/*
74952419Sjulian * Incoming messages get passed up to the control socket.
75052885Sjulian * Unless they are for us specifically (socket_type)
75152419Sjulian */
75252419Sjulianstatic int
75370700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook)
75452419Sjulian{
75570784Sjulian	struct ngsock *const sockdata = NG_NODE_PRIVATE(node);
75652419Sjulian	struct ngpcb *const pcbp = sockdata->ctlsock;
75752419Sjulian	struct sockaddr_ng *addr;
75852419Sjulian	int addrlen;
75952419Sjulian	int error = 0;
76070700Sjulian	struct	ng_mesg *msg;
76170700Sjulian	ng_ID_t	retaddr = NGI_RETADDR(item);
76270700Sjulian	char	retabuf[32];
76352419Sjulian
76470700Sjulian	NGI_GET_MSG(item, msg);
76570700Sjulian	NG_FREE_ITEM(item); /* we have all we need */
76670700Sjulian
76752419Sjulian	/* Only allow mesgs to be passed if we have the control socket.
76852419Sjulian	 * Data sockets can only support the generic messages. */
76952419Sjulian	if (pcbp == NULL) {
77052419Sjulian		TRAP_ERROR;
77152419Sjulian		return (EINVAL);
77252419Sjulian	}
77370784Sjulian#ifdef TRACE_MESSAGES
77470784Sjulianprintf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n",
77570784Sjulianretaddr,
77670784Sjulianmsg->header.typecookie,
77770784Sjulianmsg->header.cmd,
77870784Sjulianmsg->header.cmdstr,
77970784Sjulianmsg->header.flags,
78070784Sjulianmsg->header.token);
78152419Sjulian
78270784Sjulian#endif
78370784Sjulian
78452885Sjulian	if (msg->header.typecookie == NGM_SOCKET_COOKIE) {
78552885Sjulian		switch (msg->header.cmd) {
78652885Sjulian		case NGM_SOCK_CMD_NOLINGER:
78752885Sjulian			sockdata->flags |= NGS_FLAG_NOLINGER;
78852885Sjulian			break;
78952885Sjulian		case NGM_SOCK_CMD_LINGER:
79052885Sjulian			sockdata->flags &= ~NGS_FLAG_NOLINGER;
79152885Sjulian			break;
79252885Sjulian		default:
79352885Sjulian			error = EINVAL;		/* unknown command */
79452885Sjulian		}
79552885Sjulian		/* Free the message and return */
79670700Sjulian		NG_FREE_MSG(msg);
79752885Sjulian		return(error);
79852885Sjulian
79952885Sjulian	}
80052419Sjulian	/* Get the return address into a sockaddr */
80170700Sjulian	sprintf(retabuf,"[%x]:", retaddr);
80270700Sjulian	addrlen = strlen(retabuf);
80352419Sjulian	MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH, M_NOWAIT);
80452419Sjulian	if (addr == NULL) {
80552419Sjulian		TRAP_ERROR;
80652419Sjulian		return (ENOMEM);
80752419Sjulian	}
80852419Sjulian	addr->sg_len = addrlen + 3;
80952419Sjulian	addr->sg_family = AF_NETGRAPH;
81070700Sjulian	bcopy(retabuf, addr->sg_data, addrlen);
81152419Sjulian	addr->sg_data[addrlen] = '\0';
81252419Sjulian
81352419Sjulian	/* Send it up */
81452419Sjulian	error = ship_msg(pcbp, msg, addr);
81552419Sjulian	FREE(addr, M_NETGRAPH);
81652419Sjulian	return (error);
81752419Sjulian}
81852419Sjulian
81952419Sjulian/*
82052419Sjulian * Receive data on a hook
82152419Sjulian */
82252419Sjulianstatic int
82370700Sjulianngs_rcvdata(hook_p hook, item_p item)
82452419Sjulian{
82570784Sjulian	struct ngsock *const sockdata = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
82652419Sjulian	struct ngpcb *const pcbp = sockdata->datasock;
82752419Sjulian	struct socket *so;
82852419Sjulian	struct sockaddr_ng *addr;
82952419Sjulian	char *addrbuf[NG_HOOKLEN + 1 + 4];
83052419Sjulian	int addrlen;
83170700Sjulian	struct mbuf *m;
83252419Sjulian
83370700Sjulian	NGI_GET_M(item, m);
83470700Sjulian	NG_FREE_ITEM(item);
83552419Sjulian	/* If there is no data socket, black-hole it */
83652419Sjulian	if (pcbp == NULL) {
83770700Sjulian		NG_FREE_M(m);
83852419Sjulian		return (0);
83952419Sjulian	}
84052419Sjulian	so = pcbp->ng_socket;
84152419Sjulian
84252419Sjulian	/* Get the return address into a sockaddr. */
84370784Sjulian	addrlen = strlen(NG_HOOK_NAME(hook));	/* <= NG_HOOKLEN */
84452419Sjulian	addr = (struct sockaddr_ng *) addrbuf;
84552419Sjulian	addr->sg_len = addrlen + 3;
84652419Sjulian	addr->sg_family = AF_NETGRAPH;
84770784Sjulian	bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen);
84852419Sjulian	addr->sg_data[addrlen] = '\0';
84952419Sjulian
85052419Sjulian	/* Try to tell the socket which hook it came in on */
85152419Sjulian	if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) {
85252419Sjulian		m_freem(m);
85352419Sjulian		TRAP_ERROR;
85452419Sjulian		return (ENOBUFS);
85552419Sjulian	}
85652419Sjulian	sorwakeup(so);
85752419Sjulian	return (0);
85852419Sjulian}
85952419Sjulian
86052419Sjulian/*
86153498Sjulian * Hook disconnection
86252885Sjulian *
86352885Sjulian * For this type, removal of the last link destroys the node
86452885Sjulian * if the NOLINGER flag is set.
86552885Sjulian */
86652885Sjulianstatic int
86752885Sjulianngs_disconnect(hook_p hook)
86852885Sjulian{
86970784Sjulian	struct ngsock *const sockdata = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
87052885Sjulian
87152885Sjulian	if ((sockdata->flags & NGS_FLAG_NOLINGER )
87270784Sjulian	&& (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
87370784Sjulian	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
87470784Sjulian		ng_rmnode_self(NG_HOOK_NODE(hook));
87552885Sjulian	}
87652885Sjulian	return (0);
87752885Sjulian}
87852885Sjulian
87952885Sjulian/*
88052419Sjulian * Do local shutdown processing.
88152419Sjulian * In this case, that involves making sure the socket
88252419Sjulian * knows we should be shutting down.
88352419Sjulian */
88452419Sjulianstatic int
88570700Sjulianngs_shutdown(node_p node)
88652419Sjulian{
88770784Sjulian	struct ngsock *const sockdata = NG_NODE_PRIVATE(node);
88852419Sjulian	struct ngpcb *const dpcbp = sockdata->datasock;
88952419Sjulian	struct ngpcb *const pcbp = sockdata->ctlsock;
89052419Sjulian
89152419Sjulian	if (dpcbp != NULL) {
89252419Sjulian		soisdisconnected(dpcbp->ng_socket);
89352419Sjulian		dpcbp->sockdata = NULL;
89452419Sjulian		sockdata->datasock = NULL;
89552419Sjulian		sockdata->refs--;
89652419Sjulian	}
89752419Sjulian	if (pcbp != NULL) {
89852419Sjulian		soisdisconnected(pcbp->ng_socket);
89952419Sjulian		pcbp->sockdata = NULL;
90052419Sjulian		sockdata->ctlsock = NULL;
90152419Sjulian		sockdata->refs--;
90252419Sjulian	}
90370784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
90470784Sjulian	NG_NODE_UNREF(node);
90552419Sjulian	FREE(sockdata, M_NETGRAPH);
90652419Sjulian	return (0);
90752419Sjulian}
90852419Sjulian
90952419Sjulian/*
91052419Sjulian * Control and data socket type descriptors
91152419Sjulian */
91252419Sjulian
91352419Sjulianstatic struct pr_usrreqs ngc_usrreqs = {
91452419Sjulian	NULL,			/* abort */
91552419Sjulian	pru_accept_notsupp,
91652419Sjulian	ngc_attach,
91752419Sjulian	ngc_bind,
91852419Sjulian	ngc_connect,
91952419Sjulian	pru_connect2_notsupp,
92052419Sjulian	pru_control_notsupp,
92152419Sjulian	ngc_detach,
92252419Sjulian	NULL,			/* disconnect */
92352419Sjulian	pru_listen_notsupp,
92452419Sjulian	NULL,			/* setpeeraddr */
92552419Sjulian	pru_rcvd_notsupp,
92652419Sjulian	pru_rcvoob_notsupp,
92752419Sjulian	ngc_send,
92852419Sjulian	pru_sense_null,
92952419Sjulian	NULL,			/* shutdown */
93052419Sjulian	ng_setsockaddr,
93152419Sjulian	sosend,
93252419Sjulian	soreceive,
93352419Sjulian	sopoll
93452419Sjulian};
93552419Sjulian
93652419Sjulianstatic struct pr_usrreqs ngd_usrreqs = {
93752419Sjulian	NULL,			/* abort */
93852419Sjulian	pru_accept_notsupp,
93952419Sjulian	ngd_attach,
94052419Sjulian	NULL,			/* bind */
94152419Sjulian	ngd_connect,
94252419Sjulian	pru_connect2_notsupp,
94352419Sjulian	pru_control_notsupp,
94452419Sjulian	ngd_detach,
94552419Sjulian	NULL,			/* disconnect */
94652419Sjulian	pru_listen_notsupp,
94752419Sjulian	NULL,			/* setpeeraddr */
94852419Sjulian	pru_rcvd_notsupp,
94952419Sjulian	pru_rcvoob_notsupp,
95052419Sjulian	ngd_send,
95152419Sjulian	pru_sense_null,
95252419Sjulian	NULL,			/* shutdown */
95352419Sjulian	ng_setsockaddr,
95452419Sjulian	sosend,
95552419Sjulian	soreceive,
95652419Sjulian	sopoll
95752419Sjulian};
95852419Sjulian
95952419Sjulian/*
96052419Sjulian * Definitions of protocols supported in the NETGRAPH domain.
96152419Sjulian */
96252419Sjulian
96352419Sjulianextern struct domain ngdomain;		/* stop compiler warnings */
96452419Sjulian
96552419Sjulianstatic struct protosw ngsw[] = {
96652419Sjulian	{
96770700Sjulian		SOCK_DGRAM,		/* protocol type */
96870700Sjulian		&ngdomain,		/* backpointer to domain */
96952419Sjulian		NG_CONTROL,
97070700Sjulian		PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,	/* flags */
97170700Sjulian		0, 0, 0, 0,		/* input, output, ctlinput, ctloutput */
97270700Sjulian		NULL,			/* ousrreq */
97370700Sjulian		0, 0, 0, 0,		/* init, fasttimeo, slowtimo, drain */
97470700Sjulian		&ngc_usrreqs,		/* usrreq table (above) */
97570700Sjulian		/*{NULL}*/		/* pffh (protocol filter head?) */
97652419Sjulian	},
97752419Sjulian	{
97870700Sjulian		SOCK_DGRAM,		/* protocol type */
97970700Sjulian		&ngdomain,		/* backpointer to domain */
98052419Sjulian		NG_DATA,
98170700Sjulian		PR_ATOMIC | PR_ADDR,	/* flags */
98270700Sjulian		0, 0, 0, 0,		/* input, output, ctlinput, ctloutput */
98370700Sjulian		NULL,			/* ousrreq() */
98470700Sjulian		0, 0, 0, 0,		/* init, fasttimeo, slowtimo, drain */
98570700Sjulian		&ngd_usrreqs,		/* usrreq table (above) */
98670700Sjulian		/*{NULL}*/		/* pffh (protocol filter head?) */
98752419Sjulian	}
98852419Sjulian};
98952419Sjulian
99052419Sjulianstruct domain ngdomain = {
99152419Sjulian	AF_NETGRAPH,
99252419Sjulian	"netgraph",
99370700Sjulian	NULL,					/* init() */
99470700Sjulian	NULL,					/* externalise() */
99570700Sjulian	NULL,					/* dispose() */
99670700Sjulian	ngsw,					/* protosw entry */
99770700Sjulian	&ngsw[sizeof(ngsw) / sizeof(ngsw[0])], 	/* Number of protosw entries */
99870700Sjulian	NULL,					/* next domain in list */
99970700Sjulian	NULL,					/* rtattach() */
100070700Sjulian	0,					/* arg to rtattach in bits */
100170700Sjulian	0					/* maxrtkey */
100252419Sjulian};
100352419Sjulian
100452419Sjulian/*
100552419Sjulian * Handle loading and unloading for this node type
100652419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition).
100752419Sjulian */
100852419Sjulianstatic int
100952419Sjulianngs_mod_event(module_t mod, int event, void *data)
101052419Sjulian{
101152419Sjulian	int error = 0;
101252419Sjulian
101352419Sjulian	switch (event) {
101452419Sjulian	case MOD_LOAD:
101552419Sjulian		/* Register protocol domain */
101652419Sjulian		net_add_domain(&ngdomain);
101752419Sjulian		break;
101852419Sjulian	case MOD_UNLOAD:
101952419Sjulian		/* Insure there are no open netgraph sockets */
102052419Sjulian		if (!LIST_EMPTY(&ngsocklist)) {
102152419Sjulian			error = EBUSY;
102252419Sjulian			break;
102352419Sjulian		}
102452419Sjulian
102552419Sjulian#ifdef NOTYET
102670700Sjulian		if ((LIST_EMPTY(&ngsocklist)) && (typestruct.refs == 0)) {
102752419Sjulian		/* Unregister protocol domain XXX can't do this yet.. */
102870700Sjulian			if ((error = net_rm_domain(&ngdomain)) != 0)
102970700Sjulian				break;
103070700Sjulian		} else
103152419Sjulian#endif
103270700Sjulian			error = EBUSY;
103352419Sjulian		break;
103452419Sjulian	default:
103552419Sjulian		error = EOPNOTSUPP;
103652419Sjulian		break;
103752419Sjulian	}
103852419Sjulian	return (error);
103952419Sjulian}
104052419Sjulian
104152419SjulianSYSCTL_NODE(_net, AF_NETGRAPH, graph, CTLFLAG_RW, 0, "netgraph Family");
104252419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, "");
104352419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA");
104452419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, "");
104552419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL");
104652419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, "");
104752419Sjulian
1048