152419Sjulian/*
252419Sjulian * sock.c
352419Sjulian *
452419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc.
552419Sjulian * All rights reserved.
652419Sjulian *
752419Sjulian * Subject to the following obligations and disclaimer of warranty, use and
852419Sjulian * redistribution of this software, in source or object code forms, with or
952419Sjulian * without modifications are expressly permitted by Whistle Communications;
1052419Sjulian * provided, however, that:
1152419Sjulian * 1. Any and all reproductions of the source or object code must include the
1252419Sjulian *    copyright notice above and the following disclaimer of warranties; and
1352419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle
1452419Sjulian *    Communications, Inc. trademarks, including the mark "WHISTLE
1552419Sjulian *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1652419Sjulian *    such appears in the above copyright notice or in the software.
1752419Sjulian *
1852419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
1952419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2052419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2152419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2252419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2352419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2452419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2552419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2652419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2752419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2852419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
2952419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3052419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3152419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3252419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3352419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3452419Sjulian * OF SUCH DAMAGE.
3552419Sjulian *
3652419Sjulian * Author: Archie Cobbs <archie@whistle.com>
3752419Sjulian *
3852419Sjulian * $Whistle: sock.c,v 1.12 1999/01/20 00:57:23 archie Exp $
3952419Sjulian */
4052419Sjulian
4184215Sdillon#include <sys/cdefs.h>
4284215Sdillon__FBSDID("$FreeBSD$");
4384215Sdillon
4452419Sjulian#include <sys/types.h>
45163469Sglebius#include <sys/socket.h>
4652419Sjulian#include <stdarg.h>
4752419Sjulian#include <netgraph/ng_message.h>
4852419Sjulian#include <netgraph/ng_socket.h>
4952419Sjulian
5052419Sjulian#include "netgraph.h"
5152419Sjulian#include "internal.h"
5252419Sjulian
5356708Sarchie/* The socket node type KLD */
5456708Sarchie#define NG_SOCKET_KLD	"ng_socket.ko"
5556708Sarchie
5652419Sjulian/*
5752419Sjulian * Create a socket type node and give it the supplied name.
5852419Sjulian * Return data and control sockets corresponding to the node.
5952419Sjulian * Returns -1 if error and sets errno.
6052419Sjulian */
6152419Sjulianint
6252419SjulianNgMkSockNode(const char *name, int *csp, int *dsp)
6352419Sjulian{
64122649Sharti	char namebuf[NG_NODESIZ];
6552419Sjulian	int cs = -1;		/* control socket */
6652419Sjulian	int ds = -1;		/* data socket */
6752419Sjulian	int errnosv;
6852419Sjulian
6952419Sjulian	/* Empty name means no name */
7052419Sjulian	if (name && *name == 0)
7152419Sjulian		name = NULL;
7252419Sjulian
7356708Sarchie	/* Create control socket; this also creates the netgraph node.
74244538Skevlo	   If we get an EAFNOSUPPORT then the socket node type is
7556708Sarchie	   not loaded, so load it and try again. */
7652419Sjulian	if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
77244538Skevlo		if (errno == EAFNOSUPPORT) {
7856708Sarchie			if (kldload(NG_SOCKET_KLD) < 0) {
7956708Sarchie				errnosv = errno;
8056708Sarchie				if (_gNgDebugLevel >= 1)
8156708Sarchie					NGLOG("can't load %s", NG_SOCKET_KLD);
8256708Sarchie				goto errout;
8356708Sarchie			}
8456708Sarchie			cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
8556708Sarchie			if (cs >= 0)
8656708Sarchie				goto gotNode;
8756708Sarchie		}
8852419Sjulian		errnosv = errno;
8952419Sjulian		if (_gNgDebugLevel >= 1)
9052419Sjulian			NGLOG("socket");
9152419Sjulian		goto errout;
9252419Sjulian	}
9352419Sjulian
9456708SarchiegotNode:
9552419Sjulian	/* Assign the node the desired name, if any */
9652419Sjulian	if (name != NULL) {
97122649Sharti		u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD];
9852419Sjulian		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
9952419Sjulian
10052419Sjulian		/* Assign name */
101122649Sharti		strlcpy(sg->sg_data, name, NG_NODESIZ);
10252419Sjulian		sg->sg_family = AF_NETGRAPH;
103122649Sharti		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
10452419Sjulian		if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
10552419Sjulian			errnosv = errno;
10652419Sjulian			if (_gNgDebugLevel >= 1)
10752419Sjulian				NGLOG("bind(%s)", sg->sg_data);
10852419Sjulian			goto errout;
10952419Sjulian		}
11052419Sjulian
11152419Sjulian		/* Save node name */
112122649Sharti		strlcpy(namebuf, name, sizeof(namebuf));
11352419Sjulian	} else if (dsp != NULL) {
114260418Sjmg		union {
115260418Sjmg			u_char rbuf[sizeof(struct ng_mesg) +
116260418Sjmg			    sizeof(struct nodeinfo)];
117260418Sjmg			struct ng_mesg res;
118260418Sjmg		} res;
119260418Sjmg		struct nodeinfo *const ni = (struct nodeinfo *) res.res.data;
12052419Sjulian
12152419Sjulian		/* Find out the node ID */
12252419Sjulian		if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
12352419Sjulian		    NGM_NODEINFO, NULL, 0) < 0) {
12452419Sjulian			errnosv = errno;
12552419Sjulian			if (_gNgDebugLevel >= 1)
12652419Sjulian				NGLOG("send nodeinfo");
12752419Sjulian			goto errout;
12852419Sjulian		}
129260418Sjmg		if (NgRecvMsg(cs, &res.res, sizeof(res.rbuf), NULL) < 0) {
13052419Sjulian			errnosv = errno;
13152419Sjulian			if (_gNgDebugLevel >= 1)
13252419Sjulian				NGLOG("recv nodeinfo");
13352419Sjulian			goto errout;
13452419Sjulian		}
13552419Sjulian
13652419Sjulian		/* Save node "name" */
13752419Sjulian		snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
13852419Sjulian	}
13952419Sjulian
14052419Sjulian	/* Create data socket if desired */
14152419Sjulian	if (dsp != NULL) {
142122649Sharti		u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD];
14352419Sjulian		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
14452419Sjulian
14552419Sjulian		/* Create data socket, initially just "floating" */
14652419Sjulian		if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
14752419Sjulian			errnosv = errno;
14852419Sjulian			if (_gNgDebugLevel >= 1)
14952419Sjulian				NGLOG("socket");
15052419Sjulian			goto errout;
15152419Sjulian		}
15252419Sjulian
15352419Sjulian		/* Associate the data socket with the node */
154122649Sharti		snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
15552419Sjulian		sg->sg_family = AF_NETGRAPH;
156122649Sharti		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
15752419Sjulian		if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
15852419Sjulian			errnosv = errno;
15952419Sjulian			if (_gNgDebugLevel >= 1)
16052419Sjulian				NGLOG("connect(%s)", sg->sg_data);
16152419Sjulian			goto errout;
16252419Sjulian		}
16352419Sjulian	}
16452419Sjulian
16552419Sjulian	/* Return the socket(s) */
16652419Sjulian	if (csp)
16752419Sjulian		*csp = cs;
16852419Sjulian	else
16952419Sjulian		close(cs);
17052419Sjulian	if (dsp)
17152419Sjulian		*dsp = ds;
17252419Sjulian	return (0);
17352419Sjulian
17452419Sjulianerrout:
17552419Sjulian	/* Failed */
17652419Sjulian	if (cs >= 0)
17752419Sjulian		close(cs);
17852419Sjulian	if (ds >= 0)
17952419Sjulian		close(ds);
18052419Sjulian	errno = errnosv;
18152419Sjulian	return (-1);
18252419Sjulian}
18352419Sjulian
18452419Sjulian/*
18552419Sjulian * Assign a globally unique name to a node
18652419Sjulian * Returns -1 if error and sets errno.
18752419Sjulian */
18852419Sjulianint
18952419SjulianNgNameNode(int cs, const char *path, const char *fmt, ...)
19052419Sjulian{
19152419Sjulian	struct ngm_name ngn;
19252419Sjulian	va_list args;
19352419Sjulian
19452419Sjulian	/* Build message arg */
19552419Sjulian	va_start(args, fmt);
19652419Sjulian	vsnprintf(ngn.name, sizeof(ngn.name), fmt, args);
19752419Sjulian	va_end(args);
19852419Sjulian
19952419Sjulian	/* Send message */
20052419Sjulian	if (NgSendMsg(cs, path,
20152419Sjulian	    NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) {
20252419Sjulian		if (_gNgDebugLevel >= 1)
203135576Sstefanf			NGLOGX("%s: failed", __func__);
20452419Sjulian		return (-1);
20552419Sjulian	}
20652419Sjulian
20752419Sjulian	/* Done */
20852419Sjulian	return (0);
20952419Sjulian}
21052419Sjulian
21152419Sjulian/*
21252419Sjulian * Read a packet from a data socket
21352419Sjulian * Returns -1 if error and sets errno.
21452419Sjulian */
21552419Sjulianint
21652419SjulianNgRecvData(int ds, u_char * buf, size_t len, char *hook)
21752419Sjulian{
218122649Sharti	u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD];
21952419Sjulian	struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf;
220145546Smux	socklen_t fromlen = sizeof(frombuf);
22152419Sjulian	int rtn, errnosv;
22252419Sjulian
22352419Sjulian	/* Read packet */
22452419Sjulian	rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen);
22552419Sjulian	if (rtn < 0) {
22652419Sjulian		errnosv = errno;
22752419Sjulian		if (_gNgDebugLevel >= 1)
22852419Sjulian			NGLOG("recvfrom");
22952419Sjulian		errno = errnosv;
23052419Sjulian		return (-1);
23152419Sjulian	}
23252419Sjulian
23352419Sjulian	/* Copy hook name */
23452419Sjulian	if (hook != NULL)
235122649Sharti		strlcpy(hook, from->sg_data, NG_HOOKSIZ);
23652419Sjulian
23752419Sjulian	/* Debugging */
23852419Sjulian	if (_gNgDebugLevel >= 2) {
23952419Sjulian		NGLOGX("READ %s from hook \"%s\" (%d bytes)",
24052419Sjulian		       rtn ? "PACKET" : "EOF", from->sg_data, rtn);
24152419Sjulian		if (_gNgDebugLevel >= 3)
24252419Sjulian			_NgDebugBytes(buf, rtn);
24352419Sjulian	}
24452419Sjulian
24552419Sjulian	/* Done */
24652419Sjulian	return (rtn);
24752419Sjulian}
24852419Sjulian
24952419Sjulian/*
250125113Sru * Identical to NgRecvData() except buffer is dynamically allocated.
251125113Sru */
252125113Sruint
253125113SruNgAllocRecvData(int ds, u_char **buf, char *hook)
254125113Sru{
255125113Sru	int len;
256125113Sru	socklen_t optlen;
257125113Sru
258125113Sru	optlen = sizeof(len);
259125113Sru	if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
260125113Sru	    (*buf = malloc(len)) == NULL)
261125113Sru		return (-1);
262125113Sru	if ((len = NgRecvData(ds, *buf, len, hook)) < 0)
263125113Sru		free(*buf);
264125113Sru	return (len);
265125113Sru}
266125113Sru
267125113Sru/*
26852419Sjulian * Write a packet to a data socket. The packet will be sent
26952419Sjulian * out the corresponding node on the specified hook.
27052419Sjulian * Returns -1 if error and sets errno.
27152419Sjulian */
27252419Sjulianint
27352419SjulianNgSendData(int ds, const char *hook, const u_char * buf, size_t len)
27452419Sjulian{
275122649Sharti	u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD];
27652419Sjulian	struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
27752419Sjulian	int errnosv;
27852419Sjulian
27952419Sjulian	/* Set up destination hook */
28052419Sjulian	sg->sg_family = AF_NETGRAPH;
281122649Sharti	strlcpy(sg->sg_data, hook, NG_HOOKSIZ);
282122649Sharti	sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
28352419Sjulian
28452419Sjulian	/* Debugging */
28552419Sjulian	if (_gNgDebugLevel >= 2) {
28652419Sjulian		NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len);
28752419Sjulian		_NgDebugSockaddr(sg);
28852419Sjulian		if (_gNgDebugLevel >= 3)
28952419Sjulian			_NgDebugBytes(buf, len);
29052419Sjulian	}
29152419Sjulian
29252419Sjulian	/* Send packet */
29352419Sjulian	if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
29452419Sjulian		errnosv = errno;
29552419Sjulian		if (_gNgDebugLevel >= 1)
29652419Sjulian			NGLOG("sendto(%s)", sg->sg_data);
29752419Sjulian		errno = errnosv;
29852419Sjulian		return (-1);
29952419Sjulian	}
30052419Sjulian
30152419Sjulian	/* Done */
30252419Sjulian	return (0);
30352419Sjulian}
30452419Sjulian
305