ng_socket.c revision 177071
152419Sjulian/*
252419Sjulian * ng_socket.c
3139823Simp */
4139823Simp
5139823Simp/*-
652419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc.
752419Sjulian * All rights reserved.
870784Sjulian *
952419Sjulian * Subject to the following obligations and disclaimer of warranty, use and
1052419Sjulian * redistribution of this software, in source or object code forms, with or
1152419Sjulian * without modifications are expressly permitted by Whistle Communications;
1252419Sjulian * provided, however, that:
1352419Sjulian * 1. Any and all reproductions of the source or object code must include the
1452419Sjulian *    copyright notice above and the following disclaimer of warranties; and
1552419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle
1652419Sjulian *    Communications, Inc. trademarks, including the mark "WHISTLE
1752419Sjulian *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1852419Sjulian *    such appears in the above copyright notice or in the software.
1970784Sjulian *
2052419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2152419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2252419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2352419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2452419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2552419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2652419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2752419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2852419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2952419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
3052419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3152419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3252419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3352419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3452419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3552419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3652419Sjulian * OF SUCH DAMAGE.
3752419Sjulian *
3867506Sjulian * Author: Julian Elischer <julian@freebsd.org>
3952419Sjulian *
4052419Sjulian * $FreeBSD: head/sys/netgraph/ng_socket.c 177071 2008-03-11 21:58:48Z mav $
4152752Sjulian * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $
4252419Sjulian */
4352419Sjulian
4452419Sjulian/*
4552419Sjulian * Netgraph socket nodes
4652419Sjulian *
4752419Sjulian * There are two types of netgraph sockets, control and data.
4852419Sjulian * Control sockets have a netgraph node, but data sockets are
4952419Sjulian * parasitic on control sockets, and have no node of their own.
5052419Sjulian */
5152419Sjulian
5252419Sjulian#include <sys/param.h>
5352419Sjulian#include <sys/domain.h>
5452419Sjulian#include <sys/kernel.h>
55132705Sglebius#include <sys/linker.h>
5695759Stanimura#include <sys/lock.h>
5752419Sjulian#include <sys/malloc.h>
5852419Sjulian#include <sys/mbuf.h>
59132013Srwatson#include <sys/mutex.h>
60164033Srwatson#include <sys/priv.h>
6152419Sjulian#include <sys/protosw.h>
6295759Stanimura#include <sys/queue.h>
6352419Sjulian#include <sys/socket.h>
6452419Sjulian#include <sys/socketvar.h>
65159590Sjhb#include <sys/syscallsubr.h>
6652419Sjulian#include <sys/sysctl.h>
6752419Sjulian#ifdef NOTYET
6852419Sjulian#include <sys/vnode.h>
6952419Sjulian#endif
7052419Sjulian#include <netgraph/ng_message.h>
7152419Sjulian#include <netgraph/netgraph.h>
7252919Sjulian#include <netgraph/ng_socketvar.h>
7352419Sjulian#include <netgraph/ng_socket.h>
7452419Sjulian
7570870Sjulian#ifdef NG_SEPARATE_MALLOC
7670870SjulianMALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info ");
7770870SjulianMALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info ");
7870870Sjulian#else
7970870Sjulian#define M_NETGRAPH_PATH M_NETGRAPH
8070870Sjulian#define M_NETGRAPH_SOCK M_NETGRAPH
8170870Sjulian#endif
8270870Sjulian
8352419Sjulian/*
8452419Sjulian * It's Ascii-art time!
8552419Sjulian *   +-------------+   +-------------+
8652419Sjulian *   |socket  (ctl)|   |socket (data)|
8752419Sjulian *   +-------------+   +-------------+
8852419Sjulian *          ^                 ^
8952419Sjulian *          |                 |
9052419Sjulian *          v                 v
9152419Sjulian *    +-----------+     +-----------+
9252419Sjulian *    |pcb   (ctl)|     |pcb  (data)|
9352419Sjulian *    +-----------+     +-----------+
9452419Sjulian *          ^                 ^
9552419Sjulian *          |                 |
9652419Sjulian *          v                 v
9752419Sjulian *      +--------------------------+
9852419Sjulian *      |   Socket type private    |
9952419Sjulian *      |       data               |
10052419Sjulian *      +--------------------------+
10152419Sjulian *                   ^
10252419Sjulian *                   |
10352419Sjulian *                   v
10452419Sjulian *           +----------------+
10552419Sjulian *           | struct ng_node |
10652419Sjulian *           +----------------+
10752419Sjulian */
10852419Sjulian
10952419Sjulian/* Netgraph node methods */
11052752Sjulianstatic ng_constructor_t	ngs_constructor;
11152752Sjulianstatic ng_rcvmsg_t	ngs_rcvmsg;
11270700Sjulianstatic ng_shutdown_t	ngs_shutdown;
11352752Sjulianstatic ng_newhook_t	ngs_newhook;
11472053Sjulianstatic ng_connect_t	ngs_connect;
11552752Sjulianstatic ng_rcvdata_t	ngs_rcvdata;
11652885Sjulianstatic ng_disconnect_t	ngs_disconnect;
11752419Sjulian
11852419Sjulian/* Internal methods */
11952419Sjulianstatic int	ng_attach_data(struct socket *so);
12052419Sjulianstatic int	ng_attach_cntl(struct socket *so);
12152419Sjulianstatic int	ng_attach_common(struct socket *so, int type);
122151975Sglebiusstatic void	ng_detach_common(struct ngpcb *pcbp, int type);
123151975Sglebiusstatic void	ng_socket_free_priv(struct ngsock *priv);
124163463Sglebius#ifdef NOTYET
125163463Sglebiusstatic int	ng_internalize(struct mbuf *m, struct thread *p);
126163463Sglebius#endif
12752419Sjulianstatic int	ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
12852419Sjulianstatic int	ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
12952419Sjulian
13052419Sjulianstatic int	ngs_mod_event(module_t mod, int event, void *data);
131147774Sglebiusstatic void	ng_socket_item_applied(void *context, int error);
13252419Sjulian
13352419Sjulian/* Netgraph type descriptor */
13452419Sjulianstatic struct ng_type typestruct = {
135129823Sjulian	.version =	NG_ABI_VERSION,
136129823Sjulian	.name =		NG_SOCKET_NODE_TYPE,
137129823Sjulian	.mod_event =	ngs_mod_event,
138129823Sjulian	.constructor =	ngs_constructor,
139129823Sjulian	.rcvmsg =	ngs_rcvmsg,
140129823Sjulian	.shutdown =	ngs_shutdown,
141129823Sjulian	.newhook =	ngs_newhook,
142129823Sjulian	.connect =	ngs_connect,
143129823Sjulian	.rcvdata =	ngs_rcvdata,
144129823Sjulian	.disconnect =	ngs_disconnect,
14552419Sjulian};
146138238SmlaierNETGRAPH_INIT_ORDERED(socket, &typestruct, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
14752419Sjulian
14852419Sjulian/* Buffer space */
14964512Sarchiestatic u_long ngpdg_sendspace = 20 * 1024;	/* really max datagram size */
150124871SruSYSCTL_INT(_net_graph, OID_AUTO, maxdgram, CTLFLAG_RW,
151124871Sru    &ngpdg_sendspace , 0, "Maximum outgoing Netgraph datagram size");
15252419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024;
153124871SruSYSCTL_INT(_net_graph, OID_AUTO, recvspace, CTLFLAG_RW,
154125116Sru    &ngpdg_recvspace , 0, "Maximum space for incoming Netgraph datagrams");
15552419Sjulian
15653526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb)
15752419Sjulian
158131933Smarcel/* If getting unexplained errors returned, set this to "kdb_enter("X"); */
15952419Sjulian#ifndef TRAP_ERROR
16052419Sjulian#define TRAP_ERROR
16152419Sjulian#endif
16252419Sjulian
16352419Sjulian/***************************************************************
16452419Sjulian	Control sockets
16552419Sjulian***************************************************************/
16652419Sjulian
16752419Sjulianstatic int
16883366Sjulianngc_attach(struct socket *so, int proto, struct thread *td)
16952419Sjulian{
17052419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
171164033Srwatson	int error;
17252419Sjulian
173164033Srwatson	error = priv_check(td, PRIV_NETGRAPH_CONTROL);
174164033Srwatson	if (error)
175164033Srwatson		return (error);
17652419Sjulian	if (pcbp != NULL)
17752419Sjulian		return (EISCONN);
17852419Sjulian	return (ng_attach_cntl(so));
17952419Sjulian}
18052419Sjulian
181157370Srwatsonstatic void
18252419Sjulianngc_detach(struct socket *so)
18352419Sjulian{
18452419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
18552419Sjulian
186157370Srwatson	KASSERT(pcbp != NULL, ("ngc_detach: pcbp == NULL"));
187151975Sglebius	ng_detach_common(pcbp, NG_CONTROL);
18852419Sjulian}
18952419Sjulian
19052419Sjulianstatic int
19152419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
19283366Sjulian	 struct mbuf *control, struct thread *td)
19352419Sjulian{
19452419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
195147774Sglebius	struct ngsock *const priv = NG_NODE_PRIVATE(pcbp->sockdata->node);
19652419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
19770700Sjulian	struct ng_mesg *msg;
19852419Sjulian	struct mbuf *m0;
199146317Sglebius	item_p item;
20070700Sjulian	char *path = NULL;
20152419Sjulian	int len, error = 0;
202172806Smav	struct ng_apply_info apply;
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
218163463Sglebius	/* Require destination as there may be >= 1 hooks on this node. */
21952419Sjulian	if (addr == NULL) {
22052419Sjulian		error = EDESTADDRREQ;
22152419Sjulian		goto release;
22252419Sjulian	}
22352419Sjulian
224163463Sglebius	/*
225163463Sglebius	 * Allocate an expendable buffer for the path, chop off
226163463Sglebius	 * the sockaddr header, and make sure it's NUL terminated.
227163463Sglebius	 */
22852419Sjulian	len = sap->sg_len - 2;
229163463Sglebius	path = malloc(len + 1, M_NETGRAPH_PATH, M_WAITOK);
23052419Sjulian	bcopy(sap->sg_data, path, len);
23152419Sjulian	path[len] = '\0';
23252419Sjulian
233163463Sglebius	/*
234163463Sglebius	 * Move the actual message out of mbufs into a linear buffer.
235163463Sglebius	 * Start by adding up the size of the data. (could use mh_len?)
236163463Sglebius	 */
23752419Sjulian	for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
23852419Sjulian		len += m0->m_len;
23952419Sjulian
240163463Sglebius	/*
241163463Sglebius	 * Move the data into a linear buffer as well.
242163463Sglebius	 * Messages are not delivered in mbufs.
243163463Sglebius	 */
244163463Sglebius	msg = malloc(len + 1, M_NETGRAPH_MSG, M_WAITOK);
24570700Sjulian	m_copydata(m, 0, len, (char *)msg);
24652419Sjulian
247141308Sglebius	if (msg->header.version != NG_VERSION) {
248163463Sglebius		free(msg, M_NETGRAPH_MSG);
249141308Sglebius		error = EINVAL;
250141308Sglebius		goto release;
251141308Sglebius	}
252141308Sglebius
253132705Sglebius	/*
254132705Sglebius	 * Hack alert!
255132705Sglebius	 * We look into the message and if it mkpeers a node of unknown type, we
256132705Sglebius	 * try to load it. We need to do this now, in syscall thread, because if
257132705Sglebius	 * message gets queued and applied later we will get panic.
258132705Sglebius	 */
259132939Sglebius	if (msg->header.typecookie == NGM_GENERIC_COOKIE &&
260132939Sglebius	    msg->header.cmd == NGM_MKPEER) {
261132705Sglebius		struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data;
262132705Sglebius		struct ng_type *type;
263132705Sglebius
264132705Sglebius		if ((type = ng_findtype(mkp->type)) == NULL) {
265132705Sglebius			char filename[NG_TYPESIZ + 3];
266159590Sjhb			int fileid;
267132705Sglebius
268146296Sglebius			/* Not found, try to load it as a loadable module. */
269146296Sglebius			snprintf(filename, sizeof(filename), "ng_%s",
270146296Sglebius			    mkp->type);
271159590Sjhb			error = kern_kldload(curthread, filename, &fileid);
272132705Sglebius			if (error != 0) {
273163463Sglebius				free(msg, M_NETGRAPH_MSG);
274132705Sglebius				goto release;
275132705Sglebius			}
276132705Sglebius
277146296Sglebius			/* See if type has been loaded successfully. */
278132705Sglebius			if ((type = ng_findtype(mkp->type)) == NULL) {
279163463Sglebius				free(msg, M_NETGRAPH_MSG);
280159590Sjhb				(void)kern_kldunload(curthread, fileid,
281159590Sjhb				    LINKER_UNLOAD_NORMAL);
282132705Sglebius				error =  ENXIO;
283132705Sglebius				goto release;
284132705Sglebius			}
285132705Sglebius		}
286132705Sglebius	}
287132705Sglebius
288163463Sglebius	item = ng_package_msg(msg, M_WAITOK);
289163463Sglebius	if ((error = ng_address_path((pcbp->sockdata->node), item, path, 0))
290163463Sglebius	    != 0) {
291146296Sglebius#ifdef TRACE_MESSAGES
292146317Sglebius		printf("ng_address_path: errx=%d\n", error);
293146317Sglebius#endif
294146317Sglebius		goto release;
295146317Sglebius	}
296146296Sglebius
297146317Sglebius#ifdef TRACE_MESSAGES
298146317Sglebius	printf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n",
299146317Sglebius		item->el_dest->nd_ID,
300146317Sglebius		msg->header.typecookie,
301146317Sglebius		msg->header.cmd,
302146317Sglebius		msg->header.cmdstr,
303146317Sglebius		msg->header.flags,
304146317Sglebius		msg->header.token,
305146317Sglebius		item->el_dest->nd_type->name);
30670784Sjulian#endif
307146317Sglebius	SAVE_LINE(item);
308147774Sglebius	/*
309147774Sglebius	 * We do not want to return from syscall until the item
310147774Sglebius	 * is processed by destination node. We register callback
311147774Sglebius	 * on the item, which will update priv->error when item
312147774Sglebius	 * was applied.
313147774Sglebius	 * If ng_snd_item() has queued item, we sleep until
314147774Sglebius	 * callback wakes us up.
315147774Sglebius	 */
316172806Smav	bzero(&apply, sizeof(apply));
317172806Smav	apply.apply = ng_socket_item_applied;
318172806Smav	apply.context = priv;
319172806Smav	item->apply = &apply;
320147774Sglebius	priv->error = -1;
321146296Sglebius
322172806Smav	error = ng_snd_item(item, 0);
323147774Sglebius
324172806Smav	mtx_lock(&priv->mtx);
325172806Smav	if (priv->error == -1)
326172806Smav		msleep(priv, &priv->mtx, 0, "ngsock", 0);
327172806Smav	mtx_unlock(&priv->mtx);
328172806Smav	KASSERT(priv->error != -1,
329172806Smav	    ("ng_socket: priv->error wasn't updated"));
330172806Smav	error = priv->error;
331147774Sglebius
33252419Sjulianrelease:
33352419Sjulian	if (path != NULL)
334163463Sglebius		free(path, M_NETGRAPH_PATH);
33552419Sjulian	if (control != NULL)
33652419Sjulian		m_freem(control);
33752419Sjulian	if (m != NULL)
33852419Sjulian		m_freem(m);
33952419Sjulian	return (error);
34052419Sjulian}
34152419Sjulian
34252419Sjulianstatic int
34383366Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
34452419Sjulian{
34552419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
34652419Sjulian
34752419Sjulian	if (pcbp == 0)
34852419Sjulian		return (EINVAL);
34952419Sjulian	return (ng_bind(nam, pcbp));
35052419Sjulian}
35152419Sjulian
35252419Sjulianstatic int
35383366Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
35452419Sjulian{
35570700Sjulian	/*
35670784Sjulian	 * At this time refuse to do this.. it used to
35770700Sjulian	 * do something but it was undocumented and not used.
35870700Sjulian	 */
359163463Sglebius	printf("program tried to connect control socket to remote node\n");
36070700Sjulian	return (EINVAL);
36152419Sjulian}
36252419Sjulian
36352419Sjulian/***************************************************************
36452419Sjulian	Data sockets
36552419Sjulian***************************************************************/
36652419Sjulian
36752419Sjulianstatic int
36883366Sjulianngd_attach(struct socket *so, int proto, struct thread *td)
36952419Sjulian{
37052419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
37152419Sjulian
37252419Sjulian	if (pcbp != NULL)
37352419Sjulian		return (EISCONN);
37452419Sjulian	return (ng_attach_data(so));
37552419Sjulian}
37652419Sjulian
377157370Srwatsonstatic void
37852419Sjulianngd_detach(struct socket *so)
37952419Sjulian{
38052419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
38152419Sjulian
382157558Srwatson	KASSERT(pcbp != NULL, ("ngd_detach: pcbp == NULL"));
383151975Sglebius	ng_detach_common(pcbp, NG_DATA);
38452419Sjulian}
38552419Sjulian
38652419Sjulianstatic int
38752419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
38883366Sjulian	 struct mbuf *control, struct thread *td)
38952419Sjulian{
39052419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
39152419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
392163463Sglebius	int	len, error;
39353498Sjulian	hook_p  hook = NULL;
394125028Sharti	char	hookname[NG_HOOKSIZ];
39552419Sjulian
39652419Sjulian	if ((pcbp == NULL) || (control != NULL)) {
39752419Sjulian		error = EINVAL;
39852419Sjulian		goto release;
39952419Sjulian	}
40052419Sjulian	if (pcbp->sockdata == NULL) {
40152419Sjulian		error = ENOTCONN;
40252419Sjulian		goto release;
40352419Sjulian	}
404146718Sbz
405146718Sbz	if (sap == NULL)
406146718Sbz		len = 0;		/* Make compiler happy. */
407146718Sbz	else
408146718Sbz		len = sap->sg_len - 2;
409146718Sbz
41053498Sjulian	/*
41153498Sjulian	 * If the user used any of these ways to not specify an address
41253498Sjulian	 * then handle specially.
41353498Sjulian	 */
414146718Sbz	if ((sap == NULL) || (len <= 0) || (*sap->sg_data == '\0')) {
41570784Sjulian		if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) {
41653498Sjulian			error = EDESTADDRREQ;
41753498Sjulian			goto release;
41853498Sjulian		}
41953498Sjulian		/*
420163463Sglebius		 * If exactly one hook exists, just use it.
42153498Sjulian		 * Special case to allow write(2) to work on an ng_socket.
42253498Sjulian		 */
42370784Sjulian		hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks);
42453498Sjulian	} else {
425125028Sharti		if (len >= NG_HOOKSIZ) {
42653498Sjulian			error = EINVAL;
42753498Sjulian			goto release;
42853498Sjulian		}
42952419Sjulian
43053498Sjulian		/*
43153498Sjulian		 * chop off the sockaddr header, and make sure it's NUL
43253498Sjulian		 * terminated
43353498Sjulian		 */
43453498Sjulian		bcopy(sap->sg_data, hookname, len);
43553498Sjulian		hookname[len] = '\0';
43652419Sjulian
43753498Sjulian		/* Find the correct hook from 'hookname' */
438163463Sglebius		hook = ng_findhook(pcbp->sockdata->node, hookname);
43972053Sjulian		if (hook == NULL) {
44053498Sjulian			error = EHOSTUNREACH;
441163463Sglebius			goto release;
44272053Sjulian		}
44352419Sjulian	}
44452419Sjulian
445163463Sglebius	/* Send data. */
446163463Sglebius	NG_SEND_DATA_FLAGS(error, hook, m, NG_WAITOK);
44752419Sjulian
44852419Sjulianrelease:
44952419Sjulian	if (control != NULL)
45052419Sjulian		m_freem(control);
45152419Sjulian	if (m != NULL)
45252419Sjulian		m_freem(m);
45352419Sjulian	return (error);
45452419Sjulian}
45552419Sjulian
45652419Sjulianstatic int
45783366Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
45852419Sjulian{
45952419Sjulian	struct ngpcb *const pcbp = sotongpcb(so);
46052419Sjulian
46152419Sjulian	if (pcbp == 0)
46252419Sjulian		return (EINVAL);
46352419Sjulian	return (ng_connect_data(nam, pcbp));
46452419Sjulian}
46552419Sjulian
46652419Sjulian/*
46752419Sjulian * Used for both data and control sockets
46852419Sjulian */
46952419Sjulianstatic int
470169462Srwatsonng_getsockaddr(struct socket *so, struct sockaddr **addr)
47152419Sjulian{
47253098Sbrian	struct ngpcb *pcbp;
47353098Sbrian	struct sockaddr_ng *sg;
474151975Sglebius	int sg_len;
475151975Sglebius	int error = 0;
47652419Sjulian
47753098Sbrian	/* Why isn't sg_data a `char[1]' ? :-( */
47853098Sbrian	sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1;
47953098Sbrian
48053098Sbrian	pcbp = sotongpcb(so);
481151975Sglebius	if ((pcbp == NULL) || (pcbp->sockdata == NULL))
482151975Sglebius		/* XXXGL: can this still happen? */
48352419Sjulian		return (EINVAL);
48453098Sbrian
485151975Sglebius	mtx_lock(&pcbp->sockdata->mtx);
486151975Sglebius	if (pcbp->sockdata->node != NULL) {
487151975Sglebius		node_p node = pcbp->sockdata->node;
488151975Sglebius		int namelen = 0;	/* silence compiler! */
48953098Sbrian
490151975Sglebius		if (NG_NODE_HAS_NAME(node))
491151975Sglebius			sg_len += namelen = strlen(NG_NODE_NAME(node));
49253098Sbrian
493151975Sglebius		sg = malloc(sg_len, M_SONAME, M_WAITOK | M_ZERO);
49453098Sbrian
495151975Sglebius		if (NG_NODE_HAS_NAME(node))
496151975Sglebius			bcopy(NG_NODE_NAME(node), sg->sg_data, namelen);
49753098Sbrian
498151975Sglebius		sg->sg_len = sg_len;
499151975Sglebius		sg->sg_family = AF_NETGRAPH;
500151975Sglebius		*addr = (struct sockaddr *)sg;
501151975Sglebius		mtx_unlock(&pcbp->sockdata->mtx);
502151975Sglebius	} else {
503151975Sglebius		mtx_unlock(&pcbp->sockdata->mtx);
504151975Sglebius		error = EINVAL;
505151975Sglebius	}
506151975Sglebius
507151975Sglebius	return (error);
50852419Sjulian}
50952419Sjulian
51052419Sjulian/*
51152419Sjulian * Attach a socket to it's protocol specific partner.
51252419Sjulian * For a control socket, actually create a netgraph node and attach
51352419Sjulian * to it as well.
51452419Sjulian */
51552419Sjulian
51652419Sjulianstatic int
51752419Sjulianng_attach_cntl(struct socket *so)
51852419Sjulian{
519151975Sglebius	struct ngsock *priv;
52052419Sjulian	struct ngpcb *pcbp;
52152419Sjulian	int error;
52252419Sjulian
523151975Sglebius	/* Allocate node private info */
524163463Sglebius	priv = malloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO);
525151975Sglebius
52652419Sjulian	/* Setup protocol control block */
527151975Sglebius	if ((error = ng_attach_common(so, NG_CONTROL)) != 0) {
528163463Sglebius		free(priv, M_NETGRAPH_SOCK);
52952419Sjulian		return (error);
530151975Sglebius	}
53153526Sjulian	pcbp = sotongpcb(so);
53252419Sjulian
533151975Sglebius	/* Link the pcb the private data. */
534151975Sglebius	priv->ctlsock = pcbp;
535151975Sglebius	pcbp->sockdata = priv;
536151975Sglebius	priv->refs++;
53752419Sjulian
538151975Sglebius	/* Initialize mutex. */
539151975Sglebius	mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF);
540151975Sglebius
54152419Sjulian	/* Make the generic node components */
542151975Sglebius	if ((error = ng_make_node_common(&typestruct, &priv->node)) != 0) {
543163463Sglebius		free(priv, M_NETGRAPH_SOCK);
544151975Sglebius		ng_detach_common(pcbp, NG_CONTROL);
54552419Sjulian		return (error);
54652419Sjulian	}
54752419Sjulian
548151975Sglebius	/* Link the node and the private data. */
549151975Sglebius	NG_NODE_SET_PRIVATE(priv->node, priv);
550151975Sglebius	NG_NODE_REF(priv->node);
551151975Sglebius	priv->refs++;
552147774Sglebius
55352419Sjulian	return (0);
55452419Sjulian}
55552419Sjulian
55652419Sjulianstatic int
55752419Sjulianng_attach_data(struct socket *so)
55852419Sjulian{
559163463Sglebius	return (ng_attach_common(so, NG_DATA));
56052419Sjulian}
56152419Sjulian
56252419Sjulian/*
56352419Sjulian * Set up a socket protocol control block.
56452419Sjulian * This code is shared between control and data sockets.
56552419Sjulian */
56652419Sjulianstatic int
56752419Sjulianng_attach_common(struct socket *so, int type)
56852419Sjulian{
56952419Sjulian	struct ngpcb *pcbp;
57052419Sjulian	int error;
57152419Sjulian
572163463Sglebius	/* Standard socket setup stuff. */
57352419Sjulian	error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
57452419Sjulian	if (error)
57552419Sjulian		return (error);
57652419Sjulian
577163463Sglebius	/* Allocate the pcb. */
578163463Sglebius	pcbp = malloc(sizeof(struct ngpcb), M_PCB, M_WAITOK | M_ZERO);
57952419Sjulian	pcbp->type = type;
58052419Sjulian
581163463Sglebius	/* Link the pcb and the socket. */
582163463Sglebius	so->so_pcb = (caddr_t)pcbp;
58352419Sjulian	pcbp->ng_socket = so;
58452419Sjulian
58552419Sjulian	return (0);
58652419Sjulian}
58752419Sjulian
58852419Sjulian/*
58952419Sjulian * Disassociate the socket from it's protocol specific
59052419Sjulian * partner. If it's attached to a node's private data structure,
59152419Sjulian * then unlink from that too. If we were the last socket attached to it,
59252419Sjulian * then shut down the entire node. Shared code for control and data sockets.
59352419Sjulian */
59452419Sjulianstatic void
595151975Sglebiusng_detach_common(struct ngpcb *pcbp, int which)
59652419Sjulian{
597151975Sglebius	struct ngsock *priv = pcbp->sockdata;
59852419Sjulian
599151975Sglebius	if (priv != NULL) {
600151975Sglebius		mtx_lock(&priv->mtx);
601146290Sglebius
60252419Sjulian		switch (which) {
60352419Sjulian		case NG_CONTROL:
60472053Sjulian			priv->ctlsock = NULL;
60552419Sjulian			break;
60652419Sjulian		case NG_DATA:
60772053Sjulian			priv->datasock = NULL;
60852419Sjulian			break;
60952419Sjulian		default:
61087599Sobrien			panic(__func__);
61152419Sjulian		}
612151975Sglebius		pcbp->sockdata = NULL;
613151975Sglebius
614151975Sglebius		ng_socket_free_priv(priv);
61552419Sjulian	}
616151975Sglebius
61752419Sjulian	pcbp->ng_socket->so_pcb = NULL;
618163463Sglebius	free(pcbp, M_PCB);
61952419Sjulian}
62052419Sjulian
621151975Sglebius/*
622151975Sglebius * Remove a reference from node private data.
623151975Sglebius */
624151975Sglebiusstatic void
625151975Sglebiusng_socket_free_priv(struct ngsock *priv)
626151975Sglebius{
627151975Sglebius	mtx_assert(&priv->mtx, MA_OWNED);
628151975Sglebius
629151975Sglebius	priv->refs--;
630151975Sglebius
631151975Sglebius	if (priv->refs == 0) {
632151975Sglebius		mtx_destroy(&priv->mtx);
633163463Sglebius		free(priv, M_NETGRAPH_SOCK);
634151975Sglebius		return;
635151975Sglebius	}
636151975Sglebius
637151975Sglebius	if ((priv->refs == 1) && (priv->node != NULL)) {
638151975Sglebius		node_p node = priv->node;
639151975Sglebius
640151975Sglebius		priv->node = NULL;
641151975Sglebius		mtx_unlock(&priv->mtx);
642151975Sglebius		NG_NODE_UNREF(node);
643151975Sglebius		ng_rmnode_self(node);
644151975Sglebius	} else
645151975Sglebius		mtx_unlock(&priv->mtx);
646151975Sglebius}
647151975Sglebius
64852419Sjulian#ifdef NOTYET
64952419Sjulian/*
650108533Sschweikh * File descriptors can be passed into an AF_NETGRAPH socket.
65152419Sjulian * Note, that file descriptors cannot be passed OUT.
65252419Sjulian * Only character device descriptors are accepted.
65352419Sjulian * Character devices are useful to connect a graph to a device,
65452419Sjulian * which after all is the purpose of this whole system.
65552419Sjulian */
65652419Sjulianstatic int
65783366Sjulianng_internalize(struct mbuf *control, struct thread *td)
65852419Sjulian{
65997897Sarchie	const struct cmsghdr *cm = mtod(control, const struct cmsghdr *);
66052419Sjulian	struct file *fp;
66152419Sjulian	struct vnode *vn;
66252419Sjulian	int oldfds;
66352419Sjulian	int fd;
66452419Sjulian
66552419Sjulian	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
66652419Sjulian	    cm->cmsg_len != control->m_len) {
66752419Sjulian		TRAP_ERROR;
66852419Sjulian		return (EINVAL);
66952419Sjulian	}
67052419Sjulian
67152419Sjulian	/* Check there is only one FD. XXX what would more than one signify? */
67284472Sdwmalone	oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int);
67352419Sjulian	if (oldfds != 1) {
67452419Sjulian		TRAP_ERROR;
67552419Sjulian		return (EINVAL);
67652419Sjulian	}
67752419Sjulian
67852419Sjulian	/* Check that the FD given is legit. and change it to a pointer to a
67952419Sjulian	 * struct file. */
68084472Sdwmalone	fd = CMSG_DATA(cm);
68189319Salfred	if ((error = fget(td, fd, &fp)) != 0)
68289319Salfred		return (error);
68352419Sjulian
68452419Sjulian	/* Depending on what kind of resource it is, act differently. For
685108533Sschweikh	 * devices, we treat it as a file. For an AF_NETGRAPH socket,
68652419Sjulian	 * shortcut straight to the node. */
68752419Sjulian	switch (fp->f_type) {
68852419Sjulian	case DTYPE_VNODE:
689109153Sdillon		vn = fp->f_data;
69052419Sjulian		if (vn && (vn->v_type == VCHR)) {
69152419Sjulian			/* for a VCHR, actually reference the FILE */
692174988Sjeff			fhold(fp);
69352419Sjulian			/* XXX then what :) */
69452419Sjulian			/* how to pass on to other modules? */
69552419Sjulian		} else {
69689306Salfred			fdrop(fp, td);
69752419Sjulian			TRAP_ERROR;
69852419Sjulian			return (EINVAL);
69952419Sjulian		}
70052419Sjulian		break;
70152419Sjulian	default:
70289306Salfred		fdrop(fp, td);
70352419Sjulian		TRAP_ERROR;
70452419Sjulian		return (EINVAL);
70552419Sjulian	}
70689306Salfred	fdrop(fp, td);
70752419Sjulian	return (0);
70852419Sjulian}
70952419Sjulian#endif	/* NOTYET */
71052419Sjulian
71152419Sjulian/*
71252419Sjulian * Connect the data socket to a named control socket node.
71352419Sjulian */
71452419Sjulianstatic int
71552419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
71652419Sjulian{
71752419Sjulian	struct sockaddr_ng *sap;
71852419Sjulian	node_p farnode;
71972053Sjulian	struct ngsock *priv;
72052419Sjulian	int error;
72170700Sjulian	item_p item;
72252419Sjulian
723163463Sglebius	/* If we are already connected, don't do it again. */
72452419Sjulian	if (pcbp->sockdata != NULL)
72552419Sjulian		return (EISCONN);
72652419Sjulian
727163463Sglebius	/*
728163463Sglebius	 * Find the target (victim) and check it doesn't already have
729163463Sglebius	 * a data socket. Also check it is a 'socket' type node.
730163463Sglebius	 * Use ng_package_data() and ng_address_path() to do this.
73170700Sjulian	 */
73270700Sjulian
73352419Sjulian	sap = (struct sockaddr_ng *) nam;
734163463Sglebius	/* The item will hold the node reference. */
735146284Sglebius	item = ng_package_data(NULL, NG_WAITOK);
736163463Sglebius
737102244Sarchie	if ((error = ng_address_path(NULL, item,  sap->sg_data, 0)))
73870700Sjulian		return (error); /* item is freed on failure */
73952419Sjulian
74070700Sjulian	/*
74170784Sjulian	 * Extract node from item and free item. Remember we now have
74270700Sjulian	 * a reference on the node. The item holds it for us.
74370700Sjulian	 * when we free the item we release the reference.
74470700Sjulian	 */
74570700Sjulian	farnode = item->el_dest; /* shortcut */
74670784Sjulian	if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) {
74770700Sjulian		NG_FREE_ITEM(item); /* drop the reference to the node */
74852419Sjulian		return (EINVAL);
74970700Sjulian	}
75072053Sjulian	priv = NG_NODE_PRIVATE(farnode);
75172053Sjulian	if (priv->datasock != NULL) {
75270700Sjulian		NG_FREE_ITEM(item);	/* drop the reference to the node */
75352419Sjulian		return (EADDRINUSE);
75470700Sjulian	}
75552419Sjulian
75670700Sjulian	/*
75770700Sjulian	 * Link the PCB and the private data struct. and note the extra
75870700Sjulian	 * reference. Drop the extra reference on the node.
75970700Sjulian	 */
760151975Sglebius	mtx_lock(&priv->mtx);
76172053Sjulian	priv->datasock = pcbp;
76272053Sjulian	pcbp->sockdata = priv;
763151975Sglebius	priv->refs++;
764151975Sglebius	mtx_unlock(&priv->mtx);
76570700Sjulian	NG_FREE_ITEM(item);	/* drop the reference to the node */
76652419Sjulian	return (0);
76752419Sjulian}
76852419Sjulian
76952419Sjulian/*
77052419Sjulian * Binding a socket means giving the corresponding node a name
77152419Sjulian */
77252419Sjulianstatic int
77352419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
77452419Sjulian{
77572053Sjulian	struct ngsock *const priv = pcbp->sockdata;
77652419Sjulian	struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
77752419Sjulian
77872053Sjulian	if (priv == NULL) {
77952419Sjulian		TRAP_ERROR;
78052419Sjulian		return (EINVAL);
78152419Sjulian	}
782163463Sglebius	if ((sap->sg_len < 4) || (sap->sg_len > (NG_NODESIZ + 2)) ||
783163463Sglebius	    (sap->sg_data[0] == '\0') ||
784163463Sglebius	    (sap->sg_data[sap->sg_len - 3] != '\0')) {
78552419Sjulian		TRAP_ERROR;
78652419Sjulian		return (EINVAL);
78752419Sjulian	}
78872053Sjulian	return (ng_name_node(priv->node, sap->sg_data));
78952419Sjulian}
79052419Sjulian
791147774Sglebius/***************************************************************
792147774Sglebius	Netgraph node
793147774Sglebius***************************************************************/
794147774Sglebius
79552419Sjulian/*
79652419Sjulian * You can only create new nodes from the socket end of things.
79752419Sjulian */
79852419Sjulianstatic int
79970700Sjulianngs_constructor(node_p nodep)
80052419Sjulian{
80152419Sjulian	return (EINVAL);
80252419Sjulian}
80352419Sjulian
80452419Sjulian/*
80552419Sjulian * We allow any hook to be connected to the node.
80652419Sjulian * There is no per-hook private information though.
80752419Sjulian */
80852419Sjulianstatic int
80952419Sjulianngs_newhook(node_p node, hook_p hook, const char *name)
81052419Sjulian{
81170784Sjulian	NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node));
81252419Sjulian	return (0);
81352419Sjulian}
81452419Sjulian
815163463Sglebius/*
816163463Sglebius * If only one hook, allow read(2) and write(2) to work.
81772053Sjulian */
81872053Sjulianstatic int
81972053Sjulianngs_connect(hook_p hook)
82072053Sjulian{
82172053Sjulian	node_p node = NG_HOOK_NODE(hook);
82272053Sjulian	struct ngsock *priv = NG_NODE_PRIVATE(node);
82372053Sjulian
824163463Sglebius	if ((priv->datasock) && (priv->datasock->ng_socket)) {
825163463Sglebius		if (NG_NODE_NUMHOOKS(node) == 1)
82672053Sjulian			priv->datasock->ng_socket->so_state |= SS_ISCONNECTED;
827163463Sglebius		else
82872053Sjulian			priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED;
82972053Sjulian	}
83072053Sjulian	return (0);
83172053Sjulian}
83272053Sjulian
83352419Sjulian/*
83452419Sjulian * Incoming messages get passed up to the control socket.
83552885Sjulian * Unless they are for us specifically (socket_type)
83652419Sjulian */
83752419Sjulianstatic int
83870700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook)
83952419Sjulian{
84072053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
84172053Sjulian	struct ngpcb *const pcbp = priv->ctlsock;
842163475Sglebius	struct socket *so;
843163468Sglebius	struct sockaddr_ng addr;
844163468Sglebius	struct ng_mesg *msg;
845163468Sglebius	struct mbuf *m;
846163468Sglebius	ng_ID_t	retaddr = NGI_RETADDR(item);
84752419Sjulian	int addrlen;
84852419Sjulian	int error = 0;
84952419Sjulian
85070700Sjulian	NGI_GET_MSG(item, msg);
851163468Sglebius	NG_FREE_ITEM(item);
85270700Sjulian
853163468Sglebius	/*
854163468Sglebius	 * Only allow mesgs to be passed if we have the control socket.
855163468Sglebius	 * Data sockets can only support the generic messages.
856163468Sglebius	 */
85752419Sjulian	if (pcbp == NULL) {
85852419Sjulian		TRAP_ERROR;
859163468Sglebius		NG_FREE_MSG(msg);
86052419Sjulian		return (EINVAL);
86152419Sjulian	}
862163475Sglebius	so = pcbp->ng_socket;
863146296Sglebius
86470784Sjulian#ifdef TRACE_MESSAGES
865146296Sglebius	printf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n",
866146296Sglebius		retaddr,
867146296Sglebius		msg->header.typecookie,
868146296Sglebius		msg->header.cmd,
869146296Sglebius		msg->header.cmdstr,
870146296Sglebius		msg->header.flags,
871146296Sglebius		msg->header.token);
87270784Sjulian#endif
87370784Sjulian
87452885Sjulian	if (msg->header.typecookie == NGM_SOCKET_COOKIE) {
87552885Sjulian		switch (msg->header.cmd) {
87652885Sjulian		case NGM_SOCK_CMD_NOLINGER:
87772053Sjulian			priv->flags |= NGS_FLAG_NOLINGER;
87852885Sjulian			break;
87952885Sjulian		case NGM_SOCK_CMD_LINGER:
88072053Sjulian			priv->flags &= ~NGS_FLAG_NOLINGER;
88152885Sjulian			break;
88252885Sjulian		default:
88352885Sjulian			error = EINVAL;		/* unknown command */
88452885Sjulian		}
885163468Sglebius		/* Free the message and return. */
88670700Sjulian		NG_FREE_MSG(msg);
887163468Sglebius		return (error);
888163468Sglebius	}
88952885Sjulian
890163468Sglebius	/* Get the return address into a sockaddr. */
891163468Sglebius	bzero(&addr, sizeof(addr));
892163468Sglebius	addr.sg_len = sizeof(addr);
893163468Sglebius	addr.sg_family = AF_NETGRAPH;
894163468Sglebius	addrlen = snprintf((char *)&addr.sg_data, sizeof(addr.sg_data),
895163468Sglebius	    "[%x]:", retaddr);
896163468Sglebius	if (addrlen < 0 || addrlen > sizeof(addr.sg_data)) {
897163468Sglebius		printf("%s: snprintf([%x]) failed - %d\n", __func__, retaddr,
898163468Sglebius		    addrlen);
899163468Sglebius		NG_FREE_MSG(msg);
900163468Sglebius		return (EINVAL);
90152885Sjulian	}
902163468Sglebius
903163468Sglebius	/* Copy the message itself into an mbuf chain. */
904163468Sglebius	m = m_devget((caddr_t)msg, sizeof(struct ng_mesg) + msg->header.arglen,
905163468Sglebius	    0, NULL, NULL);
906163468Sglebius
907163468Sglebius	/*
908163468Sglebius	 * Here we free the message. We need to do that
909163468Sglebius	 * regardless of whether we got mbufs.
910163468Sglebius	 */
911163468Sglebius	NG_FREE_MSG(msg);
912163468Sglebius
913163468Sglebius	if (m == NULL) {
91452419Sjulian		TRAP_ERROR;
915163468Sglebius		return (ENOBUFS);
91652419Sjulian	}
91752419Sjulian
918163468Sglebius	/* Send it up to the socket. */
919163468Sglebius	if (sbappendaddr(&so->so_rcv, (struct sockaddr *)&addr, m, NULL) == 0) {
920163468Sglebius		TRAP_ERROR;
921163468Sglebius		m_freem(m);
922177071Smav		return (ENOBUFS);
923163468Sglebius	}
924163468Sglebius	sorwakeup(so);
925163468Sglebius
92652419Sjulian	return (error);
92752419Sjulian}
92852419Sjulian
92952419Sjulian/*
93052419Sjulian * Receive data on a hook
93152419Sjulian */
93252419Sjulianstatic int
93370700Sjulianngs_rcvdata(hook_p hook, item_p item)
93452419Sjulian{
93572053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
93672053Sjulian	struct ngpcb *const pcbp = priv->datasock;
93752419Sjulian	struct socket *so;
93852419Sjulian	struct sockaddr_ng *addr;
939125028Sharti	char *addrbuf[NG_HOOKSIZ + 4];
94052419Sjulian	int addrlen;
94170700Sjulian	struct mbuf *m;
94252419Sjulian
94370700Sjulian	NGI_GET_M(item, m);
94470700Sjulian	NG_FREE_ITEM(item);
945163463Sglebius
946163463Sglebius	/* If there is no data socket, black-hole it. */
94752419Sjulian	if (pcbp == NULL) {
94870700Sjulian		NG_FREE_M(m);
94952419Sjulian		return (0);
95052419Sjulian	}
95152419Sjulian	so = pcbp->ng_socket;
95252419Sjulian
95352419Sjulian	/* Get the return address into a sockaddr. */
954125028Sharti	addrlen = strlen(NG_HOOK_NAME(hook));	/* <= NG_HOOKSIZ - 1 */
95552419Sjulian	addr = (struct sockaddr_ng *) addrbuf;
95652419Sjulian	addr->sg_len = addrlen + 3;
95752419Sjulian	addr->sg_family = AF_NETGRAPH;
95870784Sjulian	bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen);
95952419Sjulian	addr->sg_data[addrlen] = '\0';
96052419Sjulian
961163463Sglebius	/* Try to tell the socket which hook it came in on. */
962163463Sglebius	if (sbappendaddr(&so->so_rcv, (struct sockaddr *)addr, m, NULL) == 0) {
96352419Sjulian		m_freem(m);
96452419Sjulian		TRAP_ERROR;
96552419Sjulian		return (ENOBUFS);
96652419Sjulian	}
96752419Sjulian	sorwakeup(so);
96852419Sjulian	return (0);
96952419Sjulian}
97052419Sjulian
97152419Sjulian/*
97253498Sjulian * Hook disconnection
97352885Sjulian *
97452885Sjulian * For this type, removal of the last link destroys the node
97552885Sjulian * if the NOLINGER flag is set.
97652885Sjulian */
97752885Sjulianstatic int
97852885Sjulianngs_disconnect(hook_p hook)
97952885Sjulian{
98072053Sjulian	node_p node = NG_HOOK_NODE(hook);
98172053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
98252885Sjulian
983163463Sglebius	if ((priv->datasock) && (priv->datasock->ng_socket)) {
984163463Sglebius		if (NG_NODE_NUMHOOKS(node) == 1)
98572053Sjulian			priv->datasock->ng_socket->so_state |= SS_ISCONNECTED;
986163463Sglebius		else
98772053Sjulian			priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED;
98852885Sjulian	}
98972053Sjulian
990163463Sglebius	if ((priv->flags & NGS_FLAG_NOLINGER) &&
991163463Sglebius	    (NG_NODE_NUMHOOKS(node) == 0) && (NG_NODE_IS_VALID(node)))
99272053Sjulian		ng_rmnode_self(node);
993163463Sglebius
99452885Sjulian	return (0);
99552885Sjulian}
99652885Sjulian
99752885Sjulian/*
99852419Sjulian * Do local shutdown processing.
99952419Sjulian * In this case, that involves making sure the socket
100052419Sjulian * knows we should be shutting down.
100152419Sjulian */
100252419Sjulianstatic int
100370700Sjulianngs_shutdown(node_p node)
100452419Sjulian{
100572053Sjulian	struct ngsock *const priv = NG_NODE_PRIVATE(node);
100672053Sjulian	struct ngpcb *const dpcbp = priv->datasock;
100772053Sjulian	struct ngpcb *const pcbp = priv->ctlsock;
100852419Sjulian
1009151975Sglebius	if (dpcbp != NULL)
101052419Sjulian		soisdisconnected(dpcbp->ng_socket);
1011151975Sglebius
1012151975Sglebius	if (pcbp != NULL)
101352419Sjulian		soisdisconnected(pcbp->ng_socket);
1014151975Sglebius
1015151975Sglebius	mtx_lock(&priv->mtx);
1016151975Sglebius	priv->node = NULL;
101770784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
1018151975Sglebius	ng_socket_free_priv(priv);
1019151975Sglebius
102070784Sjulian	NG_NODE_UNREF(node);
102152419Sjulian	return (0);
102252419Sjulian}
102352419Sjulian
1024147774Sglebiusstatic void
1025147774Sglebiusng_socket_item_applied(void *context, int error)
1026147774Sglebius{
1027147774Sglebius	struct ngsock *const priv = (struct ngsock *)context;
1028147774Sglebius
1029147774Sglebius	mtx_lock(&priv->mtx);
1030147774Sglebius	priv->error = error;
1031147774Sglebius	wakeup(priv);
1032147774Sglebius	mtx_unlock(&priv->mtx);
1033147774Sglebius
1034147774Sglebius}
1035147774Sglebius
103672055Sjulianstatic	int
103772055Sjuliandummy_disconnect(struct socket *so)
103872055Sjulian{
103972055Sjulian	return (0);
104072055Sjulian}
104152419Sjulian/*
104252419Sjulian * Control and data socket type descriptors
1043160549Srwatson *
1044160549Srwatson * XXXRW: Perhaps _close should do something?
104552419Sjulian */
104652419Sjulian
104752419Sjulianstatic struct pr_usrreqs ngc_usrreqs = {
1048137386Sphk	.pru_abort =		NULL,
1049137386Sphk	.pru_attach =		ngc_attach,
1050137386Sphk	.pru_bind =		ngc_bind,
1051137386Sphk	.pru_connect =		ngc_connect,
1052137386Sphk	.pru_detach =		ngc_detach,
1053137386Sphk	.pru_disconnect =	dummy_disconnect,
1054137386Sphk	.pru_peeraddr =		NULL,
1055137386Sphk	.pru_send =		ngc_send,
1056137386Sphk	.pru_shutdown =		NULL,
1057169462Srwatson	.pru_sockaddr =		ng_getsockaddr,
1058160549Srwatson	.pru_close =		NULL,
105952419Sjulian};
106052419Sjulian
106152419Sjulianstatic struct pr_usrreqs ngd_usrreqs = {
1062137386Sphk	.pru_abort =		NULL,
1063137386Sphk	.pru_attach =		ngd_attach,
1064137386Sphk	.pru_bind =		NULL,
1065137386Sphk	.pru_connect =		ngd_connect,
1066137386Sphk	.pru_detach =		ngd_detach,
1067137386Sphk	.pru_disconnect =	dummy_disconnect,
1068137386Sphk	.pru_peeraddr =		NULL,
1069137386Sphk	.pru_send =		ngd_send,
1070137386Sphk	.pru_shutdown =		NULL,
1071169462Srwatson	.pru_sockaddr =		ng_getsockaddr,
1072160549Srwatson	.pru_close =		NULL,
107352419Sjulian};
107452419Sjulian
107552419Sjulian/*
107652419Sjulian * Definitions of protocols supported in the NETGRAPH domain.
107752419Sjulian */
107852419Sjulian
107952419Sjulianextern struct domain ngdomain;		/* stop compiler warnings */
108052419Sjulian
108152419Sjulianstatic struct protosw ngsw[] = {
1082152242Sru{
1083152242Sru	.pr_type =		SOCK_DGRAM,
1084152242Sru	.pr_domain =		&ngdomain,
1085152242Sru	.pr_protocol =		NG_CONTROL,
1086152242Sru	.pr_flags =		PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,
1087152242Sru	.pr_usrreqs =		&ngc_usrreqs
1088152242Sru},
1089152242Sru{
1090152242Sru	.pr_type =		SOCK_DGRAM,
1091152242Sru	.pr_domain =		&ngdomain,
1092152242Sru	.pr_protocol =		NG_DATA,
1093152242Sru	.pr_flags =		PR_ATOMIC | PR_ADDR,
1094152242Sru	.pr_usrreqs =		&ngd_usrreqs
1095152242Sru}
109652419Sjulian};
109752419Sjulian
109852419Sjulianstruct domain ngdomain = {
1099152242Sru	.dom_family =		AF_NETGRAPH,
1100152242Sru	.dom_name =		"netgraph",
1101152242Sru	.dom_protosw =		ngsw,
1102152242Sru	.dom_protoswNPROTOSW =	&ngsw[sizeof(ngsw) / sizeof(ngsw[0])]
110352419Sjulian};
110452419Sjulian
110552419Sjulian/*
1106163463Sglebius * Handle loading and unloading for this node type.
110752419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition).
110852419Sjulian */
110952419Sjulianstatic int
111052419Sjulianngs_mod_event(module_t mod, int event, void *data)
111152419Sjulian{
111252419Sjulian	int error = 0;
111352419Sjulian
111452419Sjulian	switch (event) {
111552419Sjulian	case MOD_LOAD:
1116163463Sglebius		/* Register protocol domain. */
111752419Sjulian		net_add_domain(&ngdomain);
111852419Sjulian		break;
111952419Sjulian	case MOD_UNLOAD:
112052419Sjulian#ifdef NOTYET
112152419Sjulian		/* Unregister protocol domain XXX can't do this yet.. */
1122163463Sglebius		if ((error = net_rm_domain(&ngdomain)) != 0)
1123163463Sglebius			break;
1124163463Sglebius		else
112552419Sjulian#endif
112670700Sjulian			error = EBUSY;
112752419Sjulian		break;
112852419Sjulian	default:
112952419Sjulian		error = EOPNOTSUPP;
113052419Sjulian		break;
113152419Sjulian	}
113252419Sjulian	return (error);
113352419Sjulian}
113452419Sjulian
113552419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, "");
113652419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA");
113752419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, "");
113852419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL");
113952419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, "");
114052419Sjulian
1141