sock.c revision 84215
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 84215 2001-09-30 22:03:54Z dillon $"); 4384215Sdillon 4452419Sjulian#include <sys/types.h> 4552419Sjulian#include <stdarg.h> 4652419Sjulian#include <netgraph/ng_message.h> 4752419Sjulian#include <netgraph/ng_socket.h> 4852419Sjulian 4952419Sjulian#include "netgraph.h" 5052419Sjulian#include "internal.h" 5152419Sjulian 5256708Sarchie/* The socket node type KLD */ 5356708Sarchie#define NG_SOCKET_KLD "ng_socket.ko" 5456708Sarchie 5552419Sjulian/* 5652419Sjulian * Create a socket type node and give it the supplied name. 5752419Sjulian * Return data and control sockets corresponding to the node. 5852419Sjulian * Returns -1 if error and sets errno. 5952419Sjulian */ 6052419Sjulianint 6152419SjulianNgMkSockNode(const char *name, int *csp, int *dsp) 6252419Sjulian{ 6352419Sjulian char namebuf[NG_NODELEN + 1]; 6452419Sjulian int cs = -1; /* control socket */ 6552419Sjulian int ds = -1; /* data socket */ 6652419Sjulian int errnosv; 6752419Sjulian 6852419Sjulian /* Empty name means no name */ 6952419Sjulian if (name && *name == 0) 7052419Sjulian name = NULL; 7152419Sjulian 7256708Sarchie /* Create control socket; this also creates the netgraph node. 7356708Sarchie If we get a EPROTONOSUPPORT then the socket node type is 7456708Sarchie not loaded, so load it and try again. */ 7552419Sjulian if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) { 7656708Sarchie if (errno == EPROTONOSUPPORT) { 7756708Sarchie if (kldload(NG_SOCKET_KLD) < 0) { 7856708Sarchie errnosv = errno; 7956708Sarchie if (_gNgDebugLevel >= 1) 8056708Sarchie NGLOG("can't load %s", NG_SOCKET_KLD); 8156708Sarchie goto errout; 8256708Sarchie } 8356708Sarchie cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL); 8456708Sarchie if (cs >= 0) 8556708Sarchie goto gotNode; 8656708Sarchie } 8752419Sjulian errnosv = errno; 8852419Sjulian if (_gNgDebugLevel >= 1) 8952419Sjulian NGLOG("socket"); 9052419Sjulian goto errout; 9152419Sjulian } 9252419Sjulian 9356708SarchiegotNode: 9452419Sjulian /* Assign the node the desired name, if any */ 9552419Sjulian if (name != NULL) { 9652419Sjulian u_char sbuf[NG_NODELEN + 3]; 9752419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 9852419Sjulian 9952419Sjulian /* Assign name */ 10052419Sjulian snprintf(sg->sg_data, NG_NODELEN + 1, "%s", name); 10152419Sjulian sg->sg_family = AF_NETGRAPH; 10252419Sjulian sg->sg_len = strlen(sg->sg_data) + 3; 10352419Sjulian if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) { 10452419Sjulian errnosv = errno; 10552419Sjulian if (_gNgDebugLevel >= 1) 10652419Sjulian NGLOG("bind(%s)", sg->sg_data); 10752419Sjulian goto errout; 10852419Sjulian } 10952419Sjulian 11052419Sjulian /* Save node name */ 11152419Sjulian snprintf(namebuf, sizeof(namebuf), "%s", name); 11252419Sjulian } else if (dsp != NULL) { 11352419Sjulian u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; 11452419Sjulian struct ng_mesg *const resp = (struct ng_mesg *) rbuf; 11552419Sjulian struct nodeinfo *const ni = (struct nodeinfo *) resp->data; 11652419Sjulian 11752419Sjulian /* Find out the node ID */ 11852419Sjulian if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE, 11952419Sjulian NGM_NODEINFO, NULL, 0) < 0) { 12052419Sjulian errnosv = errno; 12152419Sjulian if (_gNgDebugLevel >= 1) 12252419Sjulian NGLOG("send nodeinfo"); 12352419Sjulian goto errout; 12452419Sjulian } 12552419Sjulian if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) { 12652419Sjulian errnosv = errno; 12752419Sjulian if (_gNgDebugLevel >= 1) 12852419Sjulian NGLOG("recv nodeinfo"); 12952419Sjulian goto errout; 13052419Sjulian } 13152419Sjulian 13252419Sjulian /* Save node "name" */ 13352419Sjulian snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id); 13452419Sjulian } 13552419Sjulian 13652419Sjulian /* Create data socket if desired */ 13752419Sjulian if (dsp != NULL) { 13852419Sjulian u_char sbuf[NG_NODELEN + 4]; 13952419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 14052419Sjulian 14152419Sjulian /* Create data socket, initially just "floating" */ 14252419Sjulian if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) { 14352419Sjulian errnosv = errno; 14452419Sjulian if (_gNgDebugLevel >= 1) 14552419Sjulian NGLOG("socket"); 14652419Sjulian goto errout; 14752419Sjulian } 14852419Sjulian 14952419Sjulian /* Associate the data socket with the node */ 15052419Sjulian snprintf(sg->sg_data, NG_NODELEN + 2, "%s:", namebuf); 15152419Sjulian sg->sg_family = AF_NETGRAPH; 15252419Sjulian sg->sg_len = strlen(sg->sg_data) + 3; 15352419Sjulian if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) { 15452419Sjulian errnosv = errno; 15552419Sjulian if (_gNgDebugLevel >= 1) 15652419Sjulian NGLOG("connect(%s)", sg->sg_data); 15752419Sjulian goto errout; 15852419Sjulian } 15952419Sjulian } 16052419Sjulian 16152419Sjulian /* Return the socket(s) */ 16252419Sjulian if (csp) 16352419Sjulian *csp = cs; 16452419Sjulian else 16552419Sjulian close(cs); 16652419Sjulian if (dsp) 16752419Sjulian *dsp = ds; 16852419Sjulian return (0); 16952419Sjulian 17052419Sjulianerrout: 17152419Sjulian /* Failed */ 17252419Sjulian if (cs >= 0) 17352419Sjulian close(cs); 17452419Sjulian if (ds >= 0) 17552419Sjulian close(ds); 17652419Sjulian errno = errnosv; 17752419Sjulian return (-1); 17852419Sjulian} 17952419Sjulian 18052419Sjulian/* 18152419Sjulian * Assign a globally unique name to a node 18252419Sjulian * Returns -1 if error and sets errno. 18352419Sjulian */ 18452419Sjulianint 18552419SjulianNgNameNode(int cs, const char *path, const char *fmt, ...) 18652419Sjulian{ 18752419Sjulian struct ngm_name ngn; 18852419Sjulian va_list args; 18952419Sjulian 19052419Sjulian /* Build message arg */ 19152419Sjulian va_start(args, fmt); 19252419Sjulian vsnprintf(ngn.name, sizeof(ngn.name), fmt, args); 19352419Sjulian va_end(args); 19452419Sjulian 19552419Sjulian /* Send message */ 19652419Sjulian if (NgSendMsg(cs, path, 19752419Sjulian NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) { 19852419Sjulian if (_gNgDebugLevel >= 1) 19952419Sjulian NGLOGX("%s: failed", __FUNCTION__); 20052419Sjulian return (-1); 20152419Sjulian } 20252419Sjulian 20352419Sjulian /* Done */ 20452419Sjulian return (0); 20552419Sjulian} 20652419Sjulian 20752419Sjulian/* 20852419Sjulian * Read a packet from a data socket 20952419Sjulian * Returns -1 if error and sets errno. 21052419Sjulian */ 21152419Sjulianint 21252419SjulianNgRecvData(int ds, u_char * buf, size_t len, char *hook) 21352419Sjulian{ 21452419Sjulian u_char frombuf[NG_HOOKLEN + sizeof(struct sockaddr_ng)]; 21552419Sjulian struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf; 21652419Sjulian int fromlen = sizeof(frombuf); 21752419Sjulian int rtn, errnosv; 21852419Sjulian 21952419Sjulian /* Read packet */ 22052419Sjulian rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen); 22152419Sjulian if (rtn < 0) { 22252419Sjulian errnosv = errno; 22352419Sjulian if (_gNgDebugLevel >= 1) 22452419Sjulian NGLOG("recvfrom"); 22552419Sjulian errno = errnosv; 22652419Sjulian return (-1); 22752419Sjulian } 22852419Sjulian 22952419Sjulian /* Copy hook name */ 23052419Sjulian if (hook != NULL) 23152419Sjulian snprintf(hook, NG_HOOKLEN + 1, "%s", from->sg_data); 23252419Sjulian 23352419Sjulian /* Debugging */ 23452419Sjulian if (_gNgDebugLevel >= 2) { 23552419Sjulian NGLOGX("READ %s from hook \"%s\" (%d bytes)", 23652419Sjulian rtn ? "PACKET" : "EOF", from->sg_data, rtn); 23752419Sjulian if (_gNgDebugLevel >= 3) 23852419Sjulian _NgDebugBytes(buf, rtn); 23952419Sjulian } 24052419Sjulian 24152419Sjulian /* Done */ 24252419Sjulian return (rtn); 24352419Sjulian} 24452419Sjulian 24552419Sjulian/* 24652419Sjulian * Write a packet to a data socket. The packet will be sent 24752419Sjulian * out the corresponding node on the specified hook. 24852419Sjulian * Returns -1 if error and sets errno. 24952419Sjulian */ 25052419Sjulianint 25152419SjulianNgSendData(int ds, const char *hook, const u_char * buf, size_t len) 25252419Sjulian{ 25352419Sjulian u_char sgbuf[NG_HOOKLEN + sizeof(struct sockaddr_ng)]; 25452419Sjulian struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 25552419Sjulian int errnosv; 25652419Sjulian 25752419Sjulian /* Set up destination hook */ 25852419Sjulian sg->sg_family = AF_NETGRAPH; 25952419Sjulian snprintf(sg->sg_data, NG_HOOKLEN + 1, "%s", hook); 26052419Sjulian sg->sg_len = strlen(sg->sg_data) + 3; 26152419Sjulian 26252419Sjulian /* Debugging */ 26352419Sjulian if (_gNgDebugLevel >= 2) { 26452419Sjulian NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len); 26552419Sjulian _NgDebugSockaddr(sg); 26652419Sjulian if (_gNgDebugLevel >= 3) 26752419Sjulian _NgDebugBytes(buf, len); 26852419Sjulian } 26952419Sjulian 27052419Sjulian /* Send packet */ 27152419Sjulian if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) { 27252419Sjulian errnosv = errno; 27352419Sjulian if (_gNgDebugLevel >= 1) 27452419Sjulian NGLOG("sendto(%s)", sg->sg_data); 27552419Sjulian errno = errnosv; 27652419Sjulian return (-1); 27752419Sjulian } 27852419Sjulian 27952419Sjulian /* Done */ 28052419Sjulian return (0); 28152419Sjulian} 28252419Sjulian 283