1*86d7f5d3SJohn Marino
2*86d7f5d3SJohn Marino /*
3*86d7f5d3SJohn Marino * msg.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/msg.c,v 1.2.2.3 2001/10/29 18:36:30 archie Exp $
40*86d7f5d3SJohn Marino * $DragonFly: src/lib/libnetgraph/msg.c,v 1.4 2007/06/03 23:41:25 swildner Exp $
41*86d7f5d3SJohn Marino * $Whistle: msg.c,v 1.9 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 /* Next message token value */
53*86d7f5d3SJohn Marino static int gMsgId;
54*86d7f5d3SJohn Marino
55*86d7f5d3SJohn Marino /* For delivering both messages and replies */
56*86d7f5d3SJohn Marino static int NgDeliverMsg(int cs, const char *path,
57*86d7f5d3SJohn Marino const struct ng_mesg *hdr, const void *args, size_t arglen);
58*86d7f5d3SJohn Marino
59*86d7f5d3SJohn Marino /*
60*86d7f5d3SJohn Marino * Send a message to a node using control socket node "cs".
61*86d7f5d3SJohn Marino * Returns -1 if error and sets errno appropriately.
62*86d7f5d3SJohn Marino * If successful, returns the message ID (token) used.
63*86d7f5d3SJohn Marino */
64*86d7f5d3SJohn Marino int
NgSendMsg(int cs,const char * path,int cookie,int cmd,const void * args,size_t arglen)65*86d7f5d3SJohn Marino NgSendMsg(int cs, const char *path,
66*86d7f5d3SJohn Marino int cookie, int cmd, const void *args, size_t arglen)
67*86d7f5d3SJohn Marino {
68*86d7f5d3SJohn Marino struct ng_mesg msg;
69*86d7f5d3SJohn Marino
70*86d7f5d3SJohn Marino /* Prepare message header */
71*86d7f5d3SJohn Marino memset(&msg, 0, sizeof(msg));
72*86d7f5d3SJohn Marino msg.header.version = NG_VERSION;
73*86d7f5d3SJohn Marino msg.header.typecookie = cookie;
74*86d7f5d3SJohn Marino if (++gMsgId < 0)
75*86d7f5d3SJohn Marino gMsgId = 1;
76*86d7f5d3SJohn Marino msg.header.token = gMsgId;
77*86d7f5d3SJohn Marino msg.header.flags = NGF_ORIG;
78*86d7f5d3SJohn Marino msg.header.cmd = cmd;
79*86d7f5d3SJohn Marino snprintf(msg.header.cmdstr, NG_CMDSTRSIZ, "cmd%d", cmd);
80*86d7f5d3SJohn Marino
81*86d7f5d3SJohn Marino /* Deliver message */
82*86d7f5d3SJohn Marino if (NgDeliverMsg(cs, path, &msg, args, arglen) < 0)
83*86d7f5d3SJohn Marino return (-1);
84*86d7f5d3SJohn Marino return (msg.header.token);
85*86d7f5d3SJohn Marino }
86*86d7f5d3SJohn Marino
87*86d7f5d3SJohn Marino /*
88*86d7f5d3SJohn Marino * Send a message given in ASCII format. We first ask the node to translate
89*86d7f5d3SJohn Marino * the command into binary, and then we send the binary.
90*86d7f5d3SJohn Marino */
91*86d7f5d3SJohn Marino int
NgSendAsciiMsg(int cs,const char * path,const char * fmt,...)92*86d7f5d3SJohn Marino NgSendAsciiMsg(int cs, const char *path, const char *fmt, ...)
93*86d7f5d3SJohn Marino {
94*86d7f5d3SJohn Marino const int bufSize = 1024;
95*86d7f5d3SJohn Marino char replybuf[2 * sizeof(struct ng_mesg) + bufSize];
96*86d7f5d3SJohn Marino struct ng_mesg *const reply = (struct ng_mesg *)replybuf;
97*86d7f5d3SJohn Marino struct ng_mesg *const binary = (struct ng_mesg *)reply->data;
98*86d7f5d3SJohn Marino struct ng_mesg *ascii;
99*86d7f5d3SJohn Marino char *buf, *cmd, *args;
100*86d7f5d3SJohn Marino va_list fmtargs;
101*86d7f5d3SJohn Marino
102*86d7f5d3SJohn Marino /* Parse out command and arguments */
103*86d7f5d3SJohn Marino va_start(fmtargs, fmt);
104*86d7f5d3SJohn Marino vasprintf(&buf, fmt, fmtargs);
105*86d7f5d3SJohn Marino va_end(fmtargs);
106*86d7f5d3SJohn Marino if (buf == NULL)
107*86d7f5d3SJohn Marino return (-1);
108*86d7f5d3SJohn Marino
109*86d7f5d3SJohn Marino /* Parse out command, arguments */
110*86d7f5d3SJohn Marino for (cmd = buf; isspace(*cmd); cmd++)
111*86d7f5d3SJohn Marino ;
112*86d7f5d3SJohn Marino for (args = cmd; *args != '\0' && !isspace(*args); args++)
113*86d7f5d3SJohn Marino ;
114*86d7f5d3SJohn Marino if (*args != '\0') {
115*86d7f5d3SJohn Marino while (isspace(*args))
116*86d7f5d3SJohn Marino *args++ = '\0';
117*86d7f5d3SJohn Marino }
118*86d7f5d3SJohn Marino
119*86d7f5d3SJohn Marino /* Get a bigger buffer to hold inner message header plus arg string */
120*86d7f5d3SJohn Marino if ((ascii = malloc(sizeof(struct ng_mesg)
121*86d7f5d3SJohn Marino + strlen(args) + 1)) == NULL) {
122*86d7f5d3SJohn Marino free(buf);
123*86d7f5d3SJohn Marino return (-1);
124*86d7f5d3SJohn Marino }
125*86d7f5d3SJohn Marino memset(ascii, 0, sizeof(*ascii));
126*86d7f5d3SJohn Marino
127*86d7f5d3SJohn Marino /* Build inner header (only need cmdstr, arglen, and data fields) */
128*86d7f5d3SJohn Marino strncpy(ascii->header.cmdstr, cmd, sizeof(ascii->header.cmdstr) - 1);
129*86d7f5d3SJohn Marino strcpy(ascii->data, args);
130*86d7f5d3SJohn Marino ascii->header.arglen = strlen(ascii->data) + 1;
131*86d7f5d3SJohn Marino free(buf);
132*86d7f5d3SJohn Marino
133*86d7f5d3SJohn Marino /* Send node a request to convert ASCII to binary */
134*86d7f5d3SJohn Marino if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, NGM_ASCII2BINARY,
135*86d7f5d3SJohn Marino (u_char *)ascii, sizeof(*ascii) + ascii->header.arglen) < 0)
136*86d7f5d3SJohn Marino return (-1);
137*86d7f5d3SJohn Marino
138*86d7f5d3SJohn Marino /* Get reply */
139*86d7f5d3SJohn Marino if (NgRecvMsg(cs, reply, sizeof(replybuf), NULL) < 0)
140*86d7f5d3SJohn Marino return (-1);
141*86d7f5d3SJohn Marino
142*86d7f5d3SJohn Marino /* Now send binary version */
143*86d7f5d3SJohn Marino if (++gMsgId < 0)
144*86d7f5d3SJohn Marino gMsgId = 1;
145*86d7f5d3SJohn Marino binary->header.token = gMsgId;
146*86d7f5d3SJohn Marino if (NgDeliverMsg(cs,
147*86d7f5d3SJohn Marino path, binary, binary->data, binary->header.arglen) < 0)
148*86d7f5d3SJohn Marino return (-1);
149*86d7f5d3SJohn Marino return (binary->header.token);
150*86d7f5d3SJohn Marino }
151*86d7f5d3SJohn Marino
152*86d7f5d3SJohn Marino /*
153*86d7f5d3SJohn Marino * Send a message that is a reply to a previously received message.
154*86d7f5d3SJohn Marino * Returns -1 and sets errno on error, otherwise returns zero.
155*86d7f5d3SJohn Marino */
156*86d7f5d3SJohn Marino int
NgSendReplyMsg(int cs,const char * path,const struct ng_mesg * msg,const void * args,size_t arglen)157*86d7f5d3SJohn Marino NgSendReplyMsg(int cs, const char *path,
158*86d7f5d3SJohn Marino const struct ng_mesg *msg, const void *args, size_t arglen)
159*86d7f5d3SJohn Marino {
160*86d7f5d3SJohn Marino struct ng_mesg rep;
161*86d7f5d3SJohn Marino
162*86d7f5d3SJohn Marino /* Prepare message header */
163*86d7f5d3SJohn Marino rep = *msg;
164*86d7f5d3SJohn Marino rep.header.flags = NGF_RESP;
165*86d7f5d3SJohn Marino
166*86d7f5d3SJohn Marino /* Deliver message */
167*86d7f5d3SJohn Marino return (NgDeliverMsg(cs, path, &rep, args, arglen));
168*86d7f5d3SJohn Marino }
169*86d7f5d3SJohn Marino
170*86d7f5d3SJohn Marino /*
171*86d7f5d3SJohn Marino * Send a message to a node using control socket node "cs".
172*86d7f5d3SJohn Marino * Returns -1 if error and sets errno appropriately, otherwise zero.
173*86d7f5d3SJohn Marino */
174*86d7f5d3SJohn Marino static int
NgDeliverMsg(int cs,const char * path,const struct ng_mesg * hdr,const void * args,size_t arglen)175*86d7f5d3SJohn Marino NgDeliverMsg(int cs, const char *path,
176*86d7f5d3SJohn Marino const struct ng_mesg *hdr, const void *args, size_t arglen)
177*86d7f5d3SJohn Marino {
178*86d7f5d3SJohn Marino u_char sgbuf[NG_PATHSIZ + 2];
179*86d7f5d3SJohn Marino struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
180*86d7f5d3SJohn Marino u_char *buf = NULL;
181*86d7f5d3SJohn Marino struct ng_mesg *msg;
182*86d7f5d3SJohn Marino int errnosv = 0;
183*86d7f5d3SJohn Marino int rtn = 0;
184*86d7f5d3SJohn Marino
185*86d7f5d3SJohn Marino /* Sanity check */
186*86d7f5d3SJohn Marino if (args == NULL)
187*86d7f5d3SJohn Marino arglen = 0;
188*86d7f5d3SJohn Marino
189*86d7f5d3SJohn Marino /* Get buffer */
190*86d7f5d3SJohn Marino if ((buf = malloc(sizeof(*msg) + arglen)) == NULL) {
191*86d7f5d3SJohn Marino errnosv = errno;
192*86d7f5d3SJohn Marino if (_gNgDebugLevel >= 1)
193*86d7f5d3SJohn Marino NGLOG("malloc");
194*86d7f5d3SJohn Marino rtn = -1;
195*86d7f5d3SJohn Marino goto done;
196*86d7f5d3SJohn Marino }
197*86d7f5d3SJohn Marino msg = (struct ng_mesg *) buf;
198*86d7f5d3SJohn Marino
199*86d7f5d3SJohn Marino /* Finalize message */
200*86d7f5d3SJohn Marino *msg = *hdr;
201*86d7f5d3SJohn Marino msg->header.arglen = arglen;
202*86d7f5d3SJohn Marino memcpy(msg->data, args, arglen);
203*86d7f5d3SJohn Marino
204*86d7f5d3SJohn Marino /* Prepare socket address */
205*86d7f5d3SJohn Marino sg->sg_family = AF_NETGRAPH;
206*86d7f5d3SJohn Marino snprintf(sg->sg_data, NG_PATHSIZ, "%s", path);
207*86d7f5d3SJohn Marino sg->sg_len = strlen(sg->sg_data) + 3;
208*86d7f5d3SJohn Marino
209*86d7f5d3SJohn Marino /* Debugging */
210*86d7f5d3SJohn Marino if (_gNgDebugLevel >= 2) {
211*86d7f5d3SJohn Marino NGLOGX("SENDING %s:",
212*86d7f5d3SJohn Marino (msg->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE");
213*86d7f5d3SJohn Marino _NgDebugSockaddr(sg);
214*86d7f5d3SJohn Marino _NgDebugMsg(msg, sg->sg_data);
215*86d7f5d3SJohn Marino }
216*86d7f5d3SJohn Marino
217*86d7f5d3SJohn Marino /* Send it */
218*86d7f5d3SJohn Marino if (sendto(cs, msg, sizeof(*msg) + arglen,
219*86d7f5d3SJohn Marino 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
220*86d7f5d3SJohn Marino errnosv = errno;
221*86d7f5d3SJohn Marino if (_gNgDebugLevel >= 1)
222*86d7f5d3SJohn Marino NGLOG("sendto(%s)", sg->sg_data);
223*86d7f5d3SJohn Marino rtn = -1;
224*86d7f5d3SJohn Marino goto done;
225*86d7f5d3SJohn Marino }
226*86d7f5d3SJohn Marino
227*86d7f5d3SJohn Marino done:
228*86d7f5d3SJohn Marino /* Done */
229*86d7f5d3SJohn Marino free(buf); /* OK if buf is NULL */
230*86d7f5d3SJohn Marino errno = errnosv;
231*86d7f5d3SJohn Marino return (rtn);
232*86d7f5d3SJohn Marino }
233*86d7f5d3SJohn Marino
234*86d7f5d3SJohn Marino /*
235*86d7f5d3SJohn Marino * Receive a control message.
236*86d7f5d3SJohn Marino *
237*86d7f5d3SJohn Marino * On error, this returns -1 and sets errno.
238*86d7f5d3SJohn Marino * Otherwise, it returns the length of the received reply.
239*86d7f5d3SJohn Marino */
240*86d7f5d3SJohn Marino int
NgRecvMsg(int cs,struct ng_mesg * rep,size_t replen,char * path)241*86d7f5d3SJohn Marino NgRecvMsg(int cs, struct ng_mesg *rep, size_t replen, char *path)
242*86d7f5d3SJohn Marino {
243*86d7f5d3SJohn Marino u_char sgbuf[NG_PATHSIZ - 1 + sizeof(struct sockaddr_ng)];
244*86d7f5d3SJohn Marino struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
245*86d7f5d3SJohn Marino int len, sglen = sizeof(sgbuf);
246*86d7f5d3SJohn Marino int errnosv;
247*86d7f5d3SJohn Marino
248*86d7f5d3SJohn Marino /* Read reply */
249*86d7f5d3SJohn Marino len = recvfrom(cs, rep, replen, 0, (struct sockaddr *) sg, &sglen);
250*86d7f5d3SJohn Marino if (len < 0) {
251*86d7f5d3SJohn Marino errnosv = errno;
252*86d7f5d3SJohn Marino if (_gNgDebugLevel >= 1)
253*86d7f5d3SJohn Marino NGLOG("recvfrom");
254*86d7f5d3SJohn Marino goto errout;
255*86d7f5d3SJohn Marino }
256*86d7f5d3SJohn Marino if (path != NULL)
257*86d7f5d3SJohn Marino snprintf(path, NG_PATHSIZ, "%s", sg->sg_data);
258*86d7f5d3SJohn Marino
259*86d7f5d3SJohn Marino /* Debugging */
260*86d7f5d3SJohn Marino if (_gNgDebugLevel >= 2) {
261*86d7f5d3SJohn Marino NGLOGX("RECEIVED %s:",
262*86d7f5d3SJohn Marino (rep->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE");
263*86d7f5d3SJohn Marino _NgDebugSockaddr(sg);
264*86d7f5d3SJohn Marino _NgDebugMsg(rep, sg->sg_data);
265*86d7f5d3SJohn Marino }
266*86d7f5d3SJohn Marino
267*86d7f5d3SJohn Marino /* Done */
268*86d7f5d3SJohn Marino return (len);
269*86d7f5d3SJohn Marino
270*86d7f5d3SJohn Marino errout:
271*86d7f5d3SJohn Marino errno = errnosv;
272*86d7f5d3SJohn Marino return (-1);
273*86d7f5d3SJohn Marino }
274*86d7f5d3SJohn Marino
275*86d7f5d3SJohn Marino /*
276*86d7f5d3SJohn Marino * Receive a control message and convert the arguments to ASCII
277*86d7f5d3SJohn Marino */
278*86d7f5d3SJohn Marino int
NgRecvAsciiMsg(int cs,struct ng_mesg * reply,size_t replen,char * path)279*86d7f5d3SJohn Marino NgRecvAsciiMsg(int cs, struct ng_mesg *reply, size_t replen, char *path)
280*86d7f5d3SJohn Marino {
281*86d7f5d3SJohn Marino struct ng_mesg *msg, *ascii;
282*86d7f5d3SJohn Marino int bufSize, errnosv;
283*86d7f5d3SJohn Marino u_char *buf;
284*86d7f5d3SJohn Marino
285*86d7f5d3SJohn Marino /* Allocate buffer */
286*86d7f5d3SJohn Marino bufSize = 2 * sizeof(*reply) + replen;
287*86d7f5d3SJohn Marino if ((buf = malloc(bufSize)) == NULL)
288*86d7f5d3SJohn Marino return (-1);
289*86d7f5d3SJohn Marino msg = (struct ng_mesg *)buf;
290*86d7f5d3SJohn Marino ascii = (struct ng_mesg *)msg->data;
291*86d7f5d3SJohn Marino
292*86d7f5d3SJohn Marino /* Get binary message */
293*86d7f5d3SJohn Marino if (NgRecvMsg(cs, msg, bufSize, path) < 0)
294*86d7f5d3SJohn Marino goto fail;
295*86d7f5d3SJohn Marino memcpy(reply, msg, sizeof(*msg));
296*86d7f5d3SJohn Marino
297*86d7f5d3SJohn Marino /* Ask originating node to convert the arguments to ASCII */
298*86d7f5d3SJohn Marino if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE,
299*86d7f5d3SJohn Marino NGM_BINARY2ASCII, msg, sizeof(*msg) + msg->header.arglen) < 0)
300*86d7f5d3SJohn Marino goto fail;
301*86d7f5d3SJohn Marino if (NgRecvMsg(cs, msg, bufSize, NULL) < 0)
302*86d7f5d3SJohn Marino goto fail;
303*86d7f5d3SJohn Marino
304*86d7f5d3SJohn Marino /* Copy result to client buffer */
305*86d7f5d3SJohn Marino if (sizeof(*ascii) + ascii->header.arglen > replen) {
306*86d7f5d3SJohn Marino errno = ERANGE;
307*86d7f5d3SJohn Marino fail:
308*86d7f5d3SJohn Marino errnosv = errno;
309*86d7f5d3SJohn Marino free(buf);
310*86d7f5d3SJohn Marino errno = errnosv;
311*86d7f5d3SJohn Marino return (-1);
312*86d7f5d3SJohn Marino }
313*86d7f5d3SJohn Marino strncpy(reply->data, ascii->data, ascii->header.arglen);
314*86d7f5d3SJohn Marino
315*86d7f5d3SJohn Marino /* Done */
316*86d7f5d3SJohn Marino free(buf);
317*86d7f5d3SJohn Marino return (0);
318*86d7f5d3SJohn Marino }
319*86d7f5d3SJohn Marino
320