sock.c revision 135576
1254885Sdumbbell/* 2254885Sdumbbell * sock.c 3254885Sdumbbell * 4254885Sdumbbell * Copyright (c) 1996-1999 Whistle Communications, Inc. 5254885Sdumbbell * All rights reserved. 6254885Sdumbbell * 7254885Sdumbbell * Subject to the following obligations and disclaimer of warranty, use and 8254885Sdumbbell * redistribution of this software, in source or object code forms, with or 9254885Sdumbbell * without modifications are expressly permitted by Whistle Communications; 10254885Sdumbbell * provided, however, that: 11254885Sdumbbell * 1. Any and all reproductions of the source or object code must include the 12254885Sdumbbell * copyright notice above and the following disclaimer of warranties; and 13254885Sdumbbell * 2. No rights are granted, in any manner or form, to use Whistle 14254885Sdumbbell * Communications, Inc. trademarks, including the mark "WHISTLE 15254885Sdumbbell * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 16254885Sdumbbell * such appears in the above copyright notice or in the software. 17254885Sdumbbell * 18254885Sdumbbell * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 19254885Sdumbbell * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 20254885Sdumbbell * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 21254885Sdumbbell * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 22254885Sdumbbell * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 23254885Sdumbbell * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 24254885Sdumbbell * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 25254885Sdumbbell * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 26254885Sdumbbell * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 27254885Sdumbbell * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 28254885Sdumbbell * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 29254885Sdumbbell * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 30254885Sdumbbell * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 31254885Sdumbbell * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32254885Sdumbbell * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33254885Sdumbbell * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 34254885Sdumbbell * OF SUCH DAMAGE. 35254885Sdumbbell * 36254885Sdumbbell * Author: Archie Cobbs <archie@whistle.com> 37254885Sdumbbell * 38254885Sdumbbell * $Whistle: sock.c,v 1.12 1999/01/20 00:57:23 archie Exp $ 39254885Sdumbbell */ 40254885Sdumbbell 41254885Sdumbbell#include <sys/cdefs.h> 42254885Sdumbbell__FBSDID("$FreeBSD: head/lib/libnetgraph/sock.c 135576 2004-09-22 16:56:49Z stefanf $"); 43254885Sdumbbell 44254885Sdumbbell#include <sys/types.h> 45254885Sdumbbell#include <stdarg.h> 46254885Sdumbbell#include <netgraph/ng_message.h> 47254885Sdumbbell#include <netgraph/ng_socket.h> 48254885Sdumbbell 49254885Sdumbbell#include "netgraph.h" 50254885Sdumbbell#include "internal.h" 51254885Sdumbbell 52254885Sdumbbell/* The socket node type KLD */ 53254885Sdumbbell#define NG_SOCKET_KLD "ng_socket.ko" 54254885Sdumbbell 55254885Sdumbbell/* 56254885Sdumbbell * Create a socket type node and give it the supplied name. 57254885Sdumbbell * Return data and control sockets corresponding to the node. 58254885Sdumbbell * Returns -1 if error and sets errno. 59254885Sdumbbell */ 60254885Sdumbbellint 61254885SdumbbellNgMkSockNode(const char *name, int *csp, int *dsp) 62254885Sdumbbell{ 63254885Sdumbbell char namebuf[NG_NODESIZ]; 64254885Sdumbbell int cs = -1; /* control socket */ 65254885Sdumbbell int ds = -1; /* data socket */ 66254885Sdumbbell int errnosv; 67254885Sdumbbell 68254885Sdumbbell /* Empty name means no name */ 69254885Sdumbbell if (name && *name == 0) 70254885Sdumbbell name = NULL; 71254885Sdumbbell 72254885Sdumbbell /* Create control socket; this also creates the netgraph node. 73254885Sdumbbell If we get an EPROTONOSUPPORT then the socket node type is 74254885Sdumbbell not loaded, so load it and try again. */ 75254885Sdumbbell if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) { 76254885Sdumbbell if (errno == EPROTONOSUPPORT) { 77254885Sdumbbell if (kldload(NG_SOCKET_KLD) < 0) { 78254885Sdumbbell errnosv = errno; 79254885Sdumbbell if (_gNgDebugLevel >= 1) 80254885Sdumbbell NGLOG("can't load %s", NG_SOCKET_KLD); 81254885Sdumbbell goto errout; 82254885Sdumbbell } 83254885Sdumbbell cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL); 84254885Sdumbbell if (cs >= 0) 85254885Sdumbbell goto gotNode; 86254885Sdumbbell } 87254885Sdumbbell errnosv = errno; 88254885Sdumbbell if (_gNgDebugLevel >= 1) 89254885Sdumbbell NGLOG("socket"); 90254885Sdumbbell goto errout; 91254885Sdumbbell } 92254885Sdumbbell 93254885SdumbbellgotNode: 94254885Sdumbbell /* Assign the node the desired name, if any */ 95254885Sdumbbell if (name != NULL) { 96254885Sdumbbell u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD]; 97254885Sdumbbell struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 98254885Sdumbbell 99254885Sdumbbell /* Assign name */ 100254885Sdumbbell strlcpy(sg->sg_data, name, NG_NODESIZ); 101254885Sdumbbell sg->sg_family = AF_NETGRAPH; 102254885Sdumbbell sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 103255572Sdumbbell if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) { 104254885Sdumbbell errnosv = errno; 105254885Sdumbbell if (_gNgDebugLevel >= 1) 106254885Sdumbbell NGLOG("bind(%s)", sg->sg_data); 107254885Sdumbbell goto errout; 108254885Sdumbbell } 109255572Sdumbbell 110254885Sdumbbell /* Save node name */ 111254885Sdumbbell strlcpy(namebuf, name, sizeof(namebuf)); 112255572Sdumbbell } else if (dsp != NULL) { 113254885Sdumbbell u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; 114254885Sdumbbell struct ng_mesg *const resp = (struct ng_mesg *) rbuf; 115254885Sdumbbell struct nodeinfo *const ni = (struct nodeinfo *) resp->data; 116254885Sdumbbell 117254885Sdumbbell /* Find out the node ID */ 118254885Sdumbbell if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE, 119254885Sdumbbell NGM_NODEINFO, NULL, 0) < 0) { 120254885Sdumbbell errnosv = errno; 121254885Sdumbbell if (_gNgDebugLevel >= 1) 122254885Sdumbbell NGLOG("send nodeinfo"); 123254885Sdumbbell goto errout; 124254885Sdumbbell } 125255572Sdumbbell if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) { 126255587Sdumbbell errnosv = errno; 127254885Sdumbbell if (_gNgDebugLevel >= 1) 128254885Sdumbbell NGLOG("recv nodeinfo"); 129254885Sdumbbell goto errout; 130255572Sdumbbell } 131254885Sdumbbell 132254885Sdumbbell /* Save node "name" */ 133254885Sdumbbell snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id); 134254885Sdumbbell } 135254885Sdumbbell 136254885Sdumbbell /* Create data socket if desired */ 137254885Sdumbbell if (dsp != NULL) { 138254885Sdumbbell u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD]; 139254885Sdumbbell struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 140254885Sdumbbell 141254885Sdumbbell /* Create data socket, initially just "floating" */ 142254885Sdumbbell if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) { 143254885Sdumbbell errnosv = errno; 144254885Sdumbbell if (_gNgDebugLevel >= 1) 145254885Sdumbbell NGLOG("socket"); 146254885Sdumbbell goto errout; 147254885Sdumbbell } 148254885Sdumbbell 149254885Sdumbbell /* Associate the data socket with the node */ 150254885Sdumbbell snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf); 151254885Sdumbbell sg->sg_family = AF_NETGRAPH; 152254885Sdumbbell sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 153254885Sdumbbell if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) { 154254885Sdumbbell errnosv = errno; 155254885Sdumbbell if (_gNgDebugLevel >= 1) 156254885Sdumbbell NGLOG("connect(%s)", sg->sg_data); 157254885Sdumbbell goto errout; 158254885Sdumbbell } 159254885Sdumbbell } 160254885Sdumbbell 161254885Sdumbbell /* Return the socket(s) */ 162254885Sdumbbell if (csp) 163254885Sdumbbell *csp = cs; 164254885Sdumbbell else 165254885Sdumbbell close(cs); 166254885Sdumbbell if (dsp) 167254885Sdumbbell *dsp = ds; 168254885Sdumbbell return (0); 169254885Sdumbbell 170254885Sdumbbellerrout: 171254885Sdumbbell /* Failed */ 172254885Sdumbbell if (cs >= 0) 173254885Sdumbbell close(cs); 174254885Sdumbbell if (ds >= 0) 175254885Sdumbbell close(ds); 176254885Sdumbbell errno = errnosv; 177254885Sdumbbell return (-1); 178254885Sdumbbell} 179254885Sdumbbell 180254885Sdumbbell/* 181254885Sdumbbell * Assign a globally unique name to a node 182254885Sdumbbell * Returns -1 if error and sets errno. 183254885Sdumbbell */ 184254885Sdumbbellint 185254885SdumbbellNgNameNode(int cs, const char *path, const char *fmt, ...) 186254885Sdumbbell{ 187254885Sdumbbell struct ngm_name ngn; 188254885Sdumbbell va_list args; 189254885Sdumbbell 190254885Sdumbbell /* Build message arg */ 191254885Sdumbbell va_start(args, fmt); 192254885Sdumbbell vsnprintf(ngn.name, sizeof(ngn.name), fmt, args); 193254885Sdumbbell va_end(args); 194254885Sdumbbell 195254885Sdumbbell /* Send message */ 196254885Sdumbbell if (NgSendMsg(cs, path, 197254885Sdumbbell NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) { 198254885Sdumbbell if (_gNgDebugLevel >= 1) 199254885Sdumbbell NGLOGX("%s: failed", __func__); 200254885Sdumbbell return (-1); 201254885Sdumbbell } 202254885Sdumbbell 203254885Sdumbbell /* Done */ 204254885Sdumbbell return (0); 205254885Sdumbbell} 206254885Sdumbbell 207254885Sdumbbell/* 208254885Sdumbbell * Read a packet from a data socket 209254885Sdumbbell * Returns -1 if error and sets errno. 210254885Sdumbbell */ 211254885Sdumbbellint 212254885SdumbbellNgRecvData(int ds, u_char * buf, size_t len, char *hook) 213254885Sdumbbell{ 214254885Sdumbbell u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD]; 215254885Sdumbbell struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf; 216254885Sdumbbell int fromlen = sizeof(frombuf); 217254885Sdumbbell int rtn, errnosv; 218254885Sdumbbell 219254885Sdumbbell /* Read packet */ 220254885Sdumbbell rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen); 221254885Sdumbbell if (rtn < 0) { 222254885Sdumbbell errnosv = errno; 223254885Sdumbbell if (_gNgDebugLevel >= 1) 224254885Sdumbbell NGLOG("recvfrom"); 225254885Sdumbbell errno = errnosv; 226254885Sdumbbell return (-1); 227254885Sdumbbell } 228254885Sdumbbell 229254885Sdumbbell /* Copy hook name */ 230254885Sdumbbell if (hook != NULL) 231254885Sdumbbell strlcpy(hook, from->sg_data, NG_HOOKSIZ); 232254885Sdumbbell 233254885Sdumbbell /* Debugging */ 234254885Sdumbbell if (_gNgDebugLevel >= 2) { 235254885Sdumbbell NGLOGX("READ %s from hook \"%s\" (%d bytes)", 236254885Sdumbbell rtn ? "PACKET" : "EOF", from->sg_data, rtn); 237254885Sdumbbell if (_gNgDebugLevel >= 3) 238254885Sdumbbell _NgDebugBytes(buf, rtn); 239254885Sdumbbell } 240254885Sdumbbell 241254885Sdumbbell /* Done */ 242254885Sdumbbell return (rtn); 243254885Sdumbbell} 244254885Sdumbbell 245254885Sdumbbell/* 246254885Sdumbbell * Identical to NgRecvData() except buffer is dynamically allocated. 247254885Sdumbbell */ 248254885Sdumbbellint 249254885SdumbbellNgAllocRecvData(int ds, u_char **buf, char *hook) 250254885Sdumbbell{ 251254885Sdumbbell int len; 252254885Sdumbbell socklen_t optlen; 253254885Sdumbbell 254254885Sdumbbell optlen = sizeof(len); 255254885Sdumbbell if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 || 256254885Sdumbbell (*buf = malloc(len)) == NULL) 257254885Sdumbbell return (-1); 258254885Sdumbbell if ((len = NgRecvData(ds, *buf, len, hook)) < 0) 259254885Sdumbbell free(*buf); 260254885Sdumbbell return (len); 261254885Sdumbbell} 262254885Sdumbbell 263254885Sdumbbell/* 264254885Sdumbbell * Write a packet to a data socket. The packet will be sent 265254885Sdumbbell * out the corresponding node on the specified hook. 266254885Sdumbbell * Returns -1 if error and sets errno. 267254885Sdumbbell */ 268254885Sdumbbellint 269254885SdumbbellNgSendData(int ds, const char *hook, const u_char * buf, size_t len) 270254885Sdumbbell{ 271254885Sdumbbell u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD]; 272254885Sdumbbell struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 273254885Sdumbbell int errnosv; 274254885Sdumbbell 275254885Sdumbbell /* Set up destination hook */ 276254885Sdumbbell sg->sg_family = AF_NETGRAPH; 277254885Sdumbbell strlcpy(sg->sg_data, hook, NG_HOOKSIZ); 278254885Sdumbbell sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 279254885Sdumbbell 280254885Sdumbbell /* Debugging */ 281254885Sdumbbell if (_gNgDebugLevel >= 2) { 282254885Sdumbbell NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len); 283254885Sdumbbell _NgDebugSockaddr(sg); 284254885Sdumbbell if (_gNgDebugLevel >= 3) 285254885Sdumbbell _NgDebugBytes(buf, len); 286254885Sdumbbell } 287254885Sdumbbell 288254885Sdumbbell /* Send packet */ 289254885Sdumbbell if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) { 290254885Sdumbbell errnosv = errno; 291254885Sdumbbell if (_gNgDebugLevel >= 1) 292254885Sdumbbell NGLOG("sendto(%s)", sg->sg_data); 293254885Sdumbbell errno = errnosv; 294254885Sdumbbell return (-1); 295254885Sdumbbell } 296254885Sdumbbell 297254885Sdumbbell /* Done */ 298254885Sdumbbell return (0); 299254885Sdumbbell} 300254885Sdumbbell 301254885Sdumbbell