ng_socket.c revision 102244
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 102244 2002-08-22 00:30:03Z archie $
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/domain.h>
5352419Sjulian#include <sys/errno.h>
5452419Sjulian#include <sys/kernel.h>
5595759Stanimura#include <sys/lock.h>
5652419Sjulian#include <sys/malloc.h>
5752419Sjulian#include <sys/mbuf.h>
5852419Sjulian#include <sys/protosw.h>
5995759Stanimura#include <sys/queue.h>
6095759Stanimura#include <sys/signalvar.h>
6152419Sjulian#include <sys/socket.h>
6252419Sjulian#include <sys/socketvar.h>
6395759Stanimura#include <sys/sx.h>
6452419Sjulian#include <sys/sysctl.h>
6595759Stanimura#include <sys/systm.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
7470870Sjulian#ifdef NG_SEPARATE_MALLOC
7570870SjulianMALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info ");
7670870SjulianMALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info ");
7770870Sjulian#else
7870870Sjulian#define M_NETGRAPH_PATH M_NETGRAPH
7970870Sjulian#define M_NETGRAPH_SOCK M_NETGRAPH
8070870Sjulian#endif
8170870Sjulian
8252419Sjulian/*
8352419Sjulian * It's Ascii-art time!
8452419Sjulian *   +-------------+   +-------------+
8552419Sjulian *   |socket  (ctl)|   |socket (data)|
8652419Sjulian *   +-------------+   +-------------+
8752419Sjulian *          ^                 ^
8852419Sjulian *          |                 |
8952419Sjulian *          v                 v
9052419Sjulian *    +-----------+     +-----------+
9152419Sjulian *    |pcb   (ctl)|     |pcb  (data)|
9252419Sjulian *    +-----------+     +-----------+
9352419Sjulian *          ^                 ^
9452419Sjulian *          |                 |
9552419Sjulian *          v                 v
9652419Sjulian *      +--------------------------+
9752419Sjulian *      |   Socket type private    |
9852419Sjulian *      |       data               |
9952419Sjulian *      +--------------------------+
10052419Sjulian *                   ^
10152419Sjulian *                   |
10252419Sjulian *                   v
10352419Sjulian *           +----------------+
10452419Sjulian *           | struct ng_node |
10552419Sjulian *           +----------------+
10652419Sjulian */
10752419Sjulian
10852419Sjulian/* Netgraph node methods */
10952752Sjulianstatic ng_constructor_t	ngs_constructor;
11052752Sjulianstatic ng_rcvmsg_t	ngs_rcvmsg;
11170700Sjulianstatic ng_shutdown_t	ngs_shutdown;
11252752Sjulianstatic ng_newhook_t	ngs_newhook;
11372053Sjulianstatic ng_connect_t	ngs_connect;
11452752Sjulianstatic ng_rcvdata_t	ngs_rcvdata;
11552885Sjulianstatic ng_disconnect_t	ngs_disconnect;
11652419Sjulian
11752419Sjulian/* Internal methods */
11852419Sjulianstatic int	ng_attach_data(struct socket *so);
11952419Sjulianstatic int	ng_attach_cntl(struct socket *so);
12052419Sjulianstatic int	ng_attach_common(struct socket *so, int type);
12152419Sjulianstatic void	ng_detach_common(struct ngpcb *pcbp, int type);
12283366Sjulian/*static int	ng_internalize(struct mbuf *m, struct thread *p); */
12352419Sjulian
12452419Sjulianstatic int	ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
12552419Sjulianstatic int	ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
12652419Sjulian
12752419Sjulianstatic int	ngs_mod_event(module_t mod, int event, void *data);
12852419Sjulianstatic int	ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg,
12952419Sjulian			struct sockaddr_ng *addr);
13052419Sjulian
13152419Sjulian/* Netgraph type descriptor */
13252419Sjulianstatic struct ng_type typestruct = {
13370159Sjulian	NG_ABI_VERSION,
13452419Sjulian	NG_SOCKET_NODE_TYPE,
13552419Sjulian	ngs_mod_event,
13652419Sjulian	ngs_constructor,
13752419Sjulian	ngs_rcvmsg,
13870700Sjulian	ngs_shutdown,
13952419Sjulian	ngs_newhook,
14052419Sjulian	NULL,
14172053Sjulian	ngs_connect,
14252419Sjulian	ngs_rcvdata,
14353913Sarchie	ngs_disconnect,
14453913Sarchie	NULL
14552419Sjulian};
14652419SjulianNETGRAPH_INIT(socket, &typestruct);
14752419Sjulian
14852419Sjulian/* Buffer space */
14964512Sarchiestatic u_long ngpdg_sendspace = 20 * 1024;	/* really max datagram size */
15052419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024;
15152419Sjulian
15252419Sjulian/* List of all sockets */
15389066Smsmithstatic LIST_HEAD(, ngpcb) ngsocklist;
15452419Sjulian
15553526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb)
15652419Sjulian
15752419Sjulian/* If getting unexplained errors returned, set this to "Debugger("X"); */
15852419Sjulian#ifndef TRAP_ERROR
15952419Sjulian#define TRAP_ERROR
16052419Sjulian#endif
16152419Sjulian
16252419Sjulian/***************************************************************
16352419Sjulian	Control sockets
16452419Sjulian***************************************************************/
16552419Sjulian
16652419Sjulianstatic int
16783366Sjulianngc_attach(struct socket *so, int proto, struct thread *td)
16852419Sjulian{
16952419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
17052419Sjulian
17193593Sjhb	if (suser(td))
17253530Sjulian		return (EPERM);
17352419Sjulian	if (pcbp != NULL)
17452419Sjulian		return (EISCONN);
17552419Sjulian	return (ng_attach_cntl(so));
17652419Sjulian}
17752419Sjulian
17852419Sjulianstatic int
17952419Sjulianngc_detach(struct socket *so)
18052419Sjulian{
18152419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
18252419Sjulian
18352419Sjulian	if (pcbp == NULL)
18452419Sjulian		return (EINVAL);
18552419Sjulian	ng_detach_common(pcbp, NG_CONTROL);
18652419Sjulian	return (0);
18752419Sjulian}
18852419Sjulian
18952419Sjulianstatic int
19052419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
19183366Sjulian	 struct mbuf *control, struct thread *td)
19252419Sjulian{
19352419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
19452419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
19570700Sjulian	struct ng_mesg *msg;
19652419Sjulian	struct mbuf *m0;
19770700Sjulian	char *path = NULL;
19852419Sjulian	int len, error = 0;
19952419Sjulian
20052419Sjulian	if (pcbp == NULL) {
20152419Sjulian		error = EINVAL;
20252419Sjulian		goto release;
20352419Sjulian	}
20452419Sjulian#ifdef	NOTYET
20583366Sjulian	if (control && (error = ng_internalize(control, td))) {
20652419Sjulian		if (pcbp->sockdata == NULL) {
20752419Sjulian			error = ENOTCONN;
20852419Sjulian			goto release;
20952419Sjulian		}
21052419Sjulian	}
21152419Sjulian#else	/* NOTYET */
21252419Sjulian	if (control) {
21352419Sjulian		error = EINVAL;
21452419Sjulian		goto release;
21552419Sjulian	}
21652419Sjulian#endif	/* NOTYET */
21752419Sjulian
21852419Sjulian	/* Require destination as there may be >= 1 hooks on this node */
21952419Sjulian	if (addr == NULL) {
22052419Sjulian		error = EDESTADDRREQ;
22152419Sjulian		goto release;
22252419Sjulian	}
22352419Sjulian
22452419Sjulian	/* Allocate an expendable buffer for the path, chop off
22552419Sjulian	 * the sockaddr header, and make sure it's NUL terminated */
22652419Sjulian	len = sap->sg_len - 2;
22770870Sjulian	MALLOC(path, char *, len + 1, M_NETGRAPH_PATH, M_WAITOK);
22852419Sjulian	if (path == NULL) {
22952419Sjulian		error = ENOMEM;
23052419Sjulian		goto release;
23152419Sjulian	}
23252419Sjulian	bcopy(sap->sg_data, path, len);
23352419Sjulian	path[len] = '\0';
23452419Sjulian
23552419Sjulian	/* Move the actual message out of mbufs into a linear buffer.
23652419Sjulian	 * Start by adding up the size of the data. (could use mh_len?) */
23752419Sjulian	for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
23852419Sjulian		len += m0->m_len;
23952419Sjulian
24052419Sjulian	/* Move the data into a linear buffer as well. Messages are not
24152419Sjulian	 * delivered in mbufs. */
24270700Sjulian	MALLOC(msg, struct ng_mesg *, len + 1, M_NETGRAPH_MSG, M_WAITOK);
24352419Sjulian	if (msg == NULL) {
24452419Sjulian		error = ENOMEM;
24552419Sjulian		goto release;
24652419Sjulian	}
24770700Sjulian	m_copydata(m, 0, len, (char *)msg);
24852419Sjulian
24970784Sjulian#ifdef TRACE_MESSAGES
25070784Sjulian	do {
25170784Sjulian		item_p item;
25270784Sjulian		if ((item = ng_package_msg(msg)) == NULL) {
25370784Sjulian			(msg) = NULL;
25470784Sjulian			(error) = ENOMEM;
25570784Sjulianprintf("err=%d\n",error);
25670784Sjulian			break;
25770784Sjulian		}
25870784Sjulian		if (((error) = ng_address_path((pcbp->sockdata->node), (item),
25970784Sjulian					(path), (NULL))) == 0) {
26070784Sjulianprintf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n",
26170784Sjulianitem->el_dest->nd_ID,
26270784Sjulianmsg->header.typecookie,
26370784Sjulianmsg->header.cmd,
26470784Sjulianmsg->header.cmdstr,
26570784Sjulianmsg->header.flags,
26670784Sjulianmsg->header.token,
26770784Sjulianitem->el_dest->nd_type->name);
26870784Sjulian			SAVE_LINE(item);
26970784Sjulian			(error) = ng_snd_item((item), 0);
27070784Sjulian		}
27170784Sjulianelse {
27270784Sjulianprintf("errx=%d\n",error);
27370784Sjulian}
27470784Sjulian		(msg) = NULL;
27570784Sjulian	} while (0);
27670784Sjulian
27770784Sjulian#else
27870700Sjulian	/* The callee will free the msg when done. The path is our business. */
279102244Sarchie	NG_SEND_MSG_PATH(error, pcbp->sockdata->node, msg, path, 0);
28070784Sjulian#endif
28152419Sjulianrelease:
28252419Sjulian	if (path != NULL)
28370870Sjulian		FREE(path, M_NETGRAPH_PATH);
28452419Sjulian	if (control != NULL)
28552419Sjulian		m_freem(control);
28652419Sjulian	if (m != NULL)
28752419Sjulian		m_freem(m);
28852419Sjulian	return (error);
28952419Sjulian}
29052419Sjulian
29152419Sjulianstatic int
29283366Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
29352419Sjulian{
29452419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
29552419Sjulian
29652419Sjulian	if (pcbp == 0)
29752419Sjulian		return (EINVAL);
29852419Sjulian	return (ng_bind(nam, pcbp));
29952419Sjulian}
30052419Sjulian
30152419Sjulianstatic int
30283366Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
30352419Sjulian{
30470784Sjulianprintf(" program tried to connect control socket to remote node\n ");
30570700Sjulian	/*
30670784Sjulian	 * At this time refuse to do this.. it used to
30770700Sjulian	 * do something but it was undocumented and not used.
30870700Sjulian	 */
30970700Sjulian	return (EINVAL);
31052419Sjulian}
31152419Sjulian
31252419Sjulian/***************************************************************
31352419Sjulian	Data sockets
31452419Sjulian***************************************************************/
31552419Sjulian
31652419Sjulianstatic int
31783366Sjulianngd_attach(struct socket *so, int proto, struct thread *td)
31852419Sjulian{
31952419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
32052419Sjulian
32152419Sjulian	if (pcbp != NULL)
32252419Sjulian		return (EISCONN);
32352419Sjulian	return (ng_attach_data(so));
32452419Sjulian}
32552419Sjulian
32652419Sjulianstatic int
32752419Sjulianngd_detach(struct socket *so)
32852419Sjulian{
32952419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
33052419Sjulian
33152419Sjulian	if (pcbp == NULL)
33252419Sjulian		return (EINVAL);
33352419Sjulian	ng_detach_common(pcbp, NG_DATA);
33452419Sjulian	return (0);
33552419Sjulian}
33652419Sjulian
33752419Sjulianstatic int
33852419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
33983366Sjulian	 struct mbuf *control, struct thread *td)
34052419Sjulian{
34152419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
34252419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
34352419Sjulian	int     len, error;
34453498Sjulian	hook_p  hook = NULL;
34553498Sjulian	char	hookname[NG_HOOKLEN + 1];
34652419Sjulian
34752419Sjulian	if ((pcbp == NULL) || (control != NULL)) {
34852419Sjulian		error = EINVAL;
34952419Sjulian		goto release;
35052419Sjulian	}
35152419Sjulian	if (pcbp->sockdata == NULL) {
35252419Sjulian		error = ENOTCONN;
35352419Sjulian		goto release;
35452419Sjulian	}
35553498Sjulian	/*
35653498Sjulian	 * If the user used any of these ways to not specify an address
35753498Sjulian	 * then handle specially.
35853498Sjulian	 */
35953498Sjulian	if ((sap == NULL)
36084777Sarchie	    || ((len = sap->sg_len - 2) <= 0)
36184777Sarchie	    || (*sap->sg_data == '\0')) {
36270784Sjulian		if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) {
36353498Sjulian			error = EDESTADDRREQ;
36453498Sjulian			goto release;
36553498Sjulian		}
36653498Sjulian		/*
36753498Sjulian		 * if exactly one hook exists, just use it.
36853498Sjulian		 * Special case to allow write(2) to work on an ng_socket.
36953498Sjulian		 */
37070784Sjulian		hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks);
37153498Sjulian	} else {
37253498Sjulian		if (len > NG_HOOKLEN) {
37353498Sjulian			error = EINVAL;
37453498Sjulian			goto release;
37553498Sjulian		}
37652419Sjulian
37753498Sjulian		/*
37853498Sjulian		 * chop off the sockaddr header, and make sure it's NUL
37953498Sjulian		 * terminated
38053498Sjulian		 */
38153498Sjulian		bcopy(sap->sg_data, hookname, len);
38253498Sjulian		hookname[len] = '\0';
38352419Sjulian
38453498Sjulian		/* Find the correct hook from 'hookname' */
38570784Sjulian		LIST_FOREACH(hook, &pcbp->sockdata->node->nd_hooks, hk_hooks) {
38672053Sjulian			if (strcmp(hookname, NG_HOOK_NAME(hook)) == 0) {
38753498Sjulian				break;
38872053Sjulian			}
38953498Sjulian		}
39072053Sjulian		if (hook == NULL) {
39153498Sjulian			error = EHOSTUNREACH;
39272053Sjulian		}
39352419Sjulian	}
39452419Sjulian
39552419Sjulian	/* Send data (OK if hook is NULL) */
39669922Sjulian	NG_SEND_DATA_ONLY(error, hook, m);	/* makes m NULL */
39752419Sjulian
39852419Sjulianrelease:
39952419Sjulian	if (control != NULL)
40052419Sjulian		m_freem(control);
40152419Sjulian	if (m != NULL)
40252419Sjulian		m_freem(m);
40352419Sjulian	return (error);
40452419Sjulian}
40552419Sjulian
40652419Sjulianstatic int
40783366Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
40852419Sjulian{
40952419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
41052419Sjulian
41152419Sjulian	if (pcbp == 0)
41252419Sjulian		return (EINVAL);
41352419Sjulian	return (ng_connect_data(nam, pcbp));
41452419Sjulian}
41552419Sjulian
41652419Sjulian/*
41752419Sjulian * Used for both data and control sockets
41852419Sjulian */
41952419Sjulianstatic int
42052419Sjulianng_setsockaddr(struct socket *so, struct sockaddr **addr)
42152419Sjulian{
42253098Sbrian	struct ngpcb *pcbp;
42353098Sbrian	struct sockaddr_ng *sg;
42453098Sbrian	int sg_len, namelen, s;
42552419Sjulian
42653098Sbrian	/* Why isn't sg_data a `char[1]' ? :-( */
42753098Sbrian	sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1;
42853098Sbrian
42953098Sbrian	s = splnet();
43053098Sbrian	pcbp = sotongpcb(so);
43169922Sjulian	if ((pcbp == NULL) || (pcbp->sockdata == NULL)) {
43253098Sbrian		splx(s);
43352419Sjulian		return (EINVAL);
43453098Sbrian	}
43553098Sbrian
43653098Sbrian	namelen = 0;		/* silence compiler ! */
43770784Sjulian	if ( NG_NODE_HAS_NAME(pcbp->sockdata->node))
43870784Sjulian		sg_len += namelen = strlen(NG_NODE_NAME(pcbp->sockdata->node));
43953098Sbrian
44068876Sdwmalone	MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK | M_ZERO);
44153098Sbrian
44270784Sjulian	if (NG_NODE_HAS_NAME(pcbp->sockdata->node))
44370784Sjulian		bcopy(NG_NODE_NAME(pcbp->sockdata->node), sg->sg_data, namelen);
44453098Sbrian	splx(s);
44553098Sbrian
44653098Sbrian	sg->sg_len = sg_len;
44753098Sbrian	sg->sg_family = AF_NETGRAPH;
44853098Sbrian	*addr = (struct sockaddr *)sg;
44953098Sbrian
45052419Sjulian	return (0);
45152419Sjulian}
45252419Sjulian
45352419Sjulian/*
45452419Sjulian * Attach a socket to it's protocol specific partner.
45552419Sjulian * For a control socket, actually create a netgraph node and attach
45652419Sjulian * to it as well.
45752419Sjulian */
45852419Sjulian
45952419Sjulianstatic int
46052419Sjulianng_attach_cntl(struct socket *so)
46152419Sjulian{
46252419Sjulian	struct ngsock *privdata;
46352419Sjulian	struct ngpcb *pcbp;
46452419Sjulian	int error;
46552419Sjulian
46652419Sjulian	/* Setup protocol control block */
46752419Sjulian	if ((error = ng_attach_common(so, NG_CONTROL)) != 0)
46852419Sjulian		return (error);
46953526Sjulian	pcbp = sotongpcb(so);
47052419Sjulian
47152419Sjulian	/* Allocate node private info */
47252419Sjulian	MALLOC(privdata, struct ngsock *,
47370870Sjulian	    sizeof(*privdata), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO);
47452419Sjulian	if (privdata == NULL) {
47552419Sjulian		ng_detach_common(pcbp, NG_CONTROL);
47652419Sjulian		return (ENOMEM);
47752419Sjulian	}
47852419Sjulian
47952419Sjulian	/* Make the generic node components */
48052419Sjulian	if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) {
48170870Sjulian		FREE(privdata, M_NETGRAPH_SOCK);
48252419Sjulian		ng_detach_common(pcbp, NG_CONTROL);
48352419Sjulian		return (error);
48452419Sjulian	}
48570784Sjulian	NG_NODE_SET_PRIVATE(privdata->node, privdata);
48652419Sjulian
48752419Sjulian	/* Link the pcb and the node private data */
48852419Sjulian	privdata->ctlsock = pcbp;
48952419Sjulian	pcbp->sockdata = privdata;
49052419Sjulian	privdata->refs++;
49152419Sjulian	return (0);
49252419Sjulian}
49352419Sjulian
49452419Sjulianstatic int
49552419Sjulianng_attach_data(struct socket *so)
49652419Sjulian{
49752419Sjulian	return(ng_attach_common(so, NG_DATA));
49852419Sjulian}
49952419Sjulian
50052419Sjulian/*
50152419Sjulian * Set up a socket protocol control block.
50252419Sjulian * This code is shared between control and data sockets.
50352419Sjulian */
50452419Sjulianstatic int
50552419Sjulianng_attach_common(struct socket *so, int type)
50652419Sjulian{
50752419Sjulian	struct ngpcb *pcbp;
50852419Sjulian	int error;
50952419Sjulian
51052419Sjulian	/* Standard socket setup stuff */
51152419Sjulian	error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
51252419Sjulian	if (error)
51352419Sjulian		return (error);
51452419Sjulian
51552419Sjulian	/* Allocate the pcb */
51668876Sdwmalone	MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK | M_ZERO);
51752419Sjulian	if (pcbp == NULL)
51852419Sjulian		return (ENOMEM);
51952419Sjulian	pcbp->type = type;
52052419Sjulian
52152419Sjulian	/* Link the pcb and the socket */
52252419Sjulian	so->so_pcb = (caddr_t) pcbp;
52352419Sjulian	pcbp->ng_socket = so;
52452419Sjulian
52552419Sjulian	/* Add the socket to linked list */
52652419Sjulian	LIST_INSERT_HEAD(&ngsocklist, pcbp, socks);
52752419Sjulian	return (0);
52852419Sjulian}
52952419Sjulian
53052419Sjulian/*
53152419Sjulian * Disassociate the socket from it's protocol specific
53252419Sjulian * partner. If it's attached to a node's private data structure,
53352419Sjulian * then unlink from that too. If we were the last socket attached to it,
53452419Sjulian * then shut down the entire node. Shared code for control and data sockets.
53552419Sjulian */
53652419Sjulianstatic void
53752419Sjulianng_detach_common(struct ngpcb *pcbp, int which)
53852419Sjulian{
53972053Sjulian	struct ngsock *priv;
54052419Sjulian
54152419Sjulian	if (pcbp->sockdata) {
54272053Sjulian		priv = pcbp->sockdata;
54352419Sjulian		pcbp->sockdata = NULL;
54452419Sjulian		switch (which) {
54552419Sjulian		case NG_CONTROL:
54672053Sjulian			priv->ctlsock = NULL;
54752419Sjulian			break;
54852419Sjulian		case NG_DATA:
54972053Sjulian			priv->datasock = NULL;
55052419Sjulian			break;
55152419Sjulian		default:
55287599Sobrien			panic(__func__);
55352419Sjulian		}
55472053Sjulian		if ((--priv->refs == 0) && (priv->node != NULL))
55572053Sjulian			ng_rmnode_self(priv->node);
55652419Sjulian	}
55752419Sjulian	pcbp->ng_socket->so_pcb = NULL;
55852419Sjulian	pcbp->ng_socket = NULL;
55952419Sjulian	LIST_REMOVE(pcbp, socks);
56052419Sjulian	FREE(pcbp, M_PCB);
56152419Sjulian}
56252419Sjulian
56352419Sjulian#ifdef NOTYET
56452419Sjulian/*
56552419Sjulian * File descriptors can be passed into a AF_NETGRAPH socket.
56652419Sjulian * Note, that file descriptors cannot be passed OUT.
56752419Sjulian * Only character device descriptors are accepted.
56852419Sjulian * Character devices are useful to connect a graph to a device,
56952419Sjulian * which after all is the purpose of this whole system.
57052419Sjulian */
57152419Sjulianstatic int
57283366Sjulianng_internalize(struct mbuf *control, struct thread *td)
57352419Sjulian{
57497897Sarchie	const struct cmsghdr *cm = mtod(control, const struct cmsghdr *);
57552419Sjulian	struct file *fp;
57652419Sjulian	struct vnode *vn;
57752419Sjulian	int oldfds;
57852419Sjulian	int fd;
57952419Sjulian
58052419Sjulian	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
58152419Sjulian	    cm->cmsg_len != control->m_len) {
58252419Sjulian		TRAP_ERROR;
58352419Sjulian		return (EINVAL);
58452419Sjulian	}
58552419Sjulian
58652419Sjulian	/* Check there is only one FD. XXX what would more than one signify? */
58784472Sdwmalone	oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int);
58852419Sjulian	if (oldfds != 1) {
58952419Sjulian		TRAP_ERROR;
59052419Sjulian		return (EINVAL);
59152419Sjulian	}
59252419Sjulian
59352419Sjulian	/* Check that the FD given is legit. and change it to a pointer to a
59452419Sjulian	 * struct file. */
59584472Sdwmalone	fd = CMSG_DATA(cm);
59689319Salfred	if ((error = fget(td, fd, &fp)) != 0)
59789319Salfred		return (error);
59852419Sjulian
59952419Sjulian	/* Depending on what kind of resource it is, act differently. For
60052419Sjulian	 * devices, we treat it as a file. For a AF_NETGRAPH socket,
60152419Sjulian	 * shortcut straight to the node. */
60252419Sjulian	switch (fp->f_type) {
60352419Sjulian	case DTYPE_VNODE:
60452419Sjulian		vn = (struct vnode *) fp->f_data;
60552419Sjulian		if (vn && (vn->v_type == VCHR)) {
60652419Sjulian			/* for a VCHR, actually reference the FILE */
60752419Sjulian			fp->f_count++;
60852419Sjulian			/* XXX then what :) */
60952419Sjulian			/* how to pass on to other modules? */
61052419Sjulian		} else {
61189306Salfred			fdrop(fp, td);
61252419Sjulian			TRAP_ERROR;
61352419Sjulian			return (EINVAL);
61452419Sjulian		}
61552419Sjulian		break;
61652419Sjulian	default:
61789306Salfred		fdrop(fp, td);
61852419Sjulian		TRAP_ERROR;
61952419Sjulian		return (EINVAL);
62052419Sjulian	}
62189306Salfred	fdrop(fp, td);
62252419Sjulian	return (0);
62352419Sjulian}
62452419Sjulian#endif	/* NOTYET */
62552419Sjulian
62652419Sjulian/*
62752419Sjulian * Connect the data socket to a named control socket node.
62852419Sjulian */
62952419Sjulianstatic int
63052419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
63152419Sjulian{
63252419Sjulian	struct sockaddr_ng *sap;
63352419Sjulian	node_p farnode;
63472053Sjulian	struct ngsock *priv;
63552419Sjulian	int error;
63670700Sjulian	item_p item;
63752419Sjulian
63852419Sjulian	/* If we are already connected, don't do it again */
63952419Sjulian	if (pcbp->sockdata != NULL)
64052419Sjulian		return (EISCONN);
64152419Sjulian
64252419Sjulian	/* Find the target (victim) and check it doesn't already have a data
64370700Sjulian	 * socket. Also check it is a 'socket' type node.
64470700Sjulian	 * Use ng_package_data() and address_path() to do this.
64570700Sjulian	 */
64670700Sjulian
64752419Sjulian	sap = (struct sockaddr_ng *) nam;
64870700Sjulian	/* The item will hold the node reference */
64970700Sjulian	item = ng_package_data(NULL, NULL);
65070700Sjulian	if (item == NULL) {
65170700Sjulian		return (ENOMEM);
65270700Sjulian	}
653102244Sarchie	if ((error = ng_address_path(NULL, item,  sap->sg_data, 0)))
65470700Sjulian		return (error); /* item is freed on failure */
65552419Sjulian
65670700Sjulian	/*
65770784Sjulian	 * Extract node from item and free item. Remember we now have
65870700Sjulian	 * a reference on the node. The item holds it for us.
65970700Sjulian	 * when we free the item we release the reference.
66070700Sjulian	 */
66170700Sjulian	farnode = item->el_dest; /* shortcut */
66270784Sjulian	if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) {
66370700Sjulian		NG_FREE_ITEM(item); /* drop the reference to the node */
66452419Sjulian		return (EINVAL);
66570700Sjulian	}
66672053Sjulian	priv = NG_NODE_PRIVATE(farnode);
66772053Sjulian	if (priv->datasock != NULL) {
66870700Sjulian		NG_FREE_ITEM(item);	/* drop the reference to the node */
66952419Sjulian		return (EADDRINUSE);
67070700Sjulian	}
67152419Sjulian
67270700Sjulian	/*
67370700Sjulian	 * Link the PCB and the private data struct. and note the extra
67470700Sjulian	 * reference. Drop the extra reference on the node.
67570700Sjulian	 */
67672053Sjulian	priv->datasock = pcbp;
67772053Sjulian	pcbp->sockdata = priv;
67872053Sjulian	priv->refs++; /* XXX possible race if it's being freed */
67970700Sjulian	NG_FREE_ITEM(item);	/* drop the reference to the node */
68052419Sjulian	return (0);
68152419Sjulian}
68252419Sjulian
68352419Sjulian/*
68452419Sjulian * Binding a socket means giving the corresponding node a name
68552419Sjulian */
68652419Sjulianstatic int
68752419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
68852419Sjulian{
68972053Sjulian	struct ngsock *const priv = pcbp->sockdata;
69052419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
69152419Sjulian
69272053Sjulian	if (priv == NULL) {
69352419Sjulian		TRAP_ERROR;
69452419Sjulian		return (EINVAL);
69552419Sjulian	}
69669922Sjulian	if ((sap->sg_len < 4)
69769922Sjulian	||  (sap->sg_len > (NG_NODELEN + 3))
69869922Sjulian	||  (sap->sg_data[0] == '\0')
69969922Sjulian	||  (sap->sg_data[sap->sg_len - 3] != '\0')) {
70052419Sjulian		TRAP_ERROR;
70152419Sjulian		return (EINVAL);
70252419Sjulian	}
70372053Sjulian	return (ng_name_node(priv->node, sap->sg_data));
70452419Sjulian}
70552419Sjulian
70652419Sjulian/*
70752419Sjulian * Take a message and pass it up to the control socket associated
70852419Sjulian * with the node.
70952419Sjulian */
71052419Sjulianstatic int
71152419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr)
71252419Sjulian{
71352419Sjulian	struct socket *const so = pcbp->ng_socket;
71452419Sjulian	struct mbuf *mdata;
71552419Sjulian	int msglen;
71652419Sjulian
71752419Sjulian	/* Copy the message itself into an mbuf chain */
71852419Sjulian	msglen = sizeof(struct ng_mesg) + msg->header.arglen;
71952419Sjulian	mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL);
72052419Sjulian
72152419Sjulian	/* Here we free the message, as we are the end of the line.
72252419Sjulian	 * We need to do that regardless of whether we got mbufs. */
72370700Sjulian	NG_FREE_MSG(msg);
72452419Sjulian
72552419Sjulian	if (mdata == NULL) {
72652419Sjulian		TRAP_ERROR;
72752419Sjulian		return (ENOBUFS);
72852419Sjulian	}
72952419Sjulian
73052419Sjulian	/* Send it up to the socket */
73152419Sjulian	if (sbappendaddr(&so->so_rcv,
73252419Sjulian	    (struct sockaddr *) addr, mdata, NULL) == 0) {
73352419Sjulian		TRAP_ERROR;
73452419Sjulian		m_freem(mdata);
73552419Sjulian		return (ENOBUFS);
73652419Sjulian	}
73752419Sjulian	sorwakeup(so);
73852419Sjulian	return (0);
73952419Sjulian}
74052419Sjulian
74152419Sjulian/*
74252419Sjulian * You can only create new nodes from the socket end of things.
74352419Sjulian */
74452419Sjulianstatic int
74570700Sjulianngs_constructor(node_p nodep)
74652419Sjulian{
74752419Sjulian	return (EINVAL);
74852419Sjulian}
74952419Sjulian
75052419Sjulian/*
75152419Sjulian * We allow any hook to be connected to the node.
75252419Sjulian * There is no per-hook private information though.
75352419Sjulian */
75452419Sjulianstatic int
75552419Sjulianngs_newhook(node_p node, hook_p hook, const char *name)
75652419Sjulian{
75770784Sjulian	NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node));
75852419Sjulian	return (0);
75952419Sjulian}
76052419Sjulian
76172053Sjulian/*
76272053Sjulian * if only one hook, allow read(2) and write(2) to work.
76372053Sjulian */
76472053Sjulianstatic int
76572053Sjulianngs_connect(hook_p hook)
76672053Sjulian{
76772053Sjulian	node_p node = NG_HOOK_NODE(hook);
76872053Sjulian	struct ngsock *priv = NG_NODE_PRIVATE(node);
76972053Sjulian
77072053Sjulian	if ((priv->datasock)
77172053Sjulian	&&  (priv->datasock->ng_socket)) {
77272053Sjulian		if (NG_NODE_NUMHOOKS(node) == 1) {
77372053Sjulian			priv->datasock->ng_socket->so_state |= SS_ISCONNECTED;
77472053Sjulian		} else {
77572053Sjulian			priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED;
77672053Sjulian		}
77772053Sjulian	}
77872053Sjulian	return (0);
77972053Sjulian}
78072053Sjulian
78152419Sjulian/*
78252419Sjulian * Incoming messages get passed up to the control socket.
78352885Sjulian * Unless they are for us specifically (socket_type)
78452419Sjulian */
78552419Sjulianstatic int
78670700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook)
78752419Sjulian{
78872053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
78972053Sjulian	struct ngpcb *const pcbp = priv->ctlsock;
79052419Sjulian	struct sockaddr_ng *addr;
79152419Sjulian	int addrlen;
79252419Sjulian	int error = 0;
79370700Sjulian	struct	ng_mesg *msg;
79470700Sjulian	ng_ID_t	retaddr = NGI_RETADDR(item);
79570700Sjulian	char	retabuf[32];
79652419Sjulian
79770700Sjulian	NGI_GET_MSG(item, msg);
79870700Sjulian	NG_FREE_ITEM(item); /* we have all we need */
79970700Sjulian
80052419Sjulian	/* Only allow mesgs to be passed if we have the control socket.
80152419Sjulian	 * Data sockets can only support the generic messages. */
80252419Sjulian	if (pcbp == NULL) {
80352419Sjulian		TRAP_ERROR;
80452419Sjulian		return (EINVAL);
80552419Sjulian	}
80670784Sjulian#ifdef TRACE_MESSAGES
80770784Sjulianprintf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n",
80870784Sjulianretaddr,
80970784Sjulianmsg->header.typecookie,
81070784Sjulianmsg->header.cmd,
81170784Sjulianmsg->header.cmdstr,
81270784Sjulianmsg->header.flags,
81370784Sjulianmsg->header.token);
81452419Sjulian
81570784Sjulian#endif
81670784Sjulian
81752885Sjulian	if (msg->header.typecookie == NGM_SOCKET_COOKIE) {
81852885Sjulian		switch (msg->header.cmd) {
81952885Sjulian		case NGM_SOCK_CMD_NOLINGER:
82072053Sjulian			priv->flags |= NGS_FLAG_NOLINGER;
82152885Sjulian			break;
82252885Sjulian		case NGM_SOCK_CMD_LINGER:
82372053Sjulian			priv->flags &= ~NGS_FLAG_NOLINGER;
82452885Sjulian			break;
82552885Sjulian		default:
82652885Sjulian			error = EINVAL;		/* unknown command */
82752885Sjulian		}
82852885Sjulian		/* Free the message and return */
82970700Sjulian		NG_FREE_MSG(msg);
83052885Sjulian		return(error);
83152885Sjulian
83252885Sjulian	}
83352419Sjulian	/* Get the return address into a sockaddr */
83470700Sjulian	sprintf(retabuf,"[%x]:", retaddr);
83570700Sjulian	addrlen = strlen(retabuf);
83670870Sjulian	MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH_PATH, M_NOWAIT);
83752419Sjulian	if (addr == NULL) {
83852419Sjulian		TRAP_ERROR;
83952419Sjulian		return (ENOMEM);
84052419Sjulian	}
84152419Sjulian	addr->sg_len = addrlen + 3;
84252419Sjulian	addr->sg_family = AF_NETGRAPH;
84370700Sjulian	bcopy(retabuf, addr->sg_data, addrlen);
84452419Sjulian	addr->sg_data[addrlen] = '\0';
84552419Sjulian
84652419Sjulian	/* Send it up */
84752419Sjulian	error = ship_msg(pcbp, msg, addr);
84870870Sjulian	FREE(addr, M_NETGRAPH_PATH);
84952419Sjulian	return (error);
85052419Sjulian}
85152419Sjulian
85252419Sjulian/*
85352419Sjulian * Receive data on a hook
85452419Sjulian */
85552419Sjulianstatic int
85670700Sjulianngs_rcvdata(hook_p hook, item_p item)
85752419Sjulian{
85872053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
85972053Sjulian	struct ngpcb *const pcbp = priv->datasock;
86052419Sjulian	struct socket *so;
86152419Sjulian	struct sockaddr_ng *addr;
86252419Sjulian	char *addrbuf[NG_HOOKLEN + 1 + 4];
86352419Sjulian	int addrlen;
86470700Sjulian	struct mbuf *m;
86552419Sjulian
86670700Sjulian	NGI_GET_M(item, m);
86770700Sjulian	NG_FREE_ITEM(item);
86852419Sjulian	/* If there is no data socket, black-hole it */
86952419Sjulian	if (pcbp == NULL) {
87070700Sjulian		NG_FREE_M(m);
87152419Sjulian		return (0);
87252419Sjulian	}
87352419Sjulian	so = pcbp->ng_socket;
87452419Sjulian
87552419Sjulian	/* Get the return address into a sockaddr. */
87670784Sjulian	addrlen = strlen(NG_HOOK_NAME(hook));	/* <= NG_HOOKLEN */
87752419Sjulian	addr = (struct sockaddr_ng *) addrbuf;
87852419Sjulian	addr->sg_len = addrlen + 3;
87952419Sjulian	addr->sg_family = AF_NETGRAPH;
88070784Sjulian	bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen);
88152419Sjulian	addr->sg_data[addrlen] = '\0';
88252419Sjulian
88352419Sjulian	/* Try to tell the socket which hook it came in on */
88452419Sjulian	if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) {
88552419Sjulian		m_freem(m);
88652419Sjulian		TRAP_ERROR;
88752419Sjulian		return (ENOBUFS);
88852419Sjulian	}
88952419Sjulian	sorwakeup(so);
89052419Sjulian	return (0);
89152419Sjulian}
89252419Sjulian
89352419Sjulian/*
89453498Sjulian * Hook disconnection
89552885Sjulian *
89652885Sjulian * For this type, removal of the last link destroys the node
89752885Sjulian * if the NOLINGER flag is set.
89852885Sjulian */
89952885Sjulianstatic int
90052885Sjulianngs_disconnect(hook_p hook)
90152885Sjulian{
90272053Sjulian	node_p node = NG_HOOK_NODE(hook);
90372053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
90452885Sjulian
90572053Sjulian	if ((priv->datasock)
90672053Sjulian	&&  (priv->datasock->ng_socket)) {
90772053Sjulian		if (NG_NODE_NUMHOOKS(node) == 1) {
90872053Sjulian			priv->datasock->ng_socket->so_state |= SS_ISCONNECTED;
90972053Sjulian		} else {
91072053Sjulian			priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED;
91172053Sjulian		}
91252885Sjulian	}
91372053Sjulian
91472053Sjulian	if ((priv->flags & NGS_FLAG_NOLINGER )
91572053Sjulian	&& (NG_NODE_NUMHOOKS(node) == 0)
91672053Sjulian	&& (NG_NODE_IS_VALID(node))) {
91772053Sjulian		ng_rmnode_self(node);
91872053Sjulian	}
91952885Sjulian	return (0);
92052885Sjulian}
92152885Sjulian
92252885Sjulian/*
92352419Sjulian * Do local shutdown processing.
92452419Sjulian * In this case, that involves making sure the socket
92552419Sjulian * knows we should be shutting down.
92652419Sjulian */
92752419Sjulianstatic int
92870700Sjulianngs_shutdown(node_p node)
92952419Sjulian{
93072053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
93172053Sjulian	struct ngpcb *const dpcbp = priv->datasock;
93272053Sjulian	struct ngpcb *const pcbp = priv->ctlsock;
93352419Sjulian
93452419Sjulian	if (dpcbp != NULL) {
93552419Sjulian		soisdisconnected(dpcbp->ng_socket);
93652419Sjulian		dpcbp->sockdata = NULL;
93772053Sjulian		priv->datasock = NULL;
93872053Sjulian		priv->refs--;
93952419Sjulian	}
94052419Sjulian	if (pcbp != NULL) {
94152419Sjulian		soisdisconnected(pcbp->ng_socket);
94252419Sjulian		pcbp->sockdata = NULL;
94372053Sjulian		priv->ctlsock = NULL;
94472053Sjulian		priv->refs--;
94552419Sjulian	}
94670784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
94770784Sjulian	NG_NODE_UNREF(node);
94872053Sjulian	FREE(priv, M_NETGRAPH_SOCK);
94952419Sjulian	return (0);
95052419Sjulian}
95152419Sjulian
95272055Sjulianstatic	int
95372055Sjuliandummy_disconnect(struct socket *so)
95472055Sjulian{
95572055Sjulian	return (0);
95672055Sjulian}
95752419Sjulian/*
95852419Sjulian * Control and data socket type descriptors
95952419Sjulian */
96052419Sjulian
96152419Sjulianstatic struct pr_usrreqs ngc_usrreqs = {
96252419Sjulian	NULL,			/* abort */
96352419Sjulian	pru_accept_notsupp,
96452419Sjulian	ngc_attach,
96552419Sjulian	ngc_bind,
96652419Sjulian	ngc_connect,
96752419Sjulian	pru_connect2_notsupp,
96852419Sjulian	pru_control_notsupp,
96952419Sjulian	ngc_detach,
97072055Sjulian	dummy_disconnect,	/* disconnect */
97152419Sjulian	pru_listen_notsupp,
97252419Sjulian	NULL,			/* setpeeraddr */
97352419Sjulian	pru_rcvd_notsupp,
97452419Sjulian	pru_rcvoob_notsupp,
97552419Sjulian	ngc_send,
97652419Sjulian	pru_sense_null,
97752419Sjulian	NULL,			/* shutdown */
97852419Sjulian	ng_setsockaddr,
97952419Sjulian	sosend,
98052419Sjulian	soreceive,
98152419Sjulian	sopoll
98252419Sjulian};
98352419Sjulian
98452419Sjulianstatic struct pr_usrreqs ngd_usrreqs = {
98552419Sjulian	NULL,			/* abort */
98652419Sjulian	pru_accept_notsupp,
98752419Sjulian	ngd_attach,
98852419Sjulian	NULL,			/* bind */
98952419Sjulian	ngd_connect,
99052419Sjulian	pru_connect2_notsupp,
99152419Sjulian	pru_control_notsupp,
99252419Sjulian	ngd_detach,
99372055Sjulian	dummy_disconnect,	/* disconnect */
99452419Sjulian	pru_listen_notsupp,
99552419Sjulian	NULL,			/* setpeeraddr */
99652419Sjulian	pru_rcvd_notsupp,
99752419Sjulian	pru_rcvoob_notsupp,
99852419Sjulian	ngd_send,
99952419Sjulian	pru_sense_null,
100052419Sjulian	NULL,			/* shutdown */
100152419Sjulian	ng_setsockaddr,
100252419Sjulian	sosend,
100352419Sjulian	soreceive,
100452419Sjulian	sopoll
100552419Sjulian};
100652419Sjulian
100752419Sjulian/*
100852419Sjulian * Definitions of protocols supported in the NETGRAPH domain.
100952419Sjulian */
101052419Sjulian
101152419Sjulianextern struct domain ngdomain;		/* stop compiler warnings */
101252419Sjulian
101352419Sjulianstatic struct protosw ngsw[] = {
101452419Sjulian	{
101570700Sjulian		SOCK_DGRAM,		/* protocol type */
101670700Sjulian		&ngdomain,		/* backpointer to domain */
101752419Sjulian		NG_CONTROL,
101870700Sjulian		PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,	/* flags */
101970700Sjulian		0, 0, 0, 0,		/* input, output, ctlinput, ctloutput */
102070700Sjulian		NULL,			/* ousrreq */
102170700Sjulian		0, 0, 0, 0,		/* init, fasttimeo, slowtimo, drain */
102270700Sjulian		&ngc_usrreqs,		/* usrreq table (above) */
102370700Sjulian		/*{NULL}*/		/* pffh (protocol filter head?) */
102452419Sjulian	},
102552419Sjulian	{
102670700Sjulian		SOCK_DGRAM,		/* protocol type */
102770700Sjulian		&ngdomain,		/* backpointer to domain */
102852419Sjulian		NG_DATA,
102970700Sjulian		PR_ATOMIC | PR_ADDR,	/* flags */
103070700Sjulian		0, 0, 0, 0,		/* input, output, ctlinput, ctloutput */
103170700Sjulian		NULL,			/* ousrreq() */
103270700Sjulian		0, 0, 0, 0,		/* init, fasttimeo, slowtimo, drain */
103370700Sjulian		&ngd_usrreqs,		/* usrreq table (above) */
103470700Sjulian		/*{NULL}*/		/* pffh (protocol filter head?) */
103552419Sjulian	}
103652419Sjulian};
103752419Sjulian
103852419Sjulianstruct domain ngdomain = {
103952419Sjulian	AF_NETGRAPH,
104052419Sjulian	"netgraph",
104170700Sjulian	NULL,					/* init() */
104270700Sjulian	NULL,					/* externalise() */
104370700Sjulian	NULL,					/* dispose() */
104470700Sjulian	ngsw,					/* protosw entry */
104570700Sjulian	&ngsw[sizeof(ngsw) / sizeof(ngsw[0])], 	/* Number of protosw entries */
104670700Sjulian	NULL,					/* next domain in list */
104770700Sjulian	NULL,					/* rtattach() */
104870700Sjulian	0,					/* arg to rtattach in bits */
104970700Sjulian	0					/* maxrtkey */
105052419Sjulian};
105152419Sjulian
105252419Sjulian/*
105352419Sjulian * Handle loading and unloading for this node type
105452419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition).
105552419Sjulian */
105652419Sjulianstatic int
105752419Sjulianngs_mod_event(module_t mod, int event, void *data)
105852419Sjulian{
105952419Sjulian	int error = 0;
106052419Sjulian
106152419Sjulian	switch (event) {
106252419Sjulian	case MOD_LOAD:
106352419Sjulian		/* Register protocol domain */
106452419Sjulian		net_add_domain(&ngdomain);
106552419Sjulian		break;
106652419Sjulian	case MOD_UNLOAD:
106752419Sjulian		/* Insure there are no open netgraph sockets */
106852419Sjulian		if (!LIST_EMPTY(&ngsocklist)) {
106952419Sjulian			error = EBUSY;
107052419Sjulian			break;
107152419Sjulian		}
107252419Sjulian
107352419Sjulian#ifdef NOTYET
107470700Sjulian		if ((LIST_EMPTY(&ngsocklist)) && (typestruct.refs == 0)) {
107552419Sjulian		/* Unregister protocol domain XXX can't do this yet.. */
107670700Sjulian			if ((error = net_rm_domain(&ngdomain)) != 0)
107770700Sjulian				break;
107870700Sjulian		} else
107952419Sjulian#endif
108070700Sjulian			error = EBUSY;
108152419Sjulian		break;
108252419Sjulian	default:
108352419Sjulian		error = EOPNOTSUPP;
108452419Sjulian		break;
108552419Sjulian	}
108652419Sjulian	return (error);
108752419Sjulian}
108852419Sjulian
108952419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, "");
109052419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA");
109152419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, "");
109252419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL");
109352419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, "");
109452419Sjulian
1095