sock.c revision 163469
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: head/lib/libnetgraph/sock.c 163469 2006-10-17 16:56:29Z 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 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. 74108533Sschweikh If we get an EPROTONOSUPPORT 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) { 7756708Sarchie if (errno == EPROTONOSUPPORT) { 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) { 11452419Sjulian u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; 11552419Sjulian struct ng_mesg *const resp = (struct ng_mesg *) rbuf; 11652419Sjulian struct nodeinfo *const ni = (struct nodeinfo *) resp->data; 11752419Sjulian 11852419Sjulian /* Find out the node ID */ 11952419Sjulian if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE, 12052419Sjulian NGM_NODEINFO, NULL, 0) < 0) { 12152419Sjulian errnosv = errno; 12252419Sjulian if (_gNgDebugLevel >= 1) 12352419Sjulian NGLOG("send nodeinfo"); 12452419Sjulian goto errout; 12552419Sjulian } 12652419Sjulian if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) { 12752419Sjulian errnosv = errno; 12852419Sjulian if (_gNgDebugLevel >= 1) 12952419Sjulian NGLOG("recv nodeinfo"); 13052419Sjulian goto errout; 13152419Sjulian } 13252419Sjulian 13352419Sjulian /* Save node "name" */ 13452419Sjulian snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id); 13552419Sjulian } 13652419Sjulian 13752419Sjulian /* Create data socket if desired */ 13852419Sjulian if (dsp != NULL) { 139122649Sharti u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD]; 14052419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 14152419Sjulian 14252419Sjulian /* Create data socket, initially just "floating" */ 14352419Sjulian if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) { 14452419Sjulian errnosv = errno; 14552419Sjulian if (_gNgDebugLevel >= 1) 14652419Sjulian NGLOG("socket"); 14752419Sjulian goto errout; 14852419Sjulian } 14952419Sjulian 15052419Sjulian /* Associate the data socket with the node */ 151122649Sharti snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf); 15252419Sjulian sg->sg_family = AF_NETGRAPH; 153122649Sharti sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 15452419Sjulian if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) { 15552419Sjulian errnosv = errno; 15652419Sjulian if (_gNgDebugLevel >= 1) 15752419Sjulian NGLOG("connect(%s)", sg->sg_data); 15852419Sjulian goto errout; 15952419Sjulian } 16052419Sjulian } 16152419Sjulian 16252419Sjulian /* Return the socket(s) */ 16352419Sjulian if (csp) 16452419Sjulian *csp = cs; 16552419Sjulian else 16652419Sjulian close(cs); 16752419Sjulian if (dsp) 16852419Sjulian *dsp = ds; 16952419Sjulian return (0); 17052419Sjulian 17152419Sjulianerrout: 17252419Sjulian /* Failed */ 17352419Sjulian if (cs >= 0) 17452419Sjulian close(cs); 17552419Sjulian if (ds >= 0) 17652419Sjulian close(ds); 17752419Sjulian errno = errnosv; 17852419Sjulian return (-1); 17952419Sjulian} 18052419Sjulian 18152419Sjulian/* 18252419Sjulian * Assign a globally unique name to a node 18352419Sjulian * Returns -1 if error and sets errno. 18452419Sjulian */ 18552419Sjulianint 18652419SjulianNgNameNode(int cs, const char *path, const char *fmt, ...) 18752419Sjulian{ 18852419Sjulian struct ngm_name ngn; 18952419Sjulian va_list args; 19052419Sjulian 19152419Sjulian /* Build message arg */ 19252419Sjulian va_start(args, fmt); 19352419Sjulian vsnprintf(ngn.name, sizeof(ngn.name), fmt, args); 19452419Sjulian va_end(args); 19552419Sjulian 19652419Sjulian /* Send message */ 19752419Sjulian if (NgSendMsg(cs, path, 19852419Sjulian NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) { 19952419Sjulian if (_gNgDebugLevel >= 1) 200135576Sstefanf NGLOGX("%s: failed", __func__); 20152419Sjulian return (-1); 20252419Sjulian } 20352419Sjulian 20452419Sjulian /* Done */ 20552419Sjulian return (0); 20652419Sjulian} 20752419Sjulian 20852419Sjulian/* 20952419Sjulian * Read a packet from a data socket 21052419Sjulian * Returns -1 if error and sets errno. 21152419Sjulian */ 21252419Sjulianint 21352419SjulianNgRecvData(int ds, u_char * buf, size_t len, char *hook) 21452419Sjulian{ 215122649Sharti u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD]; 21652419Sjulian struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf; 217145546Smux socklen_t fromlen = sizeof(frombuf); 21852419Sjulian int rtn, errnosv; 21952419Sjulian 22052419Sjulian /* Read packet */ 22152419Sjulian rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen); 22252419Sjulian if (rtn < 0) { 22352419Sjulian errnosv = errno; 22452419Sjulian if (_gNgDebugLevel >= 1) 22552419Sjulian NGLOG("recvfrom"); 22652419Sjulian errno = errnosv; 22752419Sjulian return (-1); 22852419Sjulian } 22952419Sjulian 23052419Sjulian /* Copy hook name */ 23152419Sjulian if (hook != NULL) 232122649Sharti strlcpy(hook, from->sg_data, NG_HOOKSIZ); 23352419Sjulian 23452419Sjulian /* Debugging */ 23552419Sjulian if (_gNgDebugLevel >= 2) { 23652419Sjulian NGLOGX("READ %s from hook \"%s\" (%d bytes)", 23752419Sjulian rtn ? "PACKET" : "EOF", from->sg_data, rtn); 23852419Sjulian if (_gNgDebugLevel >= 3) 23952419Sjulian _NgDebugBytes(buf, rtn); 24052419Sjulian } 24152419Sjulian 24252419Sjulian /* Done */ 24352419Sjulian return (rtn); 24452419Sjulian} 24552419Sjulian 24652419Sjulian/* 247125113Sru * Identical to NgRecvData() except buffer is dynamically allocated. 248125113Sru */ 249125113Sruint 250125113SruNgAllocRecvData(int ds, u_char **buf, char *hook) 251125113Sru{ 252125113Sru int len; 253125113Sru socklen_t optlen; 254125113Sru 255125113Sru optlen = sizeof(len); 256125113Sru if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 || 257125113Sru (*buf = malloc(len)) == NULL) 258125113Sru return (-1); 259125113Sru if ((len = NgRecvData(ds, *buf, len, hook)) < 0) 260125113Sru free(*buf); 261125113Sru return (len); 262125113Sru} 263125113Sru 264125113Sru/* 26552419Sjulian * Write a packet to a data socket. The packet will be sent 26652419Sjulian * out the corresponding node on the specified hook. 26752419Sjulian * Returns -1 if error and sets errno. 26852419Sjulian */ 26952419Sjulianint 27052419SjulianNgSendData(int ds, const char *hook, const u_char * buf, size_t len) 27152419Sjulian{ 272122649Sharti u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD]; 27352419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 27452419Sjulian int errnosv; 27552419Sjulian 27652419Sjulian /* Set up destination hook */ 27752419Sjulian sg->sg_family = AF_NETGRAPH; 278122649Sharti strlcpy(sg->sg_data, hook, NG_HOOKSIZ); 279122649Sharti sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 28052419Sjulian 28152419Sjulian /* Debugging */ 28252419Sjulian if (_gNgDebugLevel >= 2) { 28352419Sjulian NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len); 28452419Sjulian _NgDebugSockaddr(sg); 28552419Sjulian if (_gNgDebugLevel >= 3) 28652419Sjulian _NgDebugBytes(buf, len); 28752419Sjulian } 28852419Sjulian 28952419Sjulian /* Send packet */ 29052419Sjulian if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) { 29152419Sjulian errnosv = errno; 29252419Sjulian if (_gNgDebugLevel >= 1) 29352419Sjulian NGLOG("sendto(%s)", sg->sg_data); 29452419Sjulian errno = errnosv; 29552419Sjulian return (-1); 29652419Sjulian } 29752419Sjulian 29852419Sjulian /* Done */ 29952419Sjulian return (0); 30052419Sjulian} 30152419Sjulian 302