xref: /dragonfly/lib/libnetgraph/sock.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino 
2*86d7f5d3SJohn Marino /*
3*86d7f5d3SJohn Marino  * sock.c
4*86d7f5d3SJohn Marino  *
5*86d7f5d3SJohn Marino  * Copyright (c) 1996-1999 Whistle Communications, Inc.
6*86d7f5d3SJohn Marino  * All rights reserved.
7*86d7f5d3SJohn Marino  *
8*86d7f5d3SJohn Marino  * Subject to the following obligations and disclaimer of warranty, use and
9*86d7f5d3SJohn Marino  * redistribution of this software, in source or object code forms, with or
10*86d7f5d3SJohn Marino  * without modifications are expressly permitted by Whistle Communications;
11*86d7f5d3SJohn Marino  * provided, however, that:
12*86d7f5d3SJohn Marino  * 1. Any and all reproductions of the source or object code must include the
13*86d7f5d3SJohn Marino  *    copyright notice above and the following disclaimer of warranties; and
14*86d7f5d3SJohn Marino  * 2. No rights are granted, in any manner or form, to use Whistle
15*86d7f5d3SJohn Marino  *    Communications, Inc. trademarks, including the mark "WHISTLE
16*86d7f5d3SJohn Marino  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17*86d7f5d3SJohn Marino  *    such appears in the above copyright notice or in the software.
18*86d7f5d3SJohn Marino  *
19*86d7f5d3SJohn Marino  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20*86d7f5d3SJohn Marino  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21*86d7f5d3SJohn Marino  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22*86d7f5d3SJohn Marino  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23*86d7f5d3SJohn Marino  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24*86d7f5d3SJohn Marino  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25*86d7f5d3SJohn Marino  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26*86d7f5d3SJohn Marino  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27*86d7f5d3SJohn Marino  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28*86d7f5d3SJohn Marino  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29*86d7f5d3SJohn Marino  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30*86d7f5d3SJohn Marino  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31*86d7f5d3SJohn Marino  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32*86d7f5d3SJohn Marino  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33*86d7f5d3SJohn Marino  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34*86d7f5d3SJohn Marino  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35*86d7f5d3SJohn Marino  * OF SUCH DAMAGE.
36*86d7f5d3SJohn Marino  *
37*86d7f5d3SJohn Marino  * Author: Archie Cobbs <archie@whistle.com>
38*86d7f5d3SJohn Marino  *
39*86d7f5d3SJohn Marino  * $FreeBSD: src/lib/libnetgraph/sock.c,v 1.2 2000/01/28 00:48:27 archie Exp $
40*86d7f5d3SJohn Marino  * $DragonFly: src/lib/libnetgraph/sock.c,v 1.5 2007/06/03 23:41:25 swildner Exp $
41*86d7f5d3SJohn Marino  * $Whistle: sock.c,v 1.12 1999/01/20 00:57:23 archie Exp $
42*86d7f5d3SJohn Marino  */
43*86d7f5d3SJohn Marino 
44*86d7f5d3SJohn Marino #include <sys/types.h>
45*86d7f5d3SJohn Marino #include <stdarg.h>
46*86d7f5d3SJohn Marino #include <netgraph/ng_message.h>
47*86d7f5d3SJohn Marino #include <netgraph/socket/ng_socket.h>
48*86d7f5d3SJohn Marino 
49*86d7f5d3SJohn Marino #include "netgraph.h"
50*86d7f5d3SJohn Marino #include "internal.h"
51*86d7f5d3SJohn Marino 
52*86d7f5d3SJohn Marino /* The socket node type KLD */
53*86d7f5d3SJohn Marino #define NG_SOCKET_KLD	"ng_socket.ko"
54*86d7f5d3SJohn Marino 
55*86d7f5d3SJohn Marino /*
56*86d7f5d3SJohn Marino  * Create a socket type node and give it the supplied name.
57*86d7f5d3SJohn Marino  * Return data and control sockets corresponding to the node.
58*86d7f5d3SJohn Marino  * Returns -1 if error and sets errno.
59*86d7f5d3SJohn Marino  */
60*86d7f5d3SJohn Marino int
NgMkSockNode(const char * name,int * csp,int * dsp)61*86d7f5d3SJohn Marino NgMkSockNode(const char *name, int *csp, int *dsp)
62*86d7f5d3SJohn Marino {
63*86d7f5d3SJohn Marino 	char namebuf[NG_NODESIZ];
64*86d7f5d3SJohn Marino 	int cs = -1;		/* control socket */
65*86d7f5d3SJohn Marino 	int ds = -1;		/* data socket */
66*86d7f5d3SJohn Marino 	int errnosv;
67*86d7f5d3SJohn Marino 
68*86d7f5d3SJohn Marino 	/* Empty name means no name */
69*86d7f5d3SJohn Marino 	if (name && *name == 0)
70*86d7f5d3SJohn Marino 		name = NULL;
71*86d7f5d3SJohn Marino 
72*86d7f5d3SJohn Marino 	/* Create control socket; this also creates the netgraph node.
73*86d7f5d3SJohn Marino 	   If we get a EPROTONOSUPPORT then the socket node type is
74*86d7f5d3SJohn Marino 	   not loaded, so load it and try again. */
75*86d7f5d3SJohn Marino 	if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
76*86d7f5d3SJohn Marino 		if (errno == EPROTONOSUPPORT) {
77*86d7f5d3SJohn Marino 			if (kldload(NG_SOCKET_KLD) < 0) {
78*86d7f5d3SJohn Marino 				errnosv = errno;
79*86d7f5d3SJohn Marino 				if (_gNgDebugLevel >= 1)
80*86d7f5d3SJohn Marino 					NGLOG("can't load %s", NG_SOCKET_KLD);
81*86d7f5d3SJohn Marino 				goto errout;
82*86d7f5d3SJohn Marino 			}
83*86d7f5d3SJohn Marino 			cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
84*86d7f5d3SJohn Marino 			if (cs >= 0)
85*86d7f5d3SJohn Marino 				goto gotNode;
86*86d7f5d3SJohn Marino 		}
87*86d7f5d3SJohn Marino 		errnosv = errno;
88*86d7f5d3SJohn Marino 		if (_gNgDebugLevel >= 1)
89*86d7f5d3SJohn Marino 			NGLOG("socket");
90*86d7f5d3SJohn Marino 		goto errout;
91*86d7f5d3SJohn Marino 	}
92*86d7f5d3SJohn Marino 
93*86d7f5d3SJohn Marino gotNode:
94*86d7f5d3SJohn Marino 	/* Assign the node the desired name, if any */
95*86d7f5d3SJohn Marino 	if (name != NULL) {
96*86d7f5d3SJohn Marino 		u_char sbuf[NG_NODESIZ + 2];
97*86d7f5d3SJohn Marino 		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
98*86d7f5d3SJohn Marino 
99*86d7f5d3SJohn Marino 		/* Assign name */
100*86d7f5d3SJohn Marino 		snprintf(sg->sg_data, NG_NODESIZ, "%s", name);
101*86d7f5d3SJohn Marino 		sg->sg_family = AF_NETGRAPH;
102*86d7f5d3SJohn Marino 		sg->sg_len = strlen(sg->sg_data) + 3;
103*86d7f5d3SJohn Marino 		if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
104*86d7f5d3SJohn Marino 			errnosv = errno;
105*86d7f5d3SJohn Marino 			if (_gNgDebugLevel >= 1)
106*86d7f5d3SJohn Marino 				NGLOG("bind(%s)", sg->sg_data);
107*86d7f5d3SJohn Marino 			goto errout;
108*86d7f5d3SJohn Marino 		}
109*86d7f5d3SJohn Marino 
110*86d7f5d3SJohn Marino 		/* Save node name */
111*86d7f5d3SJohn Marino 		snprintf(namebuf, sizeof(namebuf), "%s", name);
112*86d7f5d3SJohn Marino 	} else if (dsp != NULL) {
113*86d7f5d3SJohn Marino 		u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
114*86d7f5d3SJohn Marino 		struct ng_mesg *const resp = (struct ng_mesg *) rbuf;
115*86d7f5d3SJohn Marino 		struct nodeinfo *const ni = (struct nodeinfo *) resp->data;
116*86d7f5d3SJohn Marino 
117*86d7f5d3SJohn Marino 		/* Find out the node ID */
118*86d7f5d3SJohn Marino 		if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
119*86d7f5d3SJohn Marino 		    NGM_NODEINFO, NULL, 0) < 0) {
120*86d7f5d3SJohn Marino 			errnosv = errno;
121*86d7f5d3SJohn Marino 			if (_gNgDebugLevel >= 1)
122*86d7f5d3SJohn Marino 				NGLOG("send nodeinfo");
123*86d7f5d3SJohn Marino 			goto errout;
124*86d7f5d3SJohn Marino 		}
125*86d7f5d3SJohn Marino 		if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) {
126*86d7f5d3SJohn Marino 			errnosv = errno;
127*86d7f5d3SJohn Marino 			if (_gNgDebugLevel >= 1)
128*86d7f5d3SJohn Marino 				NGLOG("recv nodeinfo");
129*86d7f5d3SJohn Marino 			goto errout;
130*86d7f5d3SJohn Marino 		}
131*86d7f5d3SJohn Marino 
132*86d7f5d3SJohn Marino 		/* Save node "name" */
133*86d7f5d3SJohn Marino 		snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
134*86d7f5d3SJohn Marino 	}
135*86d7f5d3SJohn Marino 
136*86d7f5d3SJohn Marino 	/* Create data socket if desired */
137*86d7f5d3SJohn Marino 	if (dsp != NULL) {
138*86d7f5d3SJohn Marino 		u_char sbuf[NG_NODESIZ + 3];
139*86d7f5d3SJohn Marino 		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
140*86d7f5d3SJohn Marino 
141*86d7f5d3SJohn Marino 		/* Create data socket, initially just "floating" */
142*86d7f5d3SJohn Marino 		if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
143*86d7f5d3SJohn Marino 			errnosv = errno;
144*86d7f5d3SJohn Marino 			if (_gNgDebugLevel >= 1)
145*86d7f5d3SJohn Marino 				NGLOG("socket");
146*86d7f5d3SJohn Marino 			goto errout;
147*86d7f5d3SJohn Marino 		}
148*86d7f5d3SJohn Marino 
149*86d7f5d3SJohn Marino 		/* Associate the data socket with the node */
150*86d7f5d3SJohn Marino 		snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
151*86d7f5d3SJohn Marino 		sg->sg_family = AF_NETGRAPH;
152*86d7f5d3SJohn Marino 		sg->sg_len = strlen(sg->sg_data) + 3;
153*86d7f5d3SJohn Marino 		if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
154*86d7f5d3SJohn Marino 			errnosv = errno;
155*86d7f5d3SJohn Marino 			if (_gNgDebugLevel >= 1)
156*86d7f5d3SJohn Marino 				NGLOG("connect(%s)", sg->sg_data);
157*86d7f5d3SJohn Marino 			goto errout;
158*86d7f5d3SJohn Marino 		}
159*86d7f5d3SJohn Marino 	}
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino 	/* Return the socket(s) */
162*86d7f5d3SJohn Marino 	if (csp)
163*86d7f5d3SJohn Marino 		*csp = cs;
164*86d7f5d3SJohn Marino 	else
165*86d7f5d3SJohn Marino 		close(cs);
166*86d7f5d3SJohn Marino 	if (dsp)
167*86d7f5d3SJohn Marino 		*dsp = ds;
168*86d7f5d3SJohn Marino 	return (0);
169*86d7f5d3SJohn Marino 
170*86d7f5d3SJohn Marino errout:
171*86d7f5d3SJohn Marino 	/* Failed */
172*86d7f5d3SJohn Marino 	if (cs >= 0)
173*86d7f5d3SJohn Marino 		close(cs);
174*86d7f5d3SJohn Marino 	if (ds >= 0)
175*86d7f5d3SJohn Marino 		close(ds);
176*86d7f5d3SJohn Marino 	errno = errnosv;
177*86d7f5d3SJohn Marino 	return (-1);
178*86d7f5d3SJohn Marino }
179*86d7f5d3SJohn Marino 
180*86d7f5d3SJohn Marino /*
181*86d7f5d3SJohn Marino  * Assign a globally unique name to a node
182*86d7f5d3SJohn Marino  * Returns -1 if error and sets errno.
183*86d7f5d3SJohn Marino  */
184*86d7f5d3SJohn Marino int
NgNameNode(int cs,const char * path,const char * fmt,...)185*86d7f5d3SJohn Marino NgNameNode(int cs, const char *path, const char *fmt, ...)
186*86d7f5d3SJohn Marino {
187*86d7f5d3SJohn Marino 	struct ngm_name ngn;
188*86d7f5d3SJohn Marino 	va_list args;
189*86d7f5d3SJohn Marino 
190*86d7f5d3SJohn Marino 	/* Build message arg */
191*86d7f5d3SJohn Marino 	va_start(args, fmt);
192*86d7f5d3SJohn Marino 	vsnprintf(ngn.name, sizeof(ngn.name), fmt, args);
193*86d7f5d3SJohn Marino 	va_end(args);
194*86d7f5d3SJohn Marino 
195*86d7f5d3SJohn Marino 	/* Send message */
196*86d7f5d3SJohn Marino 	if (NgSendMsg(cs, path,
197*86d7f5d3SJohn Marino 	    NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) {
198*86d7f5d3SJohn Marino 		if (_gNgDebugLevel >= 1)
199*86d7f5d3SJohn Marino 			NGLOGX("%s: failed", __func__);
200*86d7f5d3SJohn Marino 		return (-1);
201*86d7f5d3SJohn Marino 	}
202*86d7f5d3SJohn Marino 
203*86d7f5d3SJohn Marino 	/* Done */
204*86d7f5d3SJohn Marino 	return (0);
205*86d7f5d3SJohn Marino }
206*86d7f5d3SJohn Marino 
207*86d7f5d3SJohn Marino /*
208*86d7f5d3SJohn Marino  * Read a packet from a data socket
209*86d7f5d3SJohn Marino  * Returns -1 if error and sets errno.
210*86d7f5d3SJohn Marino  */
211*86d7f5d3SJohn Marino int
NgRecvData(int ds,u_char * buf,size_t len,char * hook)212*86d7f5d3SJohn Marino NgRecvData(int ds, u_char * buf, size_t len, char *hook)
213*86d7f5d3SJohn Marino {
214*86d7f5d3SJohn Marino 	u_char frombuf[NG_HOOKSIZ - 1 + sizeof(struct sockaddr_ng)];
215*86d7f5d3SJohn Marino 	struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf;
216*86d7f5d3SJohn Marino 	int fromlen = sizeof(frombuf);
217*86d7f5d3SJohn Marino 	int rtn, errnosv;
218*86d7f5d3SJohn Marino 
219*86d7f5d3SJohn Marino 	/* Read packet */
220*86d7f5d3SJohn Marino 	rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen);
221*86d7f5d3SJohn Marino 	if (rtn < 0) {
222*86d7f5d3SJohn Marino 		errnosv = errno;
223*86d7f5d3SJohn Marino 		if (_gNgDebugLevel >= 1)
224*86d7f5d3SJohn Marino 			NGLOG("recvfrom");
225*86d7f5d3SJohn Marino 		errno = errnosv;
226*86d7f5d3SJohn Marino 		return (-1);
227*86d7f5d3SJohn Marino 	}
228*86d7f5d3SJohn Marino 
229*86d7f5d3SJohn Marino 	/* Copy hook name */
230*86d7f5d3SJohn Marino 	if (hook != NULL)
231*86d7f5d3SJohn Marino 		snprintf(hook, NG_HOOKSIZ, "%s", from->sg_data);
232*86d7f5d3SJohn Marino 
233*86d7f5d3SJohn Marino 	/* Debugging */
234*86d7f5d3SJohn Marino 	if (_gNgDebugLevel >= 2) {
235*86d7f5d3SJohn Marino 		NGLOGX("READ %s from hook \"%s\" (%d bytes)",
236*86d7f5d3SJohn Marino 		       rtn ? "PACKET" : "EOF", from->sg_data, rtn);
237*86d7f5d3SJohn Marino 		if (_gNgDebugLevel >= 3)
238*86d7f5d3SJohn Marino 			_NgDebugBytes(buf, rtn);
239*86d7f5d3SJohn Marino 	}
240*86d7f5d3SJohn Marino 
241*86d7f5d3SJohn Marino 	/* Done */
242*86d7f5d3SJohn Marino 	return (rtn);
243*86d7f5d3SJohn Marino }
244*86d7f5d3SJohn Marino 
245*86d7f5d3SJohn Marino /*
246*86d7f5d3SJohn Marino  * Write a packet to a data socket. The packet will be sent
247*86d7f5d3SJohn Marino  * out the corresponding node on the specified hook.
248*86d7f5d3SJohn Marino  * Returns -1 if error and sets errno.
249*86d7f5d3SJohn Marino  */
250*86d7f5d3SJohn Marino int
NgSendData(int ds,const char * hook,const u_char * buf,size_t len)251*86d7f5d3SJohn Marino NgSendData(int ds, const char *hook, const u_char * buf, size_t len)
252*86d7f5d3SJohn Marino {
253*86d7f5d3SJohn Marino 	u_char sgbuf[NG_HOOKSIZ - 1 + sizeof(struct sockaddr_ng)];
254*86d7f5d3SJohn Marino 	struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
255*86d7f5d3SJohn Marino 	int errnosv;
256*86d7f5d3SJohn Marino 
257*86d7f5d3SJohn Marino 	/* Set up destination hook */
258*86d7f5d3SJohn Marino 	sg->sg_family = AF_NETGRAPH;
259*86d7f5d3SJohn Marino 	snprintf(sg->sg_data, NG_HOOKSIZ, "%s", hook);
260*86d7f5d3SJohn Marino 	sg->sg_len = strlen(sg->sg_data) + 3;
261*86d7f5d3SJohn Marino 
262*86d7f5d3SJohn Marino 	/* Debugging */
263*86d7f5d3SJohn Marino 	if (_gNgDebugLevel >= 2) {
264*86d7f5d3SJohn Marino 		NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len);
265*86d7f5d3SJohn Marino 		_NgDebugSockaddr(sg);
266*86d7f5d3SJohn Marino 		if (_gNgDebugLevel >= 3)
267*86d7f5d3SJohn Marino 			_NgDebugBytes(buf, len);
268*86d7f5d3SJohn Marino 	}
269*86d7f5d3SJohn Marino 
270*86d7f5d3SJohn Marino 	/* Send packet */
271*86d7f5d3SJohn Marino 	if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
272*86d7f5d3SJohn Marino 		errnosv = errno;
273*86d7f5d3SJohn Marino 		if (_gNgDebugLevel >= 1)
274*86d7f5d3SJohn Marino 			NGLOG("sendto(%s)", sg->sg_data);
275*86d7f5d3SJohn Marino 		errno = errnosv;
276*86d7f5d3SJohn Marino 		return (-1);
277*86d7f5d3SJohn Marino 	}
278*86d7f5d3SJohn Marino 
279*86d7f5d3SJohn Marino 	/* Done */
280*86d7f5d3SJohn Marino 	return (0);
281*86d7f5d3SJohn Marino }
282*86d7f5d3SJohn Marino 
283