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