sock.c revision 84215
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 84215 2001-09-30 22:03:54Z dillon $");
4384215Sdillon
4452419Sjulian#include <sys/types.h>
4552419Sjulian#include <stdarg.h>
4652419Sjulian#include <netgraph/ng_message.h>
4752419Sjulian#include <netgraph/ng_socket.h>
4852419Sjulian
4952419Sjulian#include "netgraph.h"
5052419Sjulian#include "internal.h"
5152419Sjulian
5256708Sarchie/* The socket node type KLD */
5356708Sarchie#define NG_SOCKET_KLD	"ng_socket.ko"
5456708Sarchie
5552419Sjulian/*
5652419Sjulian * Create a socket type node and give it the supplied name.
5752419Sjulian * Return data and control sockets corresponding to the node.
5852419Sjulian * Returns -1 if error and sets errno.
5952419Sjulian */
6052419Sjulianint
6152419SjulianNgMkSockNode(const char *name, int *csp, int *dsp)
6252419Sjulian{
6352419Sjulian	char namebuf[NG_NODELEN + 1];
6452419Sjulian	int cs = -1;		/* control socket */
6552419Sjulian	int ds = -1;		/* data socket */
6652419Sjulian	int errnosv;
6752419Sjulian
6852419Sjulian	/* Empty name means no name */
6952419Sjulian	if (name && *name == 0)
7052419Sjulian		name = NULL;
7152419Sjulian
7256708Sarchie	/* Create control socket; this also creates the netgraph node.
7356708Sarchie	   If we get a EPROTONOSUPPORT then the socket node type is
7456708Sarchie	   not loaded, so load it and try again. */
7552419Sjulian	if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
7656708Sarchie		if (errno == EPROTONOSUPPORT) {
7756708Sarchie			if (kldload(NG_SOCKET_KLD) < 0) {
7856708Sarchie				errnosv = errno;
7956708Sarchie				if (_gNgDebugLevel >= 1)
8056708Sarchie					NGLOG("can't load %s", NG_SOCKET_KLD);
8156708Sarchie				goto errout;
8256708Sarchie			}
8356708Sarchie			cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
8456708Sarchie			if (cs >= 0)
8556708Sarchie				goto gotNode;
8656708Sarchie		}
8752419Sjulian		errnosv = errno;
8852419Sjulian		if (_gNgDebugLevel >= 1)
8952419Sjulian			NGLOG("socket");
9052419Sjulian		goto errout;
9152419Sjulian	}
9252419Sjulian
9356708SarchiegotNode:
9452419Sjulian	/* Assign the node the desired name, if any */
9552419Sjulian	if (name != NULL) {
9652419Sjulian		u_char sbuf[NG_NODELEN + 3];
9752419Sjulian		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
9852419Sjulian
9952419Sjulian		/* Assign name */
10052419Sjulian		snprintf(sg->sg_data, NG_NODELEN + 1, "%s", name);
10152419Sjulian		sg->sg_family = AF_NETGRAPH;
10252419Sjulian		sg->sg_len = strlen(sg->sg_data) + 3;
10352419Sjulian		if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
10452419Sjulian			errnosv = errno;
10552419Sjulian			if (_gNgDebugLevel >= 1)
10652419Sjulian				NGLOG("bind(%s)", sg->sg_data);
10752419Sjulian			goto errout;
10852419Sjulian		}
10952419Sjulian
11052419Sjulian		/* Save node name */
11152419Sjulian		snprintf(namebuf, sizeof(namebuf), "%s", name);
11252419Sjulian	} else if (dsp != NULL) {
11352419Sjulian		u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
11452419Sjulian		struct ng_mesg *const resp = (struct ng_mesg *) rbuf;
11552419Sjulian		struct nodeinfo *const ni = (struct nodeinfo *) resp->data;
11652419Sjulian
11752419Sjulian		/* Find out the node ID */
11852419Sjulian		if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
11952419Sjulian		    NGM_NODEINFO, NULL, 0) < 0) {
12052419Sjulian			errnosv = errno;
12152419Sjulian			if (_gNgDebugLevel >= 1)
12252419Sjulian				NGLOG("send nodeinfo");
12352419Sjulian			goto errout;
12452419Sjulian		}
12552419Sjulian		if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) {
12652419Sjulian			errnosv = errno;
12752419Sjulian			if (_gNgDebugLevel >= 1)
12852419Sjulian				NGLOG("recv nodeinfo");
12952419Sjulian			goto errout;
13052419Sjulian		}
13152419Sjulian
13252419Sjulian		/* Save node "name" */
13352419Sjulian		snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
13452419Sjulian	}
13552419Sjulian
13652419Sjulian	/* Create data socket if desired */
13752419Sjulian	if (dsp != NULL) {
13852419Sjulian		u_char sbuf[NG_NODELEN + 4];
13952419Sjulian		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
14052419Sjulian
14152419Sjulian		/* Create data socket, initially just "floating" */
14252419Sjulian		if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
14352419Sjulian			errnosv = errno;
14452419Sjulian			if (_gNgDebugLevel >= 1)
14552419Sjulian				NGLOG("socket");
14652419Sjulian			goto errout;
14752419Sjulian		}
14852419Sjulian
14952419Sjulian		/* Associate the data socket with the node */
15052419Sjulian		snprintf(sg->sg_data, NG_NODELEN + 2, "%s:", namebuf);
15152419Sjulian		sg->sg_family = AF_NETGRAPH;
15252419Sjulian		sg->sg_len = strlen(sg->sg_data) + 3;
15352419Sjulian		if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
15452419Sjulian			errnosv = errno;
15552419Sjulian			if (_gNgDebugLevel >= 1)
15652419Sjulian				NGLOG("connect(%s)", sg->sg_data);
15752419Sjulian			goto errout;
15852419Sjulian		}
15952419Sjulian	}
16052419Sjulian
16152419Sjulian	/* Return the socket(s) */
16252419Sjulian	if (csp)
16352419Sjulian		*csp = cs;
16452419Sjulian	else
16552419Sjulian		close(cs);
16652419Sjulian	if (dsp)
16752419Sjulian		*dsp = ds;
16852419Sjulian	return (0);
16952419Sjulian
17052419Sjulianerrout:
17152419Sjulian	/* Failed */
17252419Sjulian	if (cs >= 0)
17352419Sjulian		close(cs);
17452419Sjulian	if (ds >= 0)
17552419Sjulian		close(ds);
17652419Sjulian	errno = errnosv;
17752419Sjulian	return (-1);
17852419Sjulian}
17952419Sjulian
18052419Sjulian/*
18152419Sjulian * Assign a globally unique name to a node
18252419Sjulian * Returns -1 if error and sets errno.
18352419Sjulian */
18452419Sjulianint
18552419SjulianNgNameNode(int cs, const char *path, const char *fmt, ...)
18652419Sjulian{
18752419Sjulian	struct ngm_name ngn;
18852419Sjulian	va_list args;
18952419Sjulian
19052419Sjulian	/* Build message arg */
19152419Sjulian	va_start(args, fmt);
19252419Sjulian	vsnprintf(ngn.name, sizeof(ngn.name), fmt, args);
19352419Sjulian	va_end(args);
19452419Sjulian
19552419Sjulian	/* Send message */
19652419Sjulian	if (NgSendMsg(cs, path,
19752419Sjulian	    NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) {
19852419Sjulian		if (_gNgDebugLevel >= 1)
19952419Sjulian			NGLOGX("%s: failed", __FUNCTION__);
20052419Sjulian		return (-1);
20152419Sjulian	}
20252419Sjulian
20352419Sjulian	/* Done */
20452419Sjulian	return (0);
20552419Sjulian}
20652419Sjulian
20752419Sjulian/*
20852419Sjulian * Read a packet from a data socket
20952419Sjulian * Returns -1 if error and sets errno.
21052419Sjulian */
21152419Sjulianint
21252419SjulianNgRecvData(int ds, u_char * buf, size_t len, char *hook)
21352419Sjulian{
21452419Sjulian	u_char frombuf[NG_HOOKLEN + sizeof(struct sockaddr_ng)];
21552419Sjulian	struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf;
21652419Sjulian	int fromlen = sizeof(frombuf);
21752419Sjulian	int rtn, errnosv;
21852419Sjulian
21952419Sjulian	/* Read packet */
22052419Sjulian	rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen);
22152419Sjulian	if (rtn < 0) {
22252419Sjulian		errnosv = errno;
22352419Sjulian		if (_gNgDebugLevel >= 1)
22452419Sjulian			NGLOG("recvfrom");
22552419Sjulian		errno = errnosv;
22652419Sjulian		return (-1);
22752419Sjulian	}
22852419Sjulian
22952419Sjulian	/* Copy hook name */
23052419Sjulian	if (hook != NULL)
23152419Sjulian		snprintf(hook, NG_HOOKLEN + 1, "%s", from->sg_data);
23252419Sjulian
23352419Sjulian	/* Debugging */
23452419Sjulian	if (_gNgDebugLevel >= 2) {
23552419Sjulian		NGLOGX("READ %s from hook \"%s\" (%d bytes)",
23652419Sjulian		       rtn ? "PACKET" : "EOF", from->sg_data, rtn);
23752419Sjulian		if (_gNgDebugLevel >= 3)
23852419Sjulian			_NgDebugBytes(buf, rtn);
23952419Sjulian	}
24052419Sjulian
24152419Sjulian	/* Done */
24252419Sjulian	return (rtn);
24352419Sjulian}
24452419Sjulian
24552419Sjulian/*
24652419Sjulian * Write a packet to a data socket. The packet will be sent
24752419Sjulian * out the corresponding node on the specified hook.
24852419Sjulian * Returns -1 if error and sets errno.
24952419Sjulian */
25052419Sjulianint
25152419SjulianNgSendData(int ds, const char *hook, const u_char * buf, size_t len)
25252419Sjulian{
25352419Sjulian	u_char sgbuf[NG_HOOKLEN + sizeof(struct sockaddr_ng)];
25452419Sjulian	struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
25552419Sjulian	int errnosv;
25652419Sjulian
25752419Sjulian	/* Set up destination hook */
25852419Sjulian	sg->sg_family = AF_NETGRAPH;
25952419Sjulian	snprintf(sg->sg_data, NG_HOOKLEN + 1, "%s", hook);
26052419Sjulian	sg->sg_len = strlen(sg->sg_data) + 3;
26152419Sjulian
26252419Sjulian	/* Debugging */
26352419Sjulian	if (_gNgDebugLevel >= 2) {
26452419Sjulian		NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len);
26552419Sjulian		_NgDebugSockaddr(sg);
26652419Sjulian		if (_gNgDebugLevel >= 3)
26752419Sjulian			_NgDebugBytes(buf, len);
26852419Sjulian	}
26952419Sjulian
27052419Sjulian	/* Send packet */
27152419Sjulian	if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
27252419Sjulian		errnosv = errno;
27352419Sjulian		if (_gNgDebugLevel >= 1)
27452419Sjulian			NGLOG("sendto(%s)", sg->sg_data);
27552419Sjulian		errno = errnosv;
27652419Sjulian		return (-1);
27752419Sjulian	}
27852419Sjulian
27952419Sjulian	/* Done */
28052419Sjulian	return (0);
28152419Sjulian}
28252419Sjulian
283