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