ng_socket.c revision 53098
152419Sjulian
252419Sjulian/*
352419Sjulian * ng_socket.c
452419Sjulian *
552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc.
652419Sjulian * All rights reserved.
752419Sjulian *
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.
1852419Sjulian *
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 *
3752419Sjulian * Author: Julian Elischer <julian@whistle.com>
3852419Sjulian *
3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_socket.c 53098 1999-11-11 20:08:04Z brian $
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/proc.h>
5452419Sjulian#include <sys/domain.h>
5552419Sjulian#include <sys/errno.h>
5652419Sjulian#include <sys/kernel.h>
5752419Sjulian#include <sys/file.h>
5852419Sjulian#include <sys/filedesc.h>
5952419Sjulian#include <sys/malloc.h>
6052419Sjulian#include <sys/queue.h>
6152419Sjulian#include <sys/mbuf.h>
6252419Sjulian#include <sys/protosw.h>
6352419Sjulian#include <sys/socket.h>
6452419Sjulian#include <sys/socketvar.h>
6552419Sjulian#include <sys/sysctl.h>
6652419Sjulian#ifdef NOTYET
6752419Sjulian#include <sys/vnode.h>
6852419Sjulian#endif
6952419Sjulian#include <netgraph/ng_message.h>
7052419Sjulian#include <netgraph/netgraph.h>
7152919Sjulian#include <netgraph/ng_socketvar.h>
7252419Sjulian#include <netgraph/ng_socket.h>
7352419Sjulian
7452419Sjulian/*
7552419Sjulian * It's Ascii-art time!
7652419Sjulian *   +-------------+   +-------------+
7752419Sjulian *   |socket  (ctl)|   |socket (data)|
7852419Sjulian *   +-------------+   +-------------+
7952419Sjulian *          ^                 ^
8052419Sjulian *          |                 |
8152419Sjulian *          v                 v
8252419Sjulian *    +-----------+     +-----------+
8352419Sjulian *    |pcb   (ctl)|     |pcb  (data)|
8452419Sjulian *    +-----------+     +-----------+
8552419Sjulian *          ^                 ^
8652419Sjulian *          |                 |
8752419Sjulian *          v                 v
8852419Sjulian *      +--------------------------+
8952419Sjulian *      |   Socket type private    |
9052419Sjulian *      |       data               |
9152419Sjulian *      +--------------------------+
9252419Sjulian *                   ^
9352419Sjulian *                   |
9452419Sjulian *                   v
9552419Sjulian *           +----------------+
9652419Sjulian *           | struct ng_node |
9752419Sjulian *           +----------------+
9852419Sjulian */
9952419Sjulian
10052419Sjulian/* Netgraph node methods */
10152752Sjulianstatic ng_constructor_t	ngs_constructor;
10252752Sjulianstatic ng_rcvmsg_t	ngs_rcvmsg;
10352752Sjulianstatic ng_shutdown_t	ngs_rmnode;
10452752Sjulianstatic ng_newhook_t	ngs_newhook;
10552752Sjulianstatic ng_rcvdata_t	ngs_rcvdata;
10652885Sjulianstatic ng_disconnect_t	ngs_disconnect;
10752419Sjulian
10852419Sjulian/* Internal methods */
10952419Sjulianstatic int	ng_attach_data(struct socket *so);
11052419Sjulianstatic int	ng_attach_cntl(struct socket *so);
11152419Sjulianstatic int	ng_attach_common(struct socket *so, int type);
11252419Sjulianstatic void	ng_detach_common(struct ngpcb *pcbp, int type);
11352419Sjulian/*static int	ng_internalize(struct mbuf *m, struct proc *p); */
11452419Sjulian
11552419Sjulianstatic int	ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
11652419Sjulianstatic int	ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp);
11752419Sjulianstatic int	ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
11852419Sjulian
11952419Sjulianstatic int	ngs_mod_event(module_t mod, int event, void *data);
12052419Sjulianstatic int	ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg,
12152419Sjulian			struct sockaddr_ng *addr);
12252419Sjulian
12352419Sjulian/* Netgraph type descriptor */
12452419Sjulianstatic struct ng_type typestruct = {
12552419Sjulian	NG_VERSION,
12652419Sjulian	NG_SOCKET_NODE_TYPE,
12752419Sjulian	ngs_mod_event,
12852419Sjulian	ngs_constructor,
12952419Sjulian	ngs_rcvmsg,
13052419Sjulian	ngs_rmnode,
13152419Sjulian	ngs_newhook,
13252419Sjulian	NULL,
13352419Sjulian	NULL,
13452419Sjulian	ngs_rcvdata,
13552419Sjulian	ngs_rcvdata,
13652885Sjulian	ngs_disconnect
13752419Sjulian};
13852419SjulianNETGRAPH_INIT(socket, &typestruct);
13952419Sjulian
14052419Sjulian/* Buffer space */
14152419Sjulianstatic u_long ngpdg_sendspace = 2 * 1024;	/* really max datagram size */
14252419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024;
14352419Sjulian
14452419Sjulian/* List of all sockets */
14552419SjulianLIST_HEAD(, ngpcb) ngsocklist;
14652419Sjulian
14752419Sjulian#define sotongpcb(so) ((struct ngpcb *)so->so_pcb)
14852419Sjulian
14952419Sjulian/* If getting unexplained errors returned, set this to "Debugger("X"); */
15052419Sjulian#ifndef TRAP_ERROR
15152419Sjulian#define TRAP_ERROR
15252419Sjulian#endif
15352419Sjulian
15452419Sjulian/***************************************************************
15552419Sjulian	Control sockets
15652419Sjulian***************************************************************/
15752419Sjulian
15852419Sjulianstatic int
15952419Sjulianngc_attach(struct socket *so, int proto, struct proc *p)
16052419Sjulian{
16152419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
16252419Sjulian
16352419Sjulian	if (pcbp != NULL)
16452419Sjulian		return (EISCONN);
16552419Sjulian	return (ng_attach_cntl(so));
16652419Sjulian}
16752419Sjulian
16852419Sjulianstatic int
16952419Sjulianngc_detach(struct socket *so)
17052419Sjulian{
17152419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
17252419Sjulian
17352419Sjulian	if (pcbp == NULL)
17452419Sjulian		return (EINVAL);
17552419Sjulian	ng_detach_common(pcbp, NG_CONTROL);
17652419Sjulian	return (0);
17752419Sjulian}
17852419Sjulian
17952419Sjulianstatic int
18052419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
18152419Sjulian	 struct mbuf *control, struct proc *p)
18252419Sjulian{
18352419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
18452419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
18552419Sjulian	struct ng_mesg *resp;
18652419Sjulian	struct mbuf *m0;
18752419Sjulian	char *msg, *path = NULL;
18852419Sjulian	int len, error = 0;
18952419Sjulian
19052419Sjulian	if (pcbp == NULL) {
19152419Sjulian		error = EINVAL;
19252419Sjulian		goto release;
19352419Sjulian	}
19452419Sjulian#ifdef	NOTYET
19552419Sjulian	if (control && (error = ng_internalize(control, p))) {
19652419Sjulian		if (pcbp->sockdata == NULL) {
19752419Sjulian			error = ENOTCONN;
19852419Sjulian			goto release;
19952419Sjulian		}
20052419Sjulian	}
20152419Sjulian#else	/* NOTYET */
20252419Sjulian	if (control) {
20352419Sjulian		error = EINVAL;
20452419Sjulian		goto release;
20552419Sjulian	}
20652419Sjulian#endif	/* NOTYET */
20752419Sjulian
20852419Sjulian	/* Require destination as there may be >= 1 hooks on this node */
20952419Sjulian	if (addr == NULL) {
21052419Sjulian		error = EDESTADDRREQ;
21152419Sjulian		goto release;
21252419Sjulian	}
21352419Sjulian
21452419Sjulian	/* Allocate an expendable buffer for the path, chop off
21552419Sjulian	 * the sockaddr header, and make sure it's NUL terminated */
21652419Sjulian	len = sap->sg_len - 2;
21752419Sjulian	MALLOC(path, char *, len + 1, M_NETGRAPH, M_WAITOK);
21852419Sjulian	if (path == NULL) {
21952419Sjulian		error = ENOMEM;
22052419Sjulian		goto release;
22152419Sjulian	}
22252419Sjulian	bcopy(sap->sg_data, path, len);
22352419Sjulian	path[len] = '\0';
22452419Sjulian
22552419Sjulian	/* Move the actual message out of mbufs into a linear buffer.
22652419Sjulian	 * Start by adding up the size of the data. (could use mh_len?) */
22752419Sjulian	for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
22852419Sjulian		len += m0->m_len;
22952419Sjulian
23052419Sjulian	/* Move the data into a linear buffer as well. Messages are not
23152419Sjulian	 * delivered in mbufs. */
23252419Sjulian	MALLOC(msg, char *, len + 1, M_NETGRAPH, M_WAITOK);
23352419Sjulian	if (msg == NULL) {
23452419Sjulian		error = ENOMEM;
23552419Sjulian		goto release;
23652419Sjulian	}
23752419Sjulian	m_copydata(m, 0, len, msg);
23852419Sjulian
23952419Sjulian	/* The callee will free the msg when done. The addr is our business. */
24052419Sjulian	error = ng_send_msg(pcbp->sockdata->node,
24152419Sjulian			    (struct ng_mesg *) msg, path, &resp);
24252419Sjulian
24352419Sjulian	/* If the callee responded with a synchronous response, then put it
24452419Sjulian	 * back on the receive side of the socket; sap is source address. */
24552419Sjulian	if (error == 0 && resp != NULL)
24652419Sjulian		error = ship_msg(pcbp, resp, sap);
24752419Sjulian
24852419Sjulianrelease:
24952419Sjulian	if (path != NULL)
25052419Sjulian		FREE(path, M_NETGRAPH);
25152419Sjulian	if (control != NULL)
25252419Sjulian		m_freem(control);
25352419Sjulian	if (m != NULL)
25452419Sjulian		m_freem(m);
25552419Sjulian	return (error);
25652419Sjulian}
25752419Sjulian
25852419Sjulianstatic int
25952419Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
26052419Sjulian{
26152419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
26252419Sjulian
26352419Sjulian	if (pcbp == 0)
26452419Sjulian		return (EINVAL);
26552419Sjulian	return (ng_bind(nam, pcbp));
26652419Sjulian}
26752419Sjulian
26852419Sjulianstatic int
26952419Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
27052419Sjulian{
27152419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
27252419Sjulian
27352419Sjulian	if (pcbp == 0)
27452419Sjulian		return (EINVAL);
27552419Sjulian	return (ng_connect_cntl(nam, pcbp));
27652419Sjulian}
27752419Sjulian
27852419Sjulian/***************************************************************
27952419Sjulian	Data sockets
28052419Sjulian***************************************************************/
28152419Sjulian
28252419Sjulianstatic int
28352419Sjulianngd_attach(struct socket *so, int proto, struct proc *p)
28452419Sjulian{
28552419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
28652419Sjulian
28752419Sjulian	if (pcbp != NULL)
28852419Sjulian		return (EISCONN);
28952419Sjulian	return (ng_attach_data(so));
29052419Sjulian}
29152419Sjulian
29252419Sjulianstatic int
29352419Sjulianngd_detach(struct socket *so)
29452419Sjulian{
29552419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
29652419Sjulian
29752419Sjulian	if (pcbp == NULL)
29852419Sjulian		return (EINVAL);
29952419Sjulian	ng_detach_common(pcbp, NG_DATA);
30052419Sjulian	return (0);
30152419Sjulian}
30252419Sjulian
30352419Sjulianstatic int
30452419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
30552419Sjulian	 struct mbuf *control, struct proc *p)
30652419Sjulian{
30752419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
30852419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
30952419Sjulian	char   *hookname = NULL;
31052419Sjulian	meta_p  mp = NULL;
31152419Sjulian	int     len, error;
31252419Sjulian	hook_p  hook;
31352419Sjulian
31452419Sjulian	if ((pcbp == NULL) || (control != NULL)) {
31552419Sjulian		error = EINVAL;
31652419Sjulian		goto release;
31752419Sjulian	}
31852419Sjulian	if (pcbp->sockdata == NULL) {
31952419Sjulian		error = ENOTCONN;
32052419Sjulian		goto release;
32152419Sjulian	}
32252419Sjulian	if (addr == NULL) {
32352419Sjulian		error = EDESTADDRREQ;
32452419Sjulian		goto release;
32552419Sjulian	}
32652419Sjulian
32752419Sjulian	/* Allocate an expendable buffer for the hook name, chop off
32852419Sjulian	 * the sockaddr header, and make sure it's NUL terminated */
32952419Sjulian	len = sap->sg_len - 2;
33052419Sjulian	MALLOC(hookname, char *, len + 1, M_NETGRAPH, M_WAITOK);
33152419Sjulian	if (hookname == NULL) {
33252419Sjulian		error = ENOMEM;
33352419Sjulian		goto release;
33452419Sjulian	}
33552419Sjulian	bcopy(sap->sg_data, hookname, len);
33652419Sjulian	hookname[len] = '\0';
33752419Sjulian
33852419Sjulian	/* Find the correct hook from 'hookname' */
33952419Sjulian	LIST_FOREACH(hook, &pcbp->sockdata->node->hooks, hooks) {
34052419Sjulian		if (strcmp(hookname, hook->name) == 0)
34152419Sjulian			break;
34252419Sjulian	}
34352419Sjulian
34452419Sjulian	/* Send data (OK if hook is NULL) */
34552419Sjulian	NG_SEND_DATA(error, hook, m, mp);	/* makes m NULL */
34652419Sjulian
34752419Sjulianrelease:
34852419Sjulian	if (hookname != NULL)
34952419Sjulian		FREE(hookname, M_NETGRAPH);
35052419Sjulian	if (control != NULL)
35152419Sjulian		m_freem(control);
35252419Sjulian	if (m != NULL)
35352419Sjulian		m_freem(m);
35452419Sjulian	return (error);
35552419Sjulian}
35652419Sjulian
35752419Sjulianstatic int
35852419Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
35952419Sjulian{
36052419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
36152419Sjulian
36252419Sjulian	if (pcbp == 0)
36352419Sjulian		return (EINVAL);
36452419Sjulian	return (ng_connect_data(nam, pcbp));
36552419Sjulian}
36652419Sjulian
36752419Sjulian/*
36852419Sjulian * Used for both data and control sockets
36952419Sjulian */
37052419Sjulianstatic int
37152419Sjulianng_setsockaddr(struct socket *so, struct sockaddr **addr)
37252419Sjulian{
37353098Sbrian	struct ngpcb *pcbp;
37453098Sbrian	struct sockaddr_ng *sg;
37553098Sbrian	int sg_len, namelen, s;
37652419Sjulian
37753098Sbrian	/* Why isn't sg_data a `char[1]' ? :-( */
37853098Sbrian	sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1;
37953098Sbrian
38053098Sbrian	s = splnet();
38153098Sbrian	pcbp = sotongpcb(so);
38253098Sbrian	if (pcbp == 0) {
38353098Sbrian		splx(s);
38452419Sjulian		return (EINVAL);
38553098Sbrian	}
38653098Sbrian
38753098Sbrian	namelen = 0;		/* silence compiler ! */
38853098Sbrian
38953098Sbrian	if (pcbp->sockdata->node->name != NULL)
39053098Sbrian		sg_len += namelen = strlen(pcbp->sockdata->node->name);
39153098Sbrian
39253098Sbrian	MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK);
39353098Sbrian	bzero(sg, sg_len);
39453098Sbrian
39553098Sbrian	if (pcbp->sockdata->node->name != NULL)
39653098Sbrian		bcopy(pcbp->sockdata->node->name, sg->sg_data, namelen);
39753098Sbrian	splx(s);
39853098Sbrian
39953098Sbrian	sg->sg_len = sg_len;
40053098Sbrian	sg->sg_family = AF_NETGRAPH;
40153098Sbrian	*addr = (struct sockaddr *)sg;
40253098Sbrian
40352419Sjulian	return (0);
40452419Sjulian}
40552419Sjulian
40652419Sjulian/*
40752419Sjulian * Attach a socket to it's protocol specific partner.
40852419Sjulian * For a control socket, actually create a netgraph node and attach
40952419Sjulian * to it as well.
41052419Sjulian */
41152419Sjulian
41252419Sjulianstatic int
41352419Sjulianng_attach_cntl(struct socket *so)
41452419Sjulian{
41552419Sjulian	struct ngsock *privdata;
41652419Sjulian	struct ngpcb *pcbp;
41752419Sjulian	int error;
41852419Sjulian
41952419Sjulian	/* Setup protocol control block */
42052419Sjulian	if ((error = ng_attach_common(so, NG_CONTROL)) != 0)
42152419Sjulian		return (error);
42252419Sjulian	pcbp = (struct ngpcb *) so->so_pcb;
42352419Sjulian
42452419Sjulian	/* Allocate node private info */
42552419Sjulian	MALLOC(privdata, struct ngsock *,
42652419Sjulian	    sizeof(*privdata), M_NETGRAPH, M_WAITOK);
42752419Sjulian	if (privdata == NULL) {
42852419Sjulian		ng_detach_common(pcbp, NG_CONTROL);
42952419Sjulian		return (ENOMEM);
43052419Sjulian	}
43152419Sjulian	bzero(privdata, sizeof(*privdata));
43252419Sjulian
43352419Sjulian	/* Make the generic node components */
43452419Sjulian	if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) {
43552419Sjulian		FREE(privdata, M_NETGRAPH);
43652419Sjulian		ng_detach_common(pcbp, NG_CONTROL);
43752419Sjulian		return (error);
43852419Sjulian	}
43952419Sjulian	privdata->node->private = privdata;
44052419Sjulian
44152419Sjulian	/* Link the pcb and the node private data */
44252419Sjulian	privdata->ctlsock = pcbp;
44352419Sjulian	pcbp->sockdata = privdata;
44452419Sjulian	privdata->refs++;
44552419Sjulian	return (0);
44652419Sjulian}
44752419Sjulian
44852419Sjulianstatic int
44952419Sjulianng_attach_data(struct socket *so)
45052419Sjulian{
45152419Sjulian	return(ng_attach_common(so, NG_DATA));
45252419Sjulian}
45352419Sjulian
45452419Sjulian/*
45552419Sjulian * Set up a socket protocol control block.
45652419Sjulian * This code is shared between control and data sockets.
45752419Sjulian */
45852419Sjulianstatic int
45952419Sjulianng_attach_common(struct socket *so, int type)
46052419Sjulian{
46152419Sjulian	struct ngpcb *pcbp;
46252419Sjulian	int error;
46352419Sjulian
46452419Sjulian	/* Standard socket setup stuff */
46552419Sjulian	error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
46652419Sjulian	if (error)
46752419Sjulian		return (error);
46852419Sjulian
46952419Sjulian	/* Allocate the pcb */
47052419Sjulian	MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK);
47152419Sjulian	if (pcbp == NULL)
47252419Sjulian		return (ENOMEM);
47352419Sjulian	bzero(pcbp, sizeof(*pcbp));
47452419Sjulian	pcbp->type = type;
47552419Sjulian
47652419Sjulian	/* Link the pcb and the socket */
47752419Sjulian	so->so_pcb = (caddr_t) pcbp;
47852419Sjulian	pcbp->ng_socket = so;
47952419Sjulian
48052419Sjulian	/* Add the socket to linked list */
48152419Sjulian	LIST_INSERT_HEAD(&ngsocklist, pcbp, socks);
48252419Sjulian	return (0);
48352419Sjulian}
48452419Sjulian
48552419Sjulian/*
48652419Sjulian * Disassociate the socket from it's protocol specific
48752419Sjulian * partner. If it's attached to a node's private data structure,
48852419Sjulian * then unlink from that too. If we were the last socket attached to it,
48952419Sjulian * then shut down the entire node. Shared code for control and data sockets.
49052419Sjulian */
49152419Sjulianstatic void
49252419Sjulianng_detach_common(struct ngpcb *pcbp, int which)
49352419Sjulian{
49452419Sjulian	struct ngsock *sockdata;
49552419Sjulian
49652419Sjulian	if (pcbp->sockdata) {
49752419Sjulian		sockdata = pcbp->sockdata;
49852419Sjulian		pcbp->sockdata = NULL;
49952419Sjulian		switch (which) {
50052419Sjulian		case NG_CONTROL:
50152419Sjulian			sockdata->ctlsock = NULL;
50252419Sjulian			break;
50352419Sjulian		case NG_DATA:
50452419Sjulian			sockdata->datasock = NULL;
50552419Sjulian			break;
50652419Sjulian		default:
50752419Sjulian			panic(__FUNCTION__);
50852419Sjulian		}
50952419Sjulian		if ((--sockdata->refs == 0) && (sockdata->node != NULL))
51052419Sjulian			ng_rmnode(sockdata->node);
51152419Sjulian	}
51252419Sjulian	pcbp->ng_socket->so_pcb = NULL;
51352419Sjulian	pcbp->ng_socket = NULL;
51452419Sjulian	LIST_REMOVE(pcbp, socks);
51552419Sjulian	FREE(pcbp, M_PCB);
51652419Sjulian}
51752419Sjulian
51852419Sjulian#ifdef NOTYET
51952419Sjulian/*
52052419Sjulian * File descriptors can be passed into a AF_NETGRAPH socket.
52152419Sjulian * Note, that file descriptors cannot be passed OUT.
52252419Sjulian * Only character device descriptors are accepted.
52352419Sjulian * Character devices are useful to connect a graph to a device,
52452419Sjulian * which after all is the purpose of this whole system.
52552419Sjulian */
52652419Sjulianstatic int
52752419Sjulianng_internalize(struct mbuf *control, struct proc *p)
52852419Sjulian{
52952419Sjulian	struct filedesc *fdp = p->p_fd;
53052419Sjulian	struct cmsghdr *cm = mtod(control, struct cmsghdr *);
53152419Sjulian	struct file *fp;
53252419Sjulian	struct vnode *vn;
53352419Sjulian	int oldfds;
53452419Sjulian	int fd;
53552419Sjulian
53652419Sjulian	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
53752419Sjulian	    cm->cmsg_len != control->m_len) {
53852419Sjulian		TRAP_ERROR;
53952419Sjulian		return (EINVAL);
54052419Sjulian	}
54152419Sjulian
54252419Sjulian	/* Check there is only one FD. XXX what would more than one signify? */
54352419Sjulian	oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int);
54452419Sjulian	if (oldfds != 1) {
54552419Sjulian		TRAP_ERROR;
54652419Sjulian		return (EINVAL);
54752419Sjulian	}
54852419Sjulian
54952419Sjulian	/* Check that the FD given is legit. and change it to a pointer to a
55052419Sjulian	 * struct file. */
55152419Sjulian	fd = *(int *) (cm + 1);
55252419Sjulian	if ((unsigned) fd >= fdp->fd_nfiles
55352419Sjulian	    || (fp = fdp->fd_ofiles[fd]) == NULL) {
55452419Sjulian		return (EBADF);
55552419Sjulian	}
55652419Sjulian
55752419Sjulian	/* Depending on what kind of resource it is, act differently. For
55852419Sjulian	 * devices, we treat it as a file. For a AF_NETGRAPH socket,
55952419Sjulian	 * shortcut straight to the node. */
56052419Sjulian	switch (fp->f_type) {
56152419Sjulian	case DTYPE_VNODE:
56252419Sjulian		vn = (struct vnode *) fp->f_data;
56352419Sjulian		if (vn && (vn->v_type == VCHR)) {
56452419Sjulian			/* for a VCHR, actually reference the FILE */
56552419Sjulian			fp->f_count++;
56652419Sjulian			/* XXX then what :) */
56752419Sjulian			/* how to pass on to other modules? */
56852419Sjulian		} else {
56952419Sjulian			TRAP_ERROR;
57052419Sjulian			return (EINVAL);
57152419Sjulian		}
57252419Sjulian		break;
57352419Sjulian	default:
57452419Sjulian		TRAP_ERROR;
57552419Sjulian		return (EINVAL);
57652419Sjulian	}
57752419Sjulian	return (0);
57852419Sjulian}
57952419Sjulian#endif	/* NOTYET */
58052419Sjulian
58152419Sjulian/*
58252419Sjulian * Connect the data socket to a named control socket node.
58352419Sjulian */
58452419Sjulianstatic int
58552419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
58652419Sjulian{
58752419Sjulian	struct sockaddr_ng *sap;
58852419Sjulian	node_p farnode;
58952419Sjulian	struct ngsock *sockdata;
59052419Sjulian	int error;
59152419Sjulian
59252419Sjulian	/* If we are already connected, don't do it again */
59352419Sjulian	if (pcbp->sockdata != NULL)
59452419Sjulian		return (EISCONN);
59552419Sjulian
59652419Sjulian	/* Find the target (victim) and check it doesn't already have a data
59752419Sjulian	 * socket. Also check it is a 'socket' type node. */
59852419Sjulian	sap = (struct sockaddr_ng *) nam;
59952419Sjulian	if ((error = ng_path2node(NULL, sap->sg_data, &farnode, NULL)))
60052419Sjulian		return (error);
60152419Sjulian
60252419Sjulian	if (strcmp(farnode->type->name, NG_SOCKET_NODE_TYPE) != 0)
60352419Sjulian		return (EINVAL);
60452419Sjulian	sockdata = farnode->private;
60552419Sjulian	if (sockdata->datasock != NULL)
60652419Sjulian		return (EADDRINUSE);
60752419Sjulian
60852419Sjulian	/* Link the PCB and the private data struct. and note the extra
60952419Sjulian	 * reference */
61052419Sjulian	sockdata->datasock = pcbp;
61152419Sjulian	pcbp->sockdata = sockdata;
61252419Sjulian	sockdata->refs++;
61352419Sjulian	return (0);
61452419Sjulian}
61552419Sjulian
61652419Sjulian/*
61752419Sjulian * Connect the existing control socket node to a named node:hook.
61852419Sjulian * The hook we use on this end is the same name as the remote node name.
61952419Sjulian */
62052419Sjulianstatic int
62152419Sjulianng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp)
62252419Sjulian{
62352419Sjulian	struct ngsock *const sockdata = pcbp->sockdata;
62452419Sjulian	struct sockaddr_ng *sap;
62552419Sjulian	char *node, *hook;
62652419Sjulian	node_p farnode;
62752419Sjulian	int rtn, error;
62852419Sjulian
62952419Sjulian	sap = (struct sockaddr_ng *) nam;
63052419Sjulian	rtn = ng_path_parse(sap->sg_data, &node, NULL, &hook);
63152419Sjulian	if (rtn < 0 || node == NULL || hook == NULL) {
63252419Sjulian		TRAP_ERROR;
63352419Sjulian		return (EINVAL);
63452419Sjulian	}
63552419Sjulian	farnode = ng_findname(sockdata->node, node);
63652419Sjulian	if (farnode == NULL) {
63752419Sjulian		TRAP_ERROR;
63852419Sjulian		return (EADDRNOTAVAIL);
63952419Sjulian	}
64052419Sjulian
64152419Sjulian	/* Connect, using a hook name the same as the far node name. */
64252419Sjulian	error = ng_con_nodes(sockdata->node, node, farnode, hook);
64352419Sjulian	return error;
64452419Sjulian}
64552419Sjulian
64652419Sjulian/*
64752419Sjulian * Binding a socket means giving the corresponding node a name
64852419Sjulian */
64952419Sjulianstatic int
65052419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
65152419Sjulian{
65252419Sjulian	struct ngsock *const sockdata = pcbp->sockdata;
65352419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
65452419Sjulian
65552419Sjulian	if (sockdata == NULL) {
65652419Sjulian		TRAP_ERROR;
65752419Sjulian		return (EINVAL);
65852419Sjulian	}
65952419Sjulian	if (sap->sg_len < 3 || sap->sg_data[sap->sg_len - 3] != '\0') {
66052419Sjulian		TRAP_ERROR;
66152419Sjulian		return (EINVAL);
66252419Sjulian	}
66352419Sjulian	return (ng_name_node(sockdata->node, sap->sg_data));
66452419Sjulian}
66552419Sjulian
66652419Sjulian/*
66752419Sjulian * Take a message and pass it up to the control socket associated
66852419Sjulian * with the node.
66952419Sjulian */
67052419Sjulianstatic int
67152419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr)
67252419Sjulian{
67352419Sjulian	struct socket *const so = pcbp->ng_socket;
67452419Sjulian	struct mbuf *mdata;
67552419Sjulian	int msglen;
67652419Sjulian
67752419Sjulian	/* Copy the message itself into an mbuf chain */
67852419Sjulian	msglen = sizeof(struct ng_mesg) + msg->header.arglen;
67952419Sjulian	mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL);
68052419Sjulian
68152419Sjulian	/* Here we free the message, as we are the end of the line.
68252419Sjulian	 * We need to do that regardless of whether we got mbufs. */
68352419Sjulian	FREE(msg, M_NETGRAPH);
68452419Sjulian
68552419Sjulian	if (mdata == NULL) {
68652419Sjulian		TRAP_ERROR;
68752419Sjulian		return (ENOBUFS);
68852419Sjulian	}
68952419Sjulian
69052419Sjulian	/* Send it up to the socket */
69152419Sjulian	if (sbappendaddr(&so->so_rcv,
69252419Sjulian	    (struct sockaddr *) addr, mdata, NULL) == 0) {
69352419Sjulian		TRAP_ERROR;
69452419Sjulian		m_freem(mdata);
69552419Sjulian		return (ENOBUFS);
69652419Sjulian	}
69752419Sjulian	sorwakeup(so);
69852419Sjulian	return (0);
69952419Sjulian}
70052419Sjulian
70152419Sjulian/*
70252419Sjulian * You can only create new nodes from the socket end of things.
70352419Sjulian */
70452419Sjulianstatic int
70552419Sjulianngs_constructor(node_p *nodep)
70652419Sjulian{
70752419Sjulian	return (EINVAL);
70852419Sjulian}
70952419Sjulian
71052419Sjulian/*
71152419Sjulian * We allow any hook to be connected to the node.
71252419Sjulian * There is no per-hook private information though.
71352419Sjulian */
71452419Sjulianstatic int
71552419Sjulianngs_newhook(node_p node, hook_p hook, const char *name)
71652419Sjulian{
71752419Sjulian	hook->private = node->private;
71852419Sjulian	return (0);
71952419Sjulian}
72052419Sjulian
72152419Sjulian/*
72252419Sjulian * Incoming messages get passed up to the control socket.
72352885Sjulian * Unless they are for us specifically (socket_type)
72452419Sjulian */
72552419Sjulianstatic int
72652419Sjulianngs_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
72752419Sjulian	   struct ng_mesg **resp)
72852419Sjulian{
72952419Sjulian	struct ngsock *const sockdata = node->private;
73052419Sjulian	struct ngpcb *const pcbp = sockdata->ctlsock;
73152419Sjulian	struct sockaddr_ng *addr;
73252419Sjulian	int addrlen;
73352419Sjulian	int error = 0;
73452419Sjulian
73552419Sjulian	/* Only allow mesgs to be passed if we have the control socket.
73652419Sjulian	 * Data sockets can only support the generic messages. */
73752419Sjulian	if (pcbp == NULL) {
73852419Sjulian		TRAP_ERROR;
73952419Sjulian		return (EINVAL);
74052419Sjulian	}
74152419Sjulian
74252885Sjulian	if (msg->header.typecookie == NGM_SOCKET_COOKIE) {
74352885Sjulian		switch (msg->header.cmd) {
74452885Sjulian		case NGM_SOCK_CMD_NOLINGER:
74552885Sjulian			sockdata->flags |= NGS_FLAG_NOLINGER;
74652885Sjulian			break;
74752885Sjulian		case NGM_SOCK_CMD_LINGER:
74852885Sjulian			sockdata->flags &= ~NGS_FLAG_NOLINGER;
74952885Sjulian			break;
75052885Sjulian		default:
75152885Sjulian			error = EINVAL;		/* unknown command */
75252885Sjulian		}
75352885Sjulian		/* Free the message and return */
75452885Sjulian		FREE(msg, M_NETGRAPH);
75552885Sjulian		return(error);
75652885Sjulian
75752885Sjulian	}
75852419Sjulian	/* Get the return address into a sockaddr */
75952419Sjulian	if ((retaddr == NULL) || (*retaddr == '\0'))
76052419Sjulian		retaddr = "";
76152419Sjulian	addrlen = strlen(retaddr);
76252419Sjulian	MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH, M_NOWAIT);
76352419Sjulian	if (addr == NULL) {
76452419Sjulian		TRAP_ERROR;
76552419Sjulian		return (ENOMEM);
76652419Sjulian	}
76752419Sjulian	addr->sg_len = addrlen + 3;
76852419Sjulian	addr->sg_family = AF_NETGRAPH;
76952419Sjulian	bcopy(retaddr, addr->sg_data, addrlen);
77052419Sjulian	addr->sg_data[addrlen] = '\0';
77152419Sjulian
77252419Sjulian	/* Send it up */
77352419Sjulian	error = ship_msg(pcbp, msg, addr);
77452419Sjulian	FREE(addr, M_NETGRAPH);
77552419Sjulian	return (error);
77652419Sjulian}
77752419Sjulian
77852419Sjulian/*
77952419Sjulian * Receive data on a hook
78052419Sjulian */
78152419Sjulianstatic int
78252419Sjulianngs_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
78352419Sjulian{
78452419Sjulian	struct ngsock *const sockdata = hook->node->private;
78552419Sjulian	struct ngpcb *const pcbp = sockdata->datasock;
78652419Sjulian	struct socket *so;
78752419Sjulian	struct sockaddr_ng *addr;
78852419Sjulian	char *addrbuf[NG_HOOKLEN + 1 + 4];
78952419Sjulian	int addrlen;
79052419Sjulian
79152419Sjulian	/* If there is no data socket, black-hole it */
79252419Sjulian	if (pcbp == NULL) {
79352419Sjulian		NG_FREE_DATA(m, meta);
79452419Sjulian		return (0);
79552419Sjulian	}
79652419Sjulian	so = pcbp->ng_socket;
79752419Sjulian
79852419Sjulian	/* Get the return address into a sockaddr. */
79952419Sjulian	addrlen = strlen(hook->name);	/* <= NG_HOOKLEN */
80052419Sjulian	addr = (struct sockaddr_ng *) addrbuf;
80152419Sjulian	addr->sg_len = addrlen + 3;
80252419Sjulian	addr->sg_family = AF_NETGRAPH;
80352419Sjulian	bcopy(hook->name, addr->sg_data, addrlen);
80452419Sjulian	addr->sg_data[addrlen] = '\0';
80552419Sjulian
80652419Sjulian	/* We have no use for the meta data, free/clear it now. */
80752419Sjulian	NG_FREE_META(meta);
80852419Sjulian
80952419Sjulian	/* Try to tell the socket which hook it came in on */
81052419Sjulian	if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) {
81152419Sjulian		m_freem(m);
81252419Sjulian		TRAP_ERROR;
81352419Sjulian		return (ENOBUFS);
81452419Sjulian	}
81552419Sjulian	sorwakeup(so);
81652419Sjulian	return (0);
81752419Sjulian}
81852419Sjulian
81952419Sjulian/*
82052885Sjulian * Dook disconnection
82152885Sjulian *
82252885Sjulian * For this type, removal of the last link destroys the node
82352885Sjulian * if the NOLINGER flag is set.
82452885Sjulian */
82552885Sjulianstatic int
82652885Sjulianngs_disconnect(hook_p hook)
82752885Sjulian{
82852885Sjulian	struct ngsock *const sockdata = hook->node->private;
82952885Sjulian
83052885Sjulian	if ((sockdata->flags & NGS_FLAG_NOLINGER )
83152885Sjulian	&& (hook->node->numhooks == 0)) {
83252885Sjulian		ng_rmnode(hook->node);
83352885Sjulian	}
83452885Sjulian	return (0);
83552885Sjulian}
83652885Sjulian
83752885Sjulian/*
83852419Sjulian * Do local shutdown processing.
83952419Sjulian * In this case, that involves making sure the socket
84052419Sjulian * knows we should be shutting down.
84152419Sjulian */
84252419Sjulianstatic int
84352419Sjulianngs_rmnode(node_p node)
84452419Sjulian{
84552419Sjulian	struct ngsock *const sockdata = node->private;
84652419Sjulian	struct ngpcb *const dpcbp = sockdata->datasock;
84752419Sjulian	struct ngpcb *const pcbp = sockdata->ctlsock;
84852419Sjulian
84952419Sjulian	ng_cutlinks(node);
85052419Sjulian	ng_unname(node);
85152419Sjulian
85252419Sjulian	if (dpcbp != NULL) {
85352419Sjulian		soisdisconnected(dpcbp->ng_socket);
85452419Sjulian		dpcbp->sockdata = NULL;
85552419Sjulian		sockdata->datasock = NULL;
85652419Sjulian		sockdata->refs--;
85752419Sjulian	}
85852419Sjulian	if (pcbp != NULL) {
85952419Sjulian		soisdisconnected(pcbp->ng_socket);
86052419Sjulian		pcbp->sockdata = NULL;
86152419Sjulian		sockdata->ctlsock = NULL;
86252419Sjulian		sockdata->refs--;
86352419Sjulian	}
86452419Sjulian	node->private = NULL;
86552419Sjulian	ng_unref(node);
86652419Sjulian	FREE(sockdata, M_NETGRAPH);
86752419Sjulian	return (0);
86852419Sjulian}
86952419Sjulian
87052419Sjulian/*
87152419Sjulian * Control and data socket type descriptors
87252419Sjulian */
87352419Sjulian
87452419Sjulianstatic struct pr_usrreqs ngc_usrreqs = {
87552419Sjulian	NULL,			/* abort */
87652419Sjulian	pru_accept_notsupp,
87752419Sjulian	ngc_attach,
87852419Sjulian	ngc_bind,
87952419Sjulian	ngc_connect,
88052419Sjulian	pru_connect2_notsupp,
88152419Sjulian	pru_control_notsupp,
88252419Sjulian	ngc_detach,
88352419Sjulian	NULL,			/* disconnect */
88452419Sjulian	pru_listen_notsupp,
88552419Sjulian	NULL,			/* setpeeraddr */
88652419Sjulian	pru_rcvd_notsupp,
88752419Sjulian	pru_rcvoob_notsupp,
88852419Sjulian	ngc_send,
88952419Sjulian	pru_sense_null,
89052419Sjulian	NULL,			/* shutdown */
89152419Sjulian	ng_setsockaddr,
89252419Sjulian	sosend,
89352419Sjulian	soreceive,
89452419Sjulian	sopoll
89552419Sjulian};
89652419Sjulian
89752419Sjulianstatic struct pr_usrreqs ngd_usrreqs = {
89852419Sjulian	NULL,			/* abort */
89952419Sjulian	pru_accept_notsupp,
90052419Sjulian	ngd_attach,
90152419Sjulian	NULL,			/* bind */
90252419Sjulian	ngd_connect,
90352419Sjulian	pru_connect2_notsupp,
90452419Sjulian	pru_control_notsupp,
90552419Sjulian	ngd_detach,
90652419Sjulian	NULL,			/* disconnect */
90752419Sjulian	pru_listen_notsupp,
90852419Sjulian	NULL,			/* setpeeraddr */
90952419Sjulian	pru_rcvd_notsupp,
91052419Sjulian	pru_rcvoob_notsupp,
91152419Sjulian	ngd_send,
91252419Sjulian	pru_sense_null,
91352419Sjulian	NULL,			/* shutdown */
91452419Sjulian	ng_setsockaddr,
91552419Sjulian	sosend,
91652419Sjulian	soreceive,
91752419Sjulian	sopoll
91852419Sjulian};
91952419Sjulian
92052419Sjulian/*
92152419Sjulian * Definitions of protocols supported in the NETGRAPH domain.
92252419Sjulian */
92352419Sjulian
92452419Sjulianextern struct domain ngdomain;		/* stop compiler warnings */
92552419Sjulian
92652419Sjulianstatic struct protosw ngsw[] = {
92752419Sjulian	{
92852419Sjulian		SOCK_DGRAM,
92952419Sjulian		&ngdomain,
93052419Sjulian		NG_CONTROL,
93152419Sjulian		PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,
93252419Sjulian		0, 0, 0, 0,
93352419Sjulian		NULL,
93452419Sjulian		0, 0, 0, 0,
93552419Sjulian		&ngc_usrreqs
93652419Sjulian	},
93752419Sjulian	{
93852419Sjulian		SOCK_DGRAM,
93952419Sjulian		&ngdomain,
94052419Sjulian		NG_DATA,
94152419Sjulian		PR_ATOMIC | PR_ADDR,
94252419Sjulian		0, 0, 0, 0,
94352419Sjulian		NULL,
94452419Sjulian		0, 0, 0, 0,
94552419Sjulian		&ngd_usrreqs
94652419Sjulian	}
94752419Sjulian};
94852419Sjulian
94952419Sjulianstruct domain ngdomain = {
95052419Sjulian	AF_NETGRAPH,
95152419Sjulian	"netgraph",
95252419Sjulian	0,
95352419Sjulian	NULL,
95452419Sjulian	NULL,
95552419Sjulian	ngsw,
95652419Sjulian	&ngsw[sizeof(ngsw) / sizeof(ngsw[0])],
95752419Sjulian	0,
95852419Sjulian	NULL,
95952419Sjulian	0,
96052419Sjulian	0
96152419Sjulian};
96252419Sjulian
96352419Sjulian/*
96452419Sjulian * Handle loading and unloading for this node type
96552419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition).
96652419Sjulian */
96752419Sjulianstatic int
96852419Sjulianngs_mod_event(module_t mod, int event, void *data)
96952419Sjulian{
97052419Sjulian	int error = 0;
97152419Sjulian
97252419Sjulian	switch (event) {
97352419Sjulian	case MOD_LOAD:
97452419Sjulian		/* Register protocol domain */
97552419Sjulian		net_add_domain(&ngdomain);
97652419Sjulian		break;
97752419Sjulian	case MOD_UNLOAD:
97852419Sjulian		/* Insure there are no open netgraph sockets */
97952419Sjulian		if (!LIST_EMPTY(&ngsocklist)) {
98052419Sjulian			error = EBUSY;
98152419Sjulian			break;
98252419Sjulian		}
98352419Sjulian
98452419Sjulian#ifdef NOTYET
98552419Sjulian		/* Unregister protocol domain XXX can't do this yet.. */
98652419Sjulian		if ((error = net_rm_domain(&ngdomain)) != 0)
98752419Sjulian			break;
98852419Sjulian#else
98952419Sjulian		error = EBUSY;
99052419Sjulian#endif
99152419Sjulian		break;
99252419Sjulian	default:
99352419Sjulian		error = EOPNOTSUPP;
99452419Sjulian		break;
99552419Sjulian	}
99652419Sjulian	return (error);
99752419Sjulian}
99852419Sjulian
99952419SjulianSYSCTL_NODE(_net, AF_NETGRAPH, graph, CTLFLAG_RW, 0, "netgraph Family");
100052419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, "");
100152419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA");
100252419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, "");
100352419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL");
100452419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, "");
100552419Sjulian
1006