152419Sjulian/* 252419Sjulian * sock.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: sock.c,v 1.12 1999/01/20 00:57:23 archie Exp $ 3952419Sjulian */ 4052419Sjulian 4184215Sdillon#include <sys/cdefs.h> 4284215Sdillon__FBSDID("$FreeBSD$"); 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 5356708Sarchie/* The socket node type KLD */ 5456708Sarchie#define NG_SOCKET_KLD "ng_socket.ko" 5556708Sarchie 5652419Sjulian/* 5752419Sjulian * Create a socket type node and give it the supplied name. 5852419Sjulian * Return data and control sockets corresponding to the node. 5952419Sjulian * Returns -1 if error and sets errno. 6052419Sjulian */ 6152419Sjulianint 6252419SjulianNgMkSockNode(const char *name, int *csp, int *dsp) 6352419Sjulian{ 64122649Sharti char namebuf[NG_NODESIZ]; 6552419Sjulian int cs = -1; /* control socket */ 6652419Sjulian int ds = -1; /* data socket */ 6752419Sjulian int errnosv; 6852419Sjulian 6952419Sjulian /* Empty name means no name */ 7052419Sjulian if (name && *name == 0) 7152419Sjulian name = NULL; 7252419Sjulian 7356708Sarchie /* Create control socket; this also creates the netgraph node. 74244538Skevlo If we get an EAFNOSUPPORT then the socket node type is 7556708Sarchie not loaded, so load it and try again. */ 7652419Sjulian if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) { 77244538Skevlo if (errno == EAFNOSUPPORT) { 7856708Sarchie if (kldload(NG_SOCKET_KLD) < 0) { 7956708Sarchie errnosv = errno; 8056708Sarchie if (_gNgDebugLevel >= 1) 8156708Sarchie NGLOG("can't load %s", NG_SOCKET_KLD); 8256708Sarchie goto errout; 8356708Sarchie } 8456708Sarchie cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL); 8556708Sarchie if (cs >= 0) 8656708Sarchie goto gotNode; 8756708Sarchie } 8852419Sjulian errnosv = errno; 8952419Sjulian if (_gNgDebugLevel >= 1) 9052419Sjulian NGLOG("socket"); 9152419Sjulian goto errout; 9252419Sjulian } 9352419Sjulian 9456708SarchiegotNode: 9552419Sjulian /* Assign the node the desired name, if any */ 9652419Sjulian if (name != NULL) { 97122649Sharti u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD]; 9852419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 9952419Sjulian 10052419Sjulian /* Assign name */ 101122649Sharti strlcpy(sg->sg_data, name, NG_NODESIZ); 10252419Sjulian sg->sg_family = AF_NETGRAPH; 103122649Sharti sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 10452419Sjulian if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) { 10552419Sjulian errnosv = errno; 10652419Sjulian if (_gNgDebugLevel >= 1) 10752419Sjulian NGLOG("bind(%s)", sg->sg_data); 10852419Sjulian goto errout; 10952419Sjulian } 11052419Sjulian 11152419Sjulian /* Save node name */ 112122649Sharti strlcpy(namebuf, name, sizeof(namebuf)); 11352419Sjulian } else if (dsp != NULL) { 114260418Sjmg union { 115260418Sjmg u_char rbuf[sizeof(struct ng_mesg) + 116260418Sjmg sizeof(struct nodeinfo)]; 117260418Sjmg struct ng_mesg res; 118260418Sjmg } res; 119260418Sjmg struct nodeinfo *const ni = (struct nodeinfo *) res.res.data; 12052419Sjulian 12152419Sjulian /* Find out the node ID */ 12252419Sjulian if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE, 12352419Sjulian NGM_NODEINFO, NULL, 0) < 0) { 12452419Sjulian errnosv = errno; 12552419Sjulian if (_gNgDebugLevel >= 1) 12652419Sjulian NGLOG("send nodeinfo"); 12752419Sjulian goto errout; 12852419Sjulian } 129260418Sjmg if (NgRecvMsg(cs, &res.res, sizeof(res.rbuf), NULL) < 0) { 13052419Sjulian errnosv = errno; 13152419Sjulian if (_gNgDebugLevel >= 1) 13252419Sjulian NGLOG("recv nodeinfo"); 13352419Sjulian goto errout; 13452419Sjulian } 13552419Sjulian 13652419Sjulian /* Save node "name" */ 13752419Sjulian snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id); 13852419Sjulian } 13952419Sjulian 14052419Sjulian /* Create data socket if desired */ 14152419Sjulian if (dsp != NULL) { 142122649Sharti u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD]; 14352419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 14452419Sjulian 14552419Sjulian /* Create data socket, initially just "floating" */ 14652419Sjulian if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) { 14752419Sjulian errnosv = errno; 14852419Sjulian if (_gNgDebugLevel >= 1) 14952419Sjulian NGLOG("socket"); 15052419Sjulian goto errout; 15152419Sjulian } 15252419Sjulian 15352419Sjulian /* Associate the data socket with the node */ 154122649Sharti snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf); 15552419Sjulian sg->sg_family = AF_NETGRAPH; 156122649Sharti sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 15752419Sjulian if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) { 15852419Sjulian errnosv = errno; 15952419Sjulian if (_gNgDebugLevel >= 1) 16052419Sjulian NGLOG("connect(%s)", sg->sg_data); 16152419Sjulian goto errout; 16252419Sjulian } 16352419Sjulian } 16452419Sjulian 16552419Sjulian /* Return the socket(s) */ 16652419Sjulian if (csp) 16752419Sjulian *csp = cs; 16852419Sjulian else 16952419Sjulian close(cs); 17052419Sjulian if (dsp) 17152419Sjulian *dsp = ds; 17252419Sjulian return (0); 17352419Sjulian 17452419Sjulianerrout: 17552419Sjulian /* Failed */ 17652419Sjulian if (cs >= 0) 17752419Sjulian close(cs); 17852419Sjulian if (ds >= 0) 17952419Sjulian close(ds); 18052419Sjulian errno = errnosv; 18152419Sjulian return (-1); 18252419Sjulian} 18352419Sjulian 18452419Sjulian/* 18552419Sjulian * Assign a globally unique name to a node 18652419Sjulian * Returns -1 if error and sets errno. 18752419Sjulian */ 18852419Sjulianint 18952419SjulianNgNameNode(int cs, const char *path, const char *fmt, ...) 19052419Sjulian{ 19152419Sjulian struct ngm_name ngn; 19252419Sjulian va_list args; 19352419Sjulian 19452419Sjulian /* Build message arg */ 19552419Sjulian va_start(args, fmt); 19652419Sjulian vsnprintf(ngn.name, sizeof(ngn.name), fmt, args); 19752419Sjulian va_end(args); 19852419Sjulian 19952419Sjulian /* Send message */ 20052419Sjulian if (NgSendMsg(cs, path, 20152419Sjulian NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) { 20252419Sjulian if (_gNgDebugLevel >= 1) 203135576Sstefanf NGLOGX("%s: failed", __func__); 20452419Sjulian return (-1); 20552419Sjulian } 20652419Sjulian 20752419Sjulian /* Done */ 20852419Sjulian return (0); 20952419Sjulian} 21052419Sjulian 21152419Sjulian/* 21252419Sjulian * Read a packet from a data socket 21352419Sjulian * Returns -1 if error and sets errno. 21452419Sjulian */ 21552419Sjulianint 21652419SjulianNgRecvData(int ds, u_char * buf, size_t len, char *hook) 21752419Sjulian{ 218122649Sharti u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD]; 21952419Sjulian struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf; 220145546Smux socklen_t fromlen = sizeof(frombuf); 22152419Sjulian int rtn, errnosv; 22252419Sjulian 22352419Sjulian /* Read packet */ 22452419Sjulian rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen); 22552419Sjulian if (rtn < 0) { 22652419Sjulian errnosv = errno; 22752419Sjulian if (_gNgDebugLevel >= 1) 22852419Sjulian NGLOG("recvfrom"); 22952419Sjulian errno = errnosv; 23052419Sjulian return (-1); 23152419Sjulian } 23252419Sjulian 23352419Sjulian /* Copy hook name */ 23452419Sjulian if (hook != NULL) 235122649Sharti strlcpy(hook, from->sg_data, NG_HOOKSIZ); 23652419Sjulian 23752419Sjulian /* Debugging */ 23852419Sjulian if (_gNgDebugLevel >= 2) { 23952419Sjulian NGLOGX("READ %s from hook \"%s\" (%d bytes)", 24052419Sjulian rtn ? "PACKET" : "EOF", from->sg_data, rtn); 24152419Sjulian if (_gNgDebugLevel >= 3) 24252419Sjulian _NgDebugBytes(buf, rtn); 24352419Sjulian } 24452419Sjulian 24552419Sjulian /* Done */ 24652419Sjulian return (rtn); 24752419Sjulian} 24852419Sjulian 24952419Sjulian/* 250125113Sru * Identical to NgRecvData() except buffer is dynamically allocated. 251125113Sru */ 252125113Sruint 253125113SruNgAllocRecvData(int ds, u_char **buf, char *hook) 254125113Sru{ 255125113Sru int len; 256125113Sru socklen_t optlen; 257125113Sru 258125113Sru optlen = sizeof(len); 259125113Sru if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 || 260125113Sru (*buf = malloc(len)) == NULL) 261125113Sru return (-1); 262125113Sru if ((len = NgRecvData(ds, *buf, len, hook)) < 0) 263125113Sru free(*buf); 264125113Sru return (len); 265125113Sru} 266125113Sru 267125113Sru/* 26852419Sjulian * Write a packet to a data socket. The packet will be sent 26952419Sjulian * out the corresponding node on the specified hook. 27052419Sjulian * Returns -1 if error and sets errno. 27152419Sjulian */ 27252419Sjulianint 27352419SjulianNgSendData(int ds, const char *hook, const u_char * buf, size_t len) 27452419Sjulian{ 275122649Sharti u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD]; 27652419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 27752419Sjulian int errnosv; 27852419Sjulian 27952419Sjulian /* Set up destination hook */ 28052419Sjulian sg->sg_family = AF_NETGRAPH; 281122649Sharti strlcpy(sg->sg_data, hook, NG_HOOKSIZ); 282122649Sharti sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 28352419Sjulian 28452419Sjulian /* Debugging */ 28552419Sjulian if (_gNgDebugLevel >= 2) { 28652419Sjulian NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len); 28752419Sjulian _NgDebugSockaddr(sg); 28852419Sjulian if (_gNgDebugLevel >= 3) 28952419Sjulian _NgDebugBytes(buf, len); 29052419Sjulian } 29152419Sjulian 29252419Sjulian /* Send packet */ 29352419Sjulian if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) { 29452419Sjulian errnosv = errno; 29552419Sjulian if (_gNgDebugLevel >= 1) 29652419Sjulian NGLOG("sendto(%s)", sg->sg_data); 29752419Sjulian errno = errnosv; 29852419Sjulian return (-1); 29952419Sjulian } 30052419Sjulian 30152419Sjulian /* Done */ 30252419Sjulian return (0); 30352419Sjulian} 30452419Sjulian 305