sock.c revision 163469
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: head/lib/libnetgraph/sock.c 163469 2006-10-17 16:56:29Z glebius $");
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.
74108533Sschweikh	   If we get an EPROTONOSUPPORT 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) {
7756708Sarchie		if (errno == EPROTONOSUPPORT) {
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) {
11452419Sjulian		u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
11552419Sjulian		struct ng_mesg *const resp = (struct ng_mesg *) rbuf;
11652419Sjulian		struct nodeinfo *const ni = (struct nodeinfo *) resp->data;
11752419Sjulian
11852419Sjulian		/* Find out the node ID */
11952419Sjulian		if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
12052419Sjulian		    NGM_NODEINFO, NULL, 0) < 0) {
12152419Sjulian			errnosv = errno;
12252419Sjulian			if (_gNgDebugLevel >= 1)
12352419Sjulian				NGLOG("send nodeinfo");
12452419Sjulian			goto errout;
12552419Sjulian		}
12652419Sjulian		if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) {
12752419Sjulian			errnosv = errno;
12852419Sjulian			if (_gNgDebugLevel >= 1)
12952419Sjulian				NGLOG("recv nodeinfo");
13052419Sjulian			goto errout;
13152419Sjulian		}
13252419Sjulian
13352419Sjulian		/* Save node "name" */
13452419Sjulian		snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
13552419Sjulian	}
13652419Sjulian
13752419Sjulian	/* Create data socket if desired */
13852419Sjulian	if (dsp != NULL) {
139122649Sharti		u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD];
14052419Sjulian		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
14152419Sjulian
14252419Sjulian		/* Create data socket, initially just "floating" */
14352419Sjulian		if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
14452419Sjulian			errnosv = errno;
14552419Sjulian			if (_gNgDebugLevel >= 1)
14652419Sjulian				NGLOG("socket");
14752419Sjulian			goto errout;
14852419Sjulian		}
14952419Sjulian
15052419Sjulian		/* Associate the data socket with the node */
151122649Sharti		snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
15252419Sjulian		sg->sg_family = AF_NETGRAPH;
153122649Sharti		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
15452419Sjulian		if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
15552419Sjulian			errnosv = errno;
15652419Sjulian			if (_gNgDebugLevel >= 1)
15752419Sjulian				NGLOG("connect(%s)", sg->sg_data);
15852419Sjulian			goto errout;
15952419Sjulian		}
16052419Sjulian	}
16152419Sjulian
16252419Sjulian	/* Return the socket(s) */
16352419Sjulian	if (csp)
16452419Sjulian		*csp = cs;
16552419Sjulian	else
16652419Sjulian		close(cs);
16752419Sjulian	if (dsp)
16852419Sjulian		*dsp = ds;
16952419Sjulian	return (0);
17052419Sjulian
17152419Sjulianerrout:
17252419Sjulian	/* Failed */
17352419Sjulian	if (cs >= 0)
17452419Sjulian		close(cs);
17552419Sjulian	if (ds >= 0)
17652419Sjulian		close(ds);
17752419Sjulian	errno = errnosv;
17852419Sjulian	return (-1);
17952419Sjulian}
18052419Sjulian
18152419Sjulian/*
18252419Sjulian * Assign a globally unique name to a node
18352419Sjulian * Returns -1 if error and sets errno.
18452419Sjulian */
18552419Sjulianint
18652419SjulianNgNameNode(int cs, const char *path, const char *fmt, ...)
18752419Sjulian{
18852419Sjulian	struct ngm_name ngn;
18952419Sjulian	va_list args;
19052419Sjulian
19152419Sjulian	/* Build message arg */
19252419Sjulian	va_start(args, fmt);
19352419Sjulian	vsnprintf(ngn.name, sizeof(ngn.name), fmt, args);
19452419Sjulian	va_end(args);
19552419Sjulian
19652419Sjulian	/* Send message */
19752419Sjulian	if (NgSendMsg(cs, path,
19852419Sjulian	    NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) {
19952419Sjulian		if (_gNgDebugLevel >= 1)
200135576Sstefanf			NGLOGX("%s: failed", __func__);
20152419Sjulian		return (-1);
20252419Sjulian	}
20352419Sjulian
20452419Sjulian	/* Done */
20552419Sjulian	return (0);
20652419Sjulian}
20752419Sjulian
20852419Sjulian/*
20952419Sjulian * Read a packet from a data socket
21052419Sjulian * Returns -1 if error and sets errno.
21152419Sjulian */
21252419Sjulianint
21352419SjulianNgRecvData(int ds, u_char * buf, size_t len, char *hook)
21452419Sjulian{
215122649Sharti	u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD];
21652419Sjulian	struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf;
217145546Smux	socklen_t fromlen = sizeof(frombuf);
21852419Sjulian	int rtn, errnosv;
21952419Sjulian
22052419Sjulian	/* Read packet */
22152419Sjulian	rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen);
22252419Sjulian	if (rtn < 0) {
22352419Sjulian		errnosv = errno;
22452419Sjulian		if (_gNgDebugLevel >= 1)
22552419Sjulian			NGLOG("recvfrom");
22652419Sjulian		errno = errnosv;
22752419Sjulian		return (-1);
22852419Sjulian	}
22952419Sjulian
23052419Sjulian	/* Copy hook name */
23152419Sjulian	if (hook != NULL)
232122649Sharti		strlcpy(hook, from->sg_data, NG_HOOKSIZ);
23352419Sjulian
23452419Sjulian	/* Debugging */
23552419Sjulian	if (_gNgDebugLevel >= 2) {
23652419Sjulian		NGLOGX("READ %s from hook \"%s\" (%d bytes)",
23752419Sjulian		       rtn ? "PACKET" : "EOF", from->sg_data, rtn);
23852419Sjulian		if (_gNgDebugLevel >= 3)
23952419Sjulian			_NgDebugBytes(buf, rtn);
24052419Sjulian	}
24152419Sjulian
24252419Sjulian	/* Done */
24352419Sjulian	return (rtn);
24452419Sjulian}
24552419Sjulian
24652419Sjulian/*
247125113Sru * Identical to NgRecvData() except buffer is dynamically allocated.
248125113Sru */
249125113Sruint
250125113SruNgAllocRecvData(int ds, u_char **buf, char *hook)
251125113Sru{
252125113Sru	int len;
253125113Sru	socklen_t optlen;
254125113Sru
255125113Sru	optlen = sizeof(len);
256125113Sru	if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
257125113Sru	    (*buf = malloc(len)) == NULL)
258125113Sru		return (-1);
259125113Sru	if ((len = NgRecvData(ds, *buf, len, hook)) < 0)
260125113Sru		free(*buf);
261125113Sru	return (len);
262125113Sru}
263125113Sru
264125113Sru/*
26552419Sjulian * Write a packet to a data socket. The packet will be sent
26652419Sjulian * out the corresponding node on the specified hook.
26752419Sjulian * Returns -1 if error and sets errno.
26852419Sjulian */
26952419Sjulianint
27052419SjulianNgSendData(int ds, const char *hook, const u_char * buf, size_t len)
27152419Sjulian{
272122649Sharti	u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD];
27352419Sjulian	struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
27452419Sjulian	int errnosv;
27552419Sjulian
27652419Sjulian	/* Set up destination hook */
27752419Sjulian	sg->sg_family = AF_NETGRAPH;
278122649Sharti	strlcpy(sg->sg_data, hook, NG_HOOKSIZ);
279122649Sharti	sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
28052419Sjulian
28152419Sjulian	/* Debugging */
28252419Sjulian	if (_gNgDebugLevel >= 2) {
28352419Sjulian		NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len);
28452419Sjulian		_NgDebugSockaddr(sg);
28552419Sjulian		if (_gNgDebugLevel >= 3)
28652419Sjulian			_NgDebugBytes(buf, len);
28752419Sjulian	}
28852419Sjulian
28952419Sjulian	/* Send packet */
29052419Sjulian	if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
29152419Sjulian		errnosv = errno;
29252419Sjulian		if (_gNgDebugLevel >= 1)
29352419Sjulian			NGLOG("sendto(%s)", sg->sg_data);
29452419Sjulian		errno = errnosv;
29552419Sjulian		return (-1);
29652419Sjulian	}
29752419Sjulian
29852419Sjulian	/* Done */
29952419Sjulian	return (0);
30052419Sjulian}
30152419Sjulian
302