152419Sjulian/* 252419Sjulian * msg.c 352419Sjulian * 452419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 552419Sjulian * All rights reserved. 652419Sjulian * 752419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 852419Sjulian * redistribution of this software, in source or object code forms, with or 952419Sjulian * without modifications are expressly permitted by Whistle Communications; 1052419Sjulian * provided, however, that: 1152419Sjulian * 1. Any and all reproductions of the source or object code must include the 1252419Sjulian * copyright notice above and the following disclaimer of warranties; and 1352419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1452419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1552419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1652419Sjulian * such appears in the above copyright notice or in the software. 1752419Sjulian * 1852419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 1952419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2052419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2152419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2252419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2352419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2452419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2552419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2652419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2752419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2852419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 2952419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3052419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3152419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3252419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3352419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3452419Sjulian * OF SUCH DAMAGE. 3552419Sjulian * 3652419Sjulian * Author: Archie Cobbs <archie@whistle.com> 3752419Sjulian * 3852419Sjulian * $Whistle: msg.c,v 1.9 1999/01/20 00:57:23 archie Exp $ 3952419Sjulian */ 4052419Sjulian 4184215Sdillon#include <sys/cdefs.h> 4284215Sdillon__FBSDID("$FreeBSD: releng/11.0/lib/libnetgraph/msg.c 248159 2013-03-11 13:05:11Z glebius $"); 4384215Sdillon 4452419Sjulian#include <sys/types.h> 45163469Sglebius#include <sys/socket.h> 4652419Sjulian#include <stdarg.h> 4752419Sjulian#include <netgraph/ng_message.h> 4852419Sjulian#include <netgraph/ng_socket.h> 4952419Sjulian 5052419Sjulian#include "netgraph.h" 5152419Sjulian#include "internal.h" 5252419Sjulian 5352419Sjulian/* Next message token value */ 5452419Sjulianstatic int gMsgId; 5552419Sjulian 5652419Sjulian/* For delivering both messages and replies */ 5752419Sjulianstatic int NgDeliverMsg(int cs, const char *path, 5852419Sjulian const struct ng_mesg *hdr, const void *args, size_t arglen); 5952419Sjulian 6052419Sjulian/* 6152419Sjulian * Send a message to a node using control socket node "cs". 6252419Sjulian * Returns -1 if error and sets errno appropriately. 6352419Sjulian * If successful, returns the message ID (token) used. 6452419Sjulian */ 6552419Sjulianint 6652419SjulianNgSendMsg(int cs, const char *path, 6752419Sjulian int cookie, int cmd, const void *args, size_t arglen) 6852419Sjulian{ 6952419Sjulian struct ng_mesg msg; 7052419Sjulian 7152419Sjulian /* Prepare message header */ 7252419Sjulian memset(&msg, 0, sizeof(msg)); 7352419Sjulian msg.header.version = NG_VERSION; 7452419Sjulian msg.header.typecookie = cookie; 7561922Sarchie if (++gMsgId < 0) 7661922Sarchie gMsgId = 1; 7761922Sarchie msg.header.token = gMsgId; 7852419Sjulian msg.header.flags = NGF_ORIG; 7952419Sjulian msg.header.cmd = cmd; 80145546Smux snprintf((char *)msg.header.cmdstr, NG_CMDSTRSIZ, "cmd%d", cmd); 8152419Sjulian 8252419Sjulian /* Deliver message */ 8352419Sjulian if (NgDeliverMsg(cs, path, &msg, args, arglen) < 0) 8452419Sjulian return (-1); 8585456Sarchie return (msg.header.token); 8652419Sjulian} 8752419Sjulian 8852419Sjulian/* 8953913Sarchie * Send a message given in ASCII format. We first ask the node to translate 9053913Sarchie * the command into binary, and then we send the binary. 9153913Sarchie */ 9253913Sarchieint 9353913SarchieNgSendAsciiMsg(int cs, const char *path, const char *fmt, ...) 9453913Sarchie{ 95125113Sru struct ng_mesg *reply, *binary, *ascii; 9653913Sarchie char *buf, *cmd, *args; 9753913Sarchie va_list fmtargs; 98125113Sru int token; 9953913Sarchie 10053913Sarchie /* Parse out command and arguments */ 10153913Sarchie va_start(fmtargs, fmt); 10253913Sarchie vasprintf(&buf, fmt, fmtargs); 10353913Sarchie va_end(fmtargs); 10453913Sarchie if (buf == NULL) 10553913Sarchie return (-1); 10653913Sarchie 10753913Sarchie /* Parse out command, arguments */ 10853913Sarchie for (cmd = buf; isspace(*cmd); cmd++) 10953913Sarchie ; 11053913Sarchie for (args = cmd; *args != '\0' && !isspace(*args); args++) 11153913Sarchie ; 11253913Sarchie if (*args != '\0') { 11353913Sarchie while (isspace(*args)) 11453913Sarchie *args++ = '\0'; 11553913Sarchie } 11653913Sarchie 11753913Sarchie /* Get a bigger buffer to hold inner message header plus arg string */ 11853913Sarchie if ((ascii = malloc(sizeof(struct ng_mesg) 11961188Sarchie + strlen(args) + 1)) == NULL) { 12053913Sarchie free(buf); 12153913Sarchie return (-1); 12253913Sarchie } 12353913Sarchie memset(ascii, 0, sizeof(*ascii)); 12453913Sarchie 12553913Sarchie /* Build inner header (only need cmdstr, arglen, and data fields) */ 126145546Smux strncpy((char *)ascii->header.cmdstr, cmd, 127145546Smux sizeof(ascii->header.cmdstr) - 1); 12853913Sarchie strcpy(ascii->data, args); 12953913Sarchie ascii->header.arglen = strlen(ascii->data) + 1; 13053913Sarchie free(buf); 13153913Sarchie 13253913Sarchie /* Send node a request to convert ASCII to binary */ 13353913Sarchie if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, NGM_ASCII2BINARY, 134125104Sru (u_char *)ascii, sizeof(*ascii) + ascii->header.arglen) < 0) { 135125104Sru free(ascii); 13653913Sarchie return (-1); 137125104Sru } 138125104Sru free(ascii); 13953913Sarchie 14053913Sarchie /* Get reply */ 141125113Sru if (NgAllocRecvMsg(cs, &reply, NULL) < 0) 14253913Sarchie return (-1); 14353913Sarchie 14453913Sarchie /* Now send binary version */ 145125113Sru binary = (struct ng_mesg *)reply->data; 14661922Sarchie if (++gMsgId < 0) 14761922Sarchie gMsgId = 1; 14861922Sarchie binary->header.token = gMsgId; 149141307Sglebius binary->header.version = NG_VERSION; 15061922Sarchie if (NgDeliverMsg(cs, 151125113Sru path, binary, binary->data, binary->header.arglen) < 0) { 152125113Sru free(reply); 15361922Sarchie return (-1); 154125113Sru } 155125113Sru token = binary->header.token; 156125113Sru free(reply); 157125113Sru return (token); 15853913Sarchie} 15953913Sarchie 16053913Sarchie/* 16152419Sjulian * Send a message that is a reply to a previously received message. 16252419Sjulian * Returns -1 and sets errno on error, otherwise returns zero. 16352419Sjulian */ 16452419Sjulianint 16552419SjulianNgSendReplyMsg(int cs, const char *path, 16652419Sjulian const struct ng_mesg *msg, const void *args, size_t arglen) 16752419Sjulian{ 16852419Sjulian struct ng_mesg rep; 16952419Sjulian 17052419Sjulian /* Prepare message header */ 17152419Sjulian rep = *msg; 17252419Sjulian rep.header.flags = NGF_RESP; 17352419Sjulian 17452419Sjulian /* Deliver message */ 17552419Sjulian return (NgDeliverMsg(cs, path, &rep, args, arglen)); 17652419Sjulian} 17752419Sjulian 17852419Sjulian/* 17952419Sjulian * Send a message to a node using control socket node "cs". 18052419Sjulian * Returns -1 if error and sets errno appropriately, otherwise zero. 18152419Sjulian */ 18252419Sjulianstatic int 18352419SjulianNgDeliverMsg(int cs, const char *path, 18452419Sjulian const struct ng_mesg *hdr, const void *args, size_t arglen) 18552419Sjulian{ 186122649Sharti u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD]; 18752419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 18852419Sjulian u_char *buf = NULL; 18952419Sjulian struct ng_mesg *msg; 19052419Sjulian int errnosv = 0; 19152419Sjulian int rtn = 0; 19252419Sjulian 19352419Sjulian /* Sanity check */ 19452419Sjulian if (args == NULL) 19552419Sjulian arglen = 0; 19652419Sjulian 19752419Sjulian /* Get buffer */ 19852419Sjulian if ((buf = malloc(sizeof(*msg) + arglen)) == NULL) { 19952419Sjulian errnosv = errno; 20052419Sjulian if (_gNgDebugLevel >= 1) 20152419Sjulian NGLOG("malloc"); 20252419Sjulian rtn = -1; 20352419Sjulian goto done; 20452419Sjulian } 20552419Sjulian msg = (struct ng_mesg *) buf; 20652419Sjulian 20752419Sjulian /* Finalize message */ 20852419Sjulian *msg = *hdr; 20952419Sjulian msg->header.arglen = arglen; 21052419Sjulian memcpy(msg->data, args, arglen); 21152419Sjulian 21252419Sjulian /* Prepare socket address */ 21352419Sjulian sg->sg_family = AF_NETGRAPH; 214122649Sharti /* XXX handle overflow */ 215122649Sharti strlcpy(sg->sg_data, path, NG_PATHSIZ); 216122649Sharti sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 21752419Sjulian 21852419Sjulian /* Debugging */ 21952419Sjulian if (_gNgDebugLevel >= 2) { 22052419Sjulian NGLOGX("SENDING %s:", 22152419Sjulian (msg->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE"); 22252419Sjulian _NgDebugSockaddr(sg); 22353913Sarchie _NgDebugMsg(msg, sg->sg_data); 22452419Sjulian } 22552419Sjulian 22652419Sjulian /* Send it */ 22752419Sjulian if (sendto(cs, msg, sizeof(*msg) + arglen, 22852419Sjulian 0, (struct sockaddr *) sg, sg->sg_len) < 0) { 22952419Sjulian errnosv = errno; 23052419Sjulian if (_gNgDebugLevel >= 1) 23152419Sjulian NGLOG("sendto(%s)", sg->sg_data); 23252419Sjulian rtn = -1; 23352419Sjulian goto done; 23452419Sjulian } 23552419Sjulian 236154265Sglebius /* Wait for reply if there should be one. */ 237248159Sglebius if (msg->header.cmd & NGM_HASREPLY && !(msg->header.flags & NGF_RESP)) { 238169551Smav struct pollfd rfds; 239154265Sglebius int n; 240154265Sglebius 241169551Smav rfds.fd = cs; 242169551Smav rfds.events = POLLIN; 243169551Smav rfds.revents = 0; 244169551Smav n = poll(&rfds, 1, INFTIM); 245154265Sglebius if (n == -1) { 246154265Sglebius errnosv = errno; 247154265Sglebius if (_gNgDebugLevel >= 1) 248169551Smav NGLOG("poll"); 249154265Sglebius rtn = -1; 250154265Sglebius } 251154265Sglebius } 252154265Sglebius 25352419Sjuliandone: 25452419Sjulian /* Done */ 25552419Sjulian free(buf); /* OK if buf is NULL */ 25652419Sjulian errno = errnosv; 25752419Sjulian return (rtn); 25852419Sjulian} 25952419Sjulian 26052419Sjulian/* 26152419Sjulian * Receive a control message. 26252419Sjulian * 26352419Sjulian * On error, this returns -1 and sets errno. 26452419Sjulian * Otherwise, it returns the length of the received reply. 26552419Sjulian */ 26652419Sjulianint 26752419SjulianNgRecvMsg(int cs, struct ng_mesg *rep, size_t replen, char *path) 26852419Sjulian{ 269122649Sharti u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD]; 27052419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 271145546Smux socklen_t sglen = sizeof(sgbuf); 272145546Smux int len, errnosv; 27352419Sjulian 27452419Sjulian /* Read reply */ 27552419Sjulian len = recvfrom(cs, rep, replen, 0, (struct sockaddr *) sg, &sglen); 27652419Sjulian if (len < 0) { 27752419Sjulian errnosv = errno; 27852419Sjulian if (_gNgDebugLevel >= 1) 27952419Sjulian NGLOG("recvfrom"); 28052419Sjulian goto errout; 28152419Sjulian } 28252419Sjulian if (path != NULL) 283122649Sharti strlcpy(path, sg->sg_data, NG_PATHSIZ); 28452419Sjulian 28552419Sjulian /* Debugging */ 28652419Sjulian if (_gNgDebugLevel >= 2) { 28752419Sjulian NGLOGX("RECEIVED %s:", 28852419Sjulian (rep->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE"); 28952419Sjulian _NgDebugSockaddr(sg); 29053913Sarchie _NgDebugMsg(rep, sg->sg_data); 29152419Sjulian } 29252419Sjulian 29352419Sjulian /* Done */ 29452419Sjulian return (len); 29552419Sjulian 29652419Sjulianerrout: 29752419Sjulian errno = errnosv; 29852419Sjulian return (-1); 29952419Sjulian} 30052419Sjulian 30153913Sarchie/* 302125113Sru * Identical to NgRecvMsg() except buffer is dynamically allocated. 303125113Sru */ 304125113Sruint 305125113SruNgAllocRecvMsg(int cs, struct ng_mesg **rep, char *path) 306125113Sru{ 307125113Sru int len; 308125113Sru socklen_t optlen; 309125113Sru 310125113Sru optlen = sizeof(len); 311125113Sru if (getsockopt(cs, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 || 312125113Sru (*rep = malloc(len)) == NULL) 313125113Sru return (-1); 314125113Sru if ((len = NgRecvMsg(cs, *rep, len, path)) < 0) 315125113Sru free(*rep); 316125113Sru return (len); 317125113Sru} 318125113Sru 319125113Sru/* 32053913Sarchie * Receive a control message and convert the arguments to ASCII 32153913Sarchie */ 32253913Sarchieint 32353913SarchieNgRecvAsciiMsg(int cs, struct ng_mesg *reply, size_t replen, char *path) 32453913Sarchie{ 32553913Sarchie struct ng_mesg *msg, *ascii; 32653913Sarchie int bufSize, errnosv; 32753913Sarchie u_char *buf; 32853913Sarchie 32953913Sarchie /* Allocate buffer */ 33053913Sarchie bufSize = 2 * sizeof(*reply) + replen; 33153913Sarchie if ((buf = malloc(bufSize)) == NULL) 33253913Sarchie return (-1); 33353913Sarchie msg = (struct ng_mesg *)buf; 33453913Sarchie ascii = (struct ng_mesg *)msg->data; 33553913Sarchie 33653913Sarchie /* Get binary message */ 33753913Sarchie if (NgRecvMsg(cs, msg, bufSize, path) < 0) 33853913Sarchie goto fail; 33953913Sarchie memcpy(reply, msg, sizeof(*msg)); 34053913Sarchie 34153913Sarchie /* Ask originating node to convert the arguments to ASCII */ 34253913Sarchie if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, 34353913Sarchie NGM_BINARY2ASCII, msg, sizeof(*msg) + msg->header.arglen) < 0) 34453913Sarchie goto fail; 34553913Sarchie if (NgRecvMsg(cs, msg, bufSize, NULL) < 0) 34653913Sarchie goto fail; 34753913Sarchie 34853913Sarchie /* Copy result to client buffer */ 34953913Sarchie if (sizeof(*ascii) + ascii->header.arglen > replen) { 35053913Sarchie errno = ERANGE; 35153913Sarchiefail: 35253913Sarchie errnosv = errno; 35353913Sarchie free(buf); 35453913Sarchie errno = errnosv; 35553913Sarchie return (-1); 35653913Sarchie } 35753913Sarchie strncpy(reply->data, ascii->data, ascii->header.arglen); 35853913Sarchie 35953913Sarchie /* Done */ 36053913Sarchie free(buf); 36153913Sarchie return (0); 36253913Sarchie} 36353913Sarchie 364125113Sru/* 365125113Sru * Identical to NgRecvAsciiMsg() except buffer is dynamically allocated. 366125113Sru */ 367125113Sruint 368125113SruNgAllocRecvAsciiMsg(int cs, struct ng_mesg **reply, char *path) 369125113Sru{ 370125113Sru int len; 371125113Sru socklen_t optlen; 372125113Sru 373125113Sru optlen = sizeof(len); 374125113Sru if (getsockopt(cs, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 || 375125113Sru (*reply = malloc(len)) == NULL) 376125113Sru return (-1); 377125113Sru if ((len = NgRecvAsciiMsg(cs, *reply, len, path)) < 0) 378125113Sru free(*reply); 379125113Sru return (len); 380125113Sru} 381