sock.c revision 135576
1254885Sdumbbell/*
2254885Sdumbbell * sock.c
3254885Sdumbbell *
4254885Sdumbbell * Copyright (c) 1996-1999 Whistle Communications, Inc.
5254885Sdumbbell * All rights reserved.
6254885Sdumbbell *
7254885Sdumbbell * Subject to the following obligations and disclaimer of warranty, use and
8254885Sdumbbell * redistribution of this software, in source or object code forms, with or
9254885Sdumbbell * without modifications are expressly permitted by Whistle Communications;
10254885Sdumbbell * provided, however, that:
11254885Sdumbbell * 1. Any and all reproductions of the source or object code must include the
12254885Sdumbbell *    copyright notice above and the following disclaimer of warranties; and
13254885Sdumbbell * 2. No rights are granted, in any manner or form, to use Whistle
14254885Sdumbbell *    Communications, Inc. trademarks, including the mark "WHISTLE
15254885Sdumbbell *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
16254885Sdumbbell *    such appears in the above copyright notice or in the software.
17254885Sdumbbell *
18254885Sdumbbell * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
19254885Sdumbbell * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
20254885Sdumbbell * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
21254885Sdumbbell * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
22254885Sdumbbell * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
23254885Sdumbbell * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
24254885Sdumbbell * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
25254885Sdumbbell * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
26254885Sdumbbell * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
27254885Sdumbbell * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
28254885Sdumbbell * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29254885Sdumbbell * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
30254885Sdumbbell * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
31254885Sdumbbell * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32254885Sdumbbell * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33254885Sdumbbell * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
34254885Sdumbbell * OF SUCH DAMAGE.
35254885Sdumbbell *
36254885Sdumbbell * Author: Archie Cobbs <archie@whistle.com>
37254885Sdumbbell *
38254885Sdumbbell * $Whistle: sock.c,v 1.12 1999/01/20 00:57:23 archie Exp $
39254885Sdumbbell */
40254885Sdumbbell
41254885Sdumbbell#include <sys/cdefs.h>
42254885Sdumbbell__FBSDID("$FreeBSD: head/lib/libnetgraph/sock.c 135576 2004-09-22 16:56:49Z stefanf $");
43254885Sdumbbell
44254885Sdumbbell#include <sys/types.h>
45254885Sdumbbell#include <stdarg.h>
46254885Sdumbbell#include <netgraph/ng_message.h>
47254885Sdumbbell#include <netgraph/ng_socket.h>
48254885Sdumbbell
49254885Sdumbbell#include "netgraph.h"
50254885Sdumbbell#include "internal.h"
51254885Sdumbbell
52254885Sdumbbell/* The socket node type KLD */
53254885Sdumbbell#define NG_SOCKET_KLD	"ng_socket.ko"
54254885Sdumbbell
55254885Sdumbbell/*
56254885Sdumbbell * Create a socket type node and give it the supplied name.
57254885Sdumbbell * Return data and control sockets corresponding to the node.
58254885Sdumbbell * Returns -1 if error and sets errno.
59254885Sdumbbell */
60254885Sdumbbellint
61254885SdumbbellNgMkSockNode(const char *name, int *csp, int *dsp)
62254885Sdumbbell{
63254885Sdumbbell	char namebuf[NG_NODESIZ];
64254885Sdumbbell	int cs = -1;		/* control socket */
65254885Sdumbbell	int ds = -1;		/* data socket */
66254885Sdumbbell	int errnosv;
67254885Sdumbbell
68254885Sdumbbell	/* Empty name means no name */
69254885Sdumbbell	if (name && *name == 0)
70254885Sdumbbell		name = NULL;
71254885Sdumbbell
72254885Sdumbbell	/* Create control socket; this also creates the netgraph node.
73254885Sdumbbell	   If we get an EPROTONOSUPPORT then the socket node type is
74254885Sdumbbell	   not loaded, so load it and try again. */
75254885Sdumbbell	if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
76254885Sdumbbell		if (errno == EPROTONOSUPPORT) {
77254885Sdumbbell			if (kldload(NG_SOCKET_KLD) < 0) {
78254885Sdumbbell				errnosv = errno;
79254885Sdumbbell				if (_gNgDebugLevel >= 1)
80254885Sdumbbell					NGLOG("can't load %s", NG_SOCKET_KLD);
81254885Sdumbbell				goto errout;
82254885Sdumbbell			}
83254885Sdumbbell			cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
84254885Sdumbbell			if (cs >= 0)
85254885Sdumbbell				goto gotNode;
86254885Sdumbbell		}
87254885Sdumbbell		errnosv = errno;
88254885Sdumbbell		if (_gNgDebugLevel >= 1)
89254885Sdumbbell			NGLOG("socket");
90254885Sdumbbell		goto errout;
91254885Sdumbbell	}
92254885Sdumbbell
93254885SdumbbellgotNode:
94254885Sdumbbell	/* Assign the node the desired name, if any */
95254885Sdumbbell	if (name != NULL) {
96254885Sdumbbell		u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD];
97254885Sdumbbell		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
98254885Sdumbbell
99254885Sdumbbell		/* Assign name */
100254885Sdumbbell		strlcpy(sg->sg_data, name, NG_NODESIZ);
101254885Sdumbbell		sg->sg_family = AF_NETGRAPH;
102254885Sdumbbell		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
103255572Sdumbbell		if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
104254885Sdumbbell			errnosv = errno;
105254885Sdumbbell			if (_gNgDebugLevel >= 1)
106254885Sdumbbell				NGLOG("bind(%s)", sg->sg_data);
107254885Sdumbbell			goto errout;
108254885Sdumbbell		}
109255572Sdumbbell
110254885Sdumbbell		/* Save node name */
111254885Sdumbbell		strlcpy(namebuf, name, sizeof(namebuf));
112255572Sdumbbell	} else if (dsp != NULL) {
113254885Sdumbbell		u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
114254885Sdumbbell		struct ng_mesg *const resp = (struct ng_mesg *) rbuf;
115254885Sdumbbell		struct nodeinfo *const ni = (struct nodeinfo *) resp->data;
116254885Sdumbbell
117254885Sdumbbell		/* Find out the node ID */
118254885Sdumbbell		if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
119254885Sdumbbell		    NGM_NODEINFO, NULL, 0) < 0) {
120254885Sdumbbell			errnosv = errno;
121254885Sdumbbell			if (_gNgDebugLevel >= 1)
122254885Sdumbbell				NGLOG("send nodeinfo");
123254885Sdumbbell			goto errout;
124254885Sdumbbell		}
125255572Sdumbbell		if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) {
126255587Sdumbbell			errnosv = errno;
127254885Sdumbbell			if (_gNgDebugLevel >= 1)
128254885Sdumbbell				NGLOG("recv nodeinfo");
129254885Sdumbbell			goto errout;
130255572Sdumbbell		}
131254885Sdumbbell
132254885Sdumbbell		/* Save node "name" */
133254885Sdumbbell		snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
134254885Sdumbbell	}
135254885Sdumbbell
136254885Sdumbbell	/* Create data socket if desired */
137254885Sdumbbell	if (dsp != NULL) {
138254885Sdumbbell		u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD];
139254885Sdumbbell		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
140254885Sdumbbell
141254885Sdumbbell		/* Create data socket, initially just "floating" */
142254885Sdumbbell		if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
143254885Sdumbbell			errnosv = errno;
144254885Sdumbbell			if (_gNgDebugLevel >= 1)
145254885Sdumbbell				NGLOG("socket");
146254885Sdumbbell			goto errout;
147254885Sdumbbell		}
148254885Sdumbbell
149254885Sdumbbell		/* Associate the data socket with the node */
150254885Sdumbbell		snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
151254885Sdumbbell		sg->sg_family = AF_NETGRAPH;
152254885Sdumbbell		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
153254885Sdumbbell		if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
154254885Sdumbbell			errnosv = errno;
155254885Sdumbbell			if (_gNgDebugLevel >= 1)
156254885Sdumbbell				NGLOG("connect(%s)", sg->sg_data);
157254885Sdumbbell			goto errout;
158254885Sdumbbell		}
159254885Sdumbbell	}
160254885Sdumbbell
161254885Sdumbbell	/* Return the socket(s) */
162254885Sdumbbell	if (csp)
163254885Sdumbbell		*csp = cs;
164254885Sdumbbell	else
165254885Sdumbbell		close(cs);
166254885Sdumbbell	if (dsp)
167254885Sdumbbell		*dsp = ds;
168254885Sdumbbell	return (0);
169254885Sdumbbell
170254885Sdumbbellerrout:
171254885Sdumbbell	/* Failed */
172254885Sdumbbell	if (cs >= 0)
173254885Sdumbbell		close(cs);
174254885Sdumbbell	if (ds >= 0)
175254885Sdumbbell		close(ds);
176254885Sdumbbell	errno = errnosv;
177254885Sdumbbell	return (-1);
178254885Sdumbbell}
179254885Sdumbbell
180254885Sdumbbell/*
181254885Sdumbbell * Assign a globally unique name to a node
182254885Sdumbbell * Returns -1 if error and sets errno.
183254885Sdumbbell */
184254885Sdumbbellint
185254885SdumbbellNgNameNode(int cs, const char *path, const char *fmt, ...)
186254885Sdumbbell{
187254885Sdumbbell	struct ngm_name ngn;
188254885Sdumbbell	va_list args;
189254885Sdumbbell
190254885Sdumbbell	/* Build message arg */
191254885Sdumbbell	va_start(args, fmt);
192254885Sdumbbell	vsnprintf(ngn.name, sizeof(ngn.name), fmt, args);
193254885Sdumbbell	va_end(args);
194254885Sdumbbell
195254885Sdumbbell	/* Send message */
196254885Sdumbbell	if (NgSendMsg(cs, path,
197254885Sdumbbell	    NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) {
198254885Sdumbbell		if (_gNgDebugLevel >= 1)
199254885Sdumbbell			NGLOGX("%s: failed", __func__);
200254885Sdumbbell		return (-1);
201254885Sdumbbell	}
202254885Sdumbbell
203254885Sdumbbell	/* Done */
204254885Sdumbbell	return (0);
205254885Sdumbbell}
206254885Sdumbbell
207254885Sdumbbell/*
208254885Sdumbbell * Read a packet from a data socket
209254885Sdumbbell * Returns -1 if error and sets errno.
210254885Sdumbbell */
211254885Sdumbbellint
212254885SdumbbellNgRecvData(int ds, u_char * buf, size_t len, char *hook)
213254885Sdumbbell{
214254885Sdumbbell	u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD];
215254885Sdumbbell	struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf;
216254885Sdumbbell	int fromlen = sizeof(frombuf);
217254885Sdumbbell	int rtn, errnosv;
218254885Sdumbbell
219254885Sdumbbell	/* Read packet */
220254885Sdumbbell	rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen);
221254885Sdumbbell	if (rtn < 0) {
222254885Sdumbbell		errnosv = errno;
223254885Sdumbbell		if (_gNgDebugLevel >= 1)
224254885Sdumbbell			NGLOG("recvfrom");
225254885Sdumbbell		errno = errnosv;
226254885Sdumbbell		return (-1);
227254885Sdumbbell	}
228254885Sdumbbell
229254885Sdumbbell	/* Copy hook name */
230254885Sdumbbell	if (hook != NULL)
231254885Sdumbbell		strlcpy(hook, from->sg_data, NG_HOOKSIZ);
232254885Sdumbbell
233254885Sdumbbell	/* Debugging */
234254885Sdumbbell	if (_gNgDebugLevel >= 2) {
235254885Sdumbbell		NGLOGX("READ %s from hook \"%s\" (%d bytes)",
236254885Sdumbbell		       rtn ? "PACKET" : "EOF", from->sg_data, rtn);
237254885Sdumbbell		if (_gNgDebugLevel >= 3)
238254885Sdumbbell			_NgDebugBytes(buf, rtn);
239254885Sdumbbell	}
240254885Sdumbbell
241254885Sdumbbell	/* Done */
242254885Sdumbbell	return (rtn);
243254885Sdumbbell}
244254885Sdumbbell
245254885Sdumbbell/*
246254885Sdumbbell * Identical to NgRecvData() except buffer is dynamically allocated.
247254885Sdumbbell */
248254885Sdumbbellint
249254885SdumbbellNgAllocRecvData(int ds, u_char **buf, char *hook)
250254885Sdumbbell{
251254885Sdumbbell	int len;
252254885Sdumbbell	socklen_t optlen;
253254885Sdumbbell
254254885Sdumbbell	optlen = sizeof(len);
255254885Sdumbbell	if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
256254885Sdumbbell	    (*buf = malloc(len)) == NULL)
257254885Sdumbbell		return (-1);
258254885Sdumbbell	if ((len = NgRecvData(ds, *buf, len, hook)) < 0)
259254885Sdumbbell		free(*buf);
260254885Sdumbbell	return (len);
261254885Sdumbbell}
262254885Sdumbbell
263254885Sdumbbell/*
264254885Sdumbbell * Write a packet to a data socket. The packet will be sent
265254885Sdumbbell * out the corresponding node on the specified hook.
266254885Sdumbbell * Returns -1 if error and sets errno.
267254885Sdumbbell */
268254885Sdumbbellint
269254885SdumbbellNgSendData(int ds, const char *hook, const u_char * buf, size_t len)
270254885Sdumbbell{
271254885Sdumbbell	u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD];
272254885Sdumbbell	struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
273254885Sdumbbell	int errnosv;
274254885Sdumbbell
275254885Sdumbbell	/* Set up destination hook */
276254885Sdumbbell	sg->sg_family = AF_NETGRAPH;
277254885Sdumbbell	strlcpy(sg->sg_data, hook, NG_HOOKSIZ);
278254885Sdumbbell	sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
279254885Sdumbbell
280254885Sdumbbell	/* Debugging */
281254885Sdumbbell	if (_gNgDebugLevel >= 2) {
282254885Sdumbbell		NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len);
283254885Sdumbbell		_NgDebugSockaddr(sg);
284254885Sdumbbell		if (_gNgDebugLevel >= 3)
285254885Sdumbbell			_NgDebugBytes(buf, len);
286254885Sdumbbell	}
287254885Sdumbbell
288254885Sdumbbell	/* Send packet */
289254885Sdumbbell	if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
290254885Sdumbbell		errnosv = errno;
291254885Sdumbbell		if (_gNgDebugLevel >= 1)
292254885Sdumbbell			NGLOG("sendto(%s)", sg->sg_data);
293254885Sdumbbell		errno = errnosv;
294254885Sdumbbell		return (-1);
295254885Sdumbbell	}
296254885Sdumbbell
297254885Sdumbbell	/* Done */
298254885Sdumbbell	return (0);
299254885Sdumbbell}
300254885Sdumbbell
301254885Sdumbbell