13b2bd0f6Slogwang /*
23b2bd0f6Slogwang * sock.c
33b2bd0f6Slogwang *
43b2bd0f6Slogwang * Copyright (c) 1996-1999 Whistle Communications, Inc.
53b2bd0f6Slogwang * All rights reserved.
63b2bd0f6Slogwang *
73b2bd0f6Slogwang * Subject to the following obligations and disclaimer of warranty, use and
83b2bd0f6Slogwang * redistribution of this software, in source or object code forms, with or
93b2bd0f6Slogwang * without modifications are expressly permitted by Whistle Communications;
103b2bd0f6Slogwang * provided, however, that:
113b2bd0f6Slogwang * 1. Any and all reproductions of the source or object code must include the
123b2bd0f6Slogwang * copyright notice above and the following disclaimer of warranties; and
133b2bd0f6Slogwang * 2. No rights are granted, in any manner or form, to use Whistle
143b2bd0f6Slogwang * Communications, Inc. trademarks, including the mark "WHISTLE
153b2bd0f6Slogwang * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
163b2bd0f6Slogwang * such appears in the above copyright notice or in the software.
173b2bd0f6Slogwang *
183b2bd0f6Slogwang * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
193b2bd0f6Slogwang * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
203b2bd0f6Slogwang * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
213b2bd0f6Slogwang * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
223b2bd0f6Slogwang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
233b2bd0f6Slogwang * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
243b2bd0f6Slogwang * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
253b2bd0f6Slogwang * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
263b2bd0f6Slogwang * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
273b2bd0f6Slogwang * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
283b2bd0f6Slogwang * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
293b2bd0f6Slogwang * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
303b2bd0f6Slogwang * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
313b2bd0f6Slogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
323b2bd0f6Slogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
333b2bd0f6Slogwang * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
343b2bd0f6Slogwang * OF SUCH DAMAGE.
353b2bd0f6Slogwang *
363b2bd0f6Slogwang * Author: Archie Cobbs <[email protected]>
373b2bd0f6Slogwang *
383b2bd0f6Slogwang * $Whistle: sock.c,v 1.12 1999/01/20 00:57:23 archie Exp $
393b2bd0f6Slogwang */
403b2bd0f6Slogwang
413b2bd0f6Slogwang #include <sys/cdefs.h>
423b2bd0f6Slogwang __FBSDID("$FreeBSD$");
433b2bd0f6Slogwang
443b2bd0f6Slogwang #include <sys/types.h>
453b2bd0f6Slogwang #include <sys/socket.h>
463b2bd0f6Slogwang #include <stdarg.h>
473b2bd0f6Slogwang #include <netgraph/ng_message.h>
483b2bd0f6Slogwang #include <netgraph/ng_socket.h>
493b2bd0f6Slogwang
503b2bd0f6Slogwang #include "netgraph.h"
513b2bd0f6Slogwang #include "internal.h"
523b2bd0f6Slogwang
533b2bd0f6Slogwang /* The socket node type KLD */
543b2bd0f6Slogwang #define NG_SOCKET_KLD "ng_socket.ko"
553b2bd0f6Slogwang
563b2bd0f6Slogwang /*
573b2bd0f6Slogwang * Create a socket type node and give it the supplied name.
583b2bd0f6Slogwang * Return data and control sockets corresponding to the node.
593b2bd0f6Slogwang * Returns -1 if error and sets errno.
603b2bd0f6Slogwang */
613b2bd0f6Slogwang int
NgMkSockNode(const char * name,int * csp,int * dsp)623b2bd0f6Slogwang NgMkSockNode(const char *name, int *csp, int *dsp)
633b2bd0f6Slogwang {
643b2bd0f6Slogwang char namebuf[NG_NODESIZ];
653b2bd0f6Slogwang int cs = -1; /* control socket */
663b2bd0f6Slogwang int ds = -1; /* data socket */
673b2bd0f6Slogwang int errnosv;
683b2bd0f6Slogwang
693b2bd0f6Slogwang /* Empty name means no name */
703b2bd0f6Slogwang if (name && *name == 0)
713b2bd0f6Slogwang name = NULL;
723b2bd0f6Slogwang
733b2bd0f6Slogwang /* Create control socket; this also creates the netgraph node.
743b2bd0f6Slogwang If we get an EAFNOSUPPORT then the socket node type is
753b2bd0f6Slogwang not loaded, so load it and try again. */
763b2bd0f6Slogwang if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
77*d4a07e70Sfengbojiang #ifndef FSTACK
783b2bd0f6Slogwang if (errno == EAFNOSUPPORT) {
793b2bd0f6Slogwang if (kldload(NG_SOCKET_KLD) < 0) {
803b2bd0f6Slogwang errnosv = errno;
813b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
823b2bd0f6Slogwang NGLOG("can't load %s", NG_SOCKET_KLD);
833b2bd0f6Slogwang goto errout;
843b2bd0f6Slogwang }
853b2bd0f6Slogwang cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
863b2bd0f6Slogwang if (cs >= 0)
873b2bd0f6Slogwang goto gotNode;
883b2bd0f6Slogwang }
89*d4a07e70Sfengbojiang #endif
903b2bd0f6Slogwang errnosv = errno;
913b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
923b2bd0f6Slogwang NGLOG("socket");
933b2bd0f6Slogwang goto errout;
943b2bd0f6Slogwang }
953b2bd0f6Slogwang
96*d4a07e70Sfengbojiang #ifndef FSTACK
973b2bd0f6Slogwang gotNode:
98*d4a07e70Sfengbojiang #endif
993b2bd0f6Slogwang /* Assign the node the desired name, if any */
1003b2bd0f6Slogwang if (name != NULL) {
1013b2bd0f6Slogwang u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD];
1023b2bd0f6Slogwang struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
1033b2bd0f6Slogwang
1043b2bd0f6Slogwang /* Assign name */
1053b2bd0f6Slogwang strlcpy(sg->sg_data, name, NG_NODESIZ);
1063b2bd0f6Slogwang sg->sg_family = AF_NETGRAPH;
1073b2bd0f6Slogwang sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
1083b2bd0f6Slogwang if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
1093b2bd0f6Slogwang errnosv = errno;
1103b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
1113b2bd0f6Slogwang NGLOG("bind(%s)", sg->sg_data);
1123b2bd0f6Slogwang goto errout;
1133b2bd0f6Slogwang }
1143b2bd0f6Slogwang
1153b2bd0f6Slogwang /* Save node name */
1163b2bd0f6Slogwang strlcpy(namebuf, name, sizeof(namebuf));
1173b2bd0f6Slogwang } else if (dsp != NULL) {
1183b2bd0f6Slogwang union {
1193b2bd0f6Slogwang u_char rbuf[sizeof(struct ng_mesg) +
1203b2bd0f6Slogwang sizeof(struct nodeinfo)];
1213b2bd0f6Slogwang struct ng_mesg res;
1223b2bd0f6Slogwang } res;
1233b2bd0f6Slogwang struct nodeinfo *const ni = (struct nodeinfo *) res.res.data;
1243b2bd0f6Slogwang
1253b2bd0f6Slogwang /* Find out the node ID */
1263b2bd0f6Slogwang if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
1273b2bd0f6Slogwang NGM_NODEINFO, NULL, 0) < 0) {
1283b2bd0f6Slogwang errnosv = errno;
1293b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
1303b2bd0f6Slogwang NGLOG("send nodeinfo");
1313b2bd0f6Slogwang goto errout;
1323b2bd0f6Slogwang }
1333b2bd0f6Slogwang if (NgRecvMsg(cs, &res.res, sizeof(res.rbuf), NULL) < 0) {
1343b2bd0f6Slogwang errnosv = errno;
1353b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
1363b2bd0f6Slogwang NGLOG("recv nodeinfo");
1373b2bd0f6Slogwang goto errout;
1383b2bd0f6Slogwang }
1393b2bd0f6Slogwang
1403b2bd0f6Slogwang /* Save node "name" */
1413b2bd0f6Slogwang snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
1423b2bd0f6Slogwang }
1433b2bd0f6Slogwang
1443b2bd0f6Slogwang /* Create data socket if desired */
1453b2bd0f6Slogwang if (dsp != NULL) {
1463b2bd0f6Slogwang u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD];
1473b2bd0f6Slogwang struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
1483b2bd0f6Slogwang
1493b2bd0f6Slogwang /* Create data socket, initially just "floating" */
1503b2bd0f6Slogwang if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
1513b2bd0f6Slogwang errnosv = errno;
1523b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
1533b2bd0f6Slogwang NGLOG("socket");
1543b2bd0f6Slogwang goto errout;
1553b2bd0f6Slogwang }
1563b2bd0f6Slogwang
1573b2bd0f6Slogwang /* Associate the data socket with the node */
1583b2bd0f6Slogwang snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
1593b2bd0f6Slogwang sg->sg_family = AF_NETGRAPH;
1603b2bd0f6Slogwang sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
1613b2bd0f6Slogwang if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
1623b2bd0f6Slogwang errnosv = errno;
1633b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
1643b2bd0f6Slogwang NGLOG("connect(%s)", sg->sg_data);
1653b2bd0f6Slogwang goto errout;
1663b2bd0f6Slogwang }
1673b2bd0f6Slogwang }
1683b2bd0f6Slogwang
1693b2bd0f6Slogwang /* Return the socket(s) */
1703b2bd0f6Slogwang if (csp)
1713b2bd0f6Slogwang *csp = cs;
1723b2bd0f6Slogwang else
1733b2bd0f6Slogwang close(cs);
1743b2bd0f6Slogwang if (dsp)
1753b2bd0f6Slogwang *dsp = ds;
1763b2bd0f6Slogwang return (0);
1773b2bd0f6Slogwang
1783b2bd0f6Slogwang errout:
1793b2bd0f6Slogwang /* Failed */
1803b2bd0f6Slogwang if (cs >= 0)
1813b2bd0f6Slogwang close(cs);
1823b2bd0f6Slogwang if (ds >= 0)
1833b2bd0f6Slogwang close(ds);
1843b2bd0f6Slogwang errno = errnosv;
1853b2bd0f6Slogwang return (-1);
1863b2bd0f6Slogwang }
1873b2bd0f6Slogwang
1883b2bd0f6Slogwang /*
1893b2bd0f6Slogwang * Assign a globally unique name to a node
1903b2bd0f6Slogwang * Returns -1 if error and sets errno.
1913b2bd0f6Slogwang */
1923b2bd0f6Slogwang int
NgNameNode(int cs,const char * path,const char * fmt,...)1933b2bd0f6Slogwang NgNameNode(int cs, const char *path, const char *fmt, ...)
1943b2bd0f6Slogwang {
1953b2bd0f6Slogwang struct ngm_name ngn;
1963b2bd0f6Slogwang va_list args;
1973b2bd0f6Slogwang
1983b2bd0f6Slogwang /* Build message arg */
1993b2bd0f6Slogwang va_start(args, fmt);
2003b2bd0f6Slogwang vsnprintf(ngn.name, sizeof(ngn.name), fmt, args);
2013b2bd0f6Slogwang va_end(args);
2023b2bd0f6Slogwang
2033b2bd0f6Slogwang /* Send message */
2043b2bd0f6Slogwang if (NgSendMsg(cs, path,
2053b2bd0f6Slogwang NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) {
2063b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
2073b2bd0f6Slogwang NGLOGX("%s: failed", __func__);
2083b2bd0f6Slogwang return (-1);
2093b2bd0f6Slogwang }
2103b2bd0f6Slogwang
2113b2bd0f6Slogwang /* Done */
2123b2bd0f6Slogwang return (0);
2133b2bd0f6Slogwang }
2143b2bd0f6Slogwang
2153b2bd0f6Slogwang /*
2163b2bd0f6Slogwang * Read a packet from a data socket
2173b2bd0f6Slogwang * Returns -1 if error and sets errno.
2183b2bd0f6Slogwang */
2193b2bd0f6Slogwang int
NgRecvData(int ds,u_char * buf,size_t len,char * hook)2203b2bd0f6Slogwang NgRecvData(int ds, u_char * buf, size_t len, char *hook)
2213b2bd0f6Slogwang {
2223b2bd0f6Slogwang u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD];
2233b2bd0f6Slogwang struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf;
2243b2bd0f6Slogwang socklen_t fromlen = sizeof(frombuf);
2253b2bd0f6Slogwang int rtn, errnosv;
2263b2bd0f6Slogwang
2273b2bd0f6Slogwang /* Read packet */
2283b2bd0f6Slogwang rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen);
2293b2bd0f6Slogwang if (rtn < 0) {
2303b2bd0f6Slogwang errnosv = errno;
2313b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
2323b2bd0f6Slogwang NGLOG("recvfrom");
2333b2bd0f6Slogwang errno = errnosv;
2343b2bd0f6Slogwang return (-1);
2353b2bd0f6Slogwang }
2363b2bd0f6Slogwang
2373b2bd0f6Slogwang /* Copy hook name */
2383b2bd0f6Slogwang if (hook != NULL)
2393b2bd0f6Slogwang strlcpy(hook, from->sg_data, NG_HOOKSIZ);
2403b2bd0f6Slogwang
2413b2bd0f6Slogwang /* Debugging */
2423b2bd0f6Slogwang if (_gNgDebugLevel >= 2) {
2433b2bd0f6Slogwang NGLOGX("READ %s from hook \"%s\" (%d bytes)",
2443b2bd0f6Slogwang rtn ? "PACKET" : "EOF", from->sg_data, rtn);
2453b2bd0f6Slogwang if (_gNgDebugLevel >= 3)
2463b2bd0f6Slogwang _NgDebugBytes(buf, rtn);
2473b2bd0f6Slogwang }
2483b2bd0f6Slogwang
2493b2bd0f6Slogwang /* Done */
2503b2bd0f6Slogwang return (rtn);
2513b2bd0f6Slogwang }
2523b2bd0f6Slogwang
2533b2bd0f6Slogwang /*
2543b2bd0f6Slogwang * Identical to NgRecvData() except buffer is dynamically allocated.
2553b2bd0f6Slogwang */
2563b2bd0f6Slogwang int
NgAllocRecvData(int ds,u_char ** buf,char * hook)2573b2bd0f6Slogwang NgAllocRecvData(int ds, u_char **buf, char *hook)
2583b2bd0f6Slogwang {
2593b2bd0f6Slogwang int len;
260*d4a07e70Sfengbojiang #ifndef FSTACK
2613b2bd0f6Slogwang socklen_t optlen;
2623b2bd0f6Slogwang
2633b2bd0f6Slogwang optlen = sizeof(len);
2643b2bd0f6Slogwang if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
265*d4a07e70Sfengbojiang #else
266*d4a07e70Sfengbojiang len = NGCTL_DEFAULT_RCVBUF;
267*d4a07e70Sfengbojiang if (
268*d4a07e70Sfengbojiang #endif
2693b2bd0f6Slogwang (*buf = malloc(len)) == NULL)
2703b2bd0f6Slogwang return (-1);
2713b2bd0f6Slogwang if ((len = NgRecvData(ds, *buf, len, hook)) < 0)
2723b2bd0f6Slogwang free(*buf);
2733b2bd0f6Slogwang return (len);
2743b2bd0f6Slogwang }
2753b2bd0f6Slogwang
2763b2bd0f6Slogwang /*
2773b2bd0f6Slogwang * Write a packet to a data socket. The packet will be sent
2783b2bd0f6Slogwang * out the corresponding node on the specified hook.
2793b2bd0f6Slogwang * Returns -1 if error and sets errno.
2803b2bd0f6Slogwang */
2813b2bd0f6Slogwang int
NgSendData(int ds,const char * hook,const u_char * buf,size_t len)2823b2bd0f6Slogwang NgSendData(int ds, const char *hook, const u_char * buf, size_t len)
2833b2bd0f6Slogwang {
2843b2bd0f6Slogwang u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD];
2853b2bd0f6Slogwang struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
2863b2bd0f6Slogwang int errnosv;
2873b2bd0f6Slogwang
2883b2bd0f6Slogwang /* Set up destination hook */
2893b2bd0f6Slogwang sg->sg_family = AF_NETGRAPH;
2903b2bd0f6Slogwang strlcpy(sg->sg_data, hook, NG_HOOKSIZ);
2913b2bd0f6Slogwang sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
2923b2bd0f6Slogwang
2933b2bd0f6Slogwang /* Debugging */
2943b2bd0f6Slogwang if (_gNgDebugLevel >= 2) {
2953b2bd0f6Slogwang NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len);
2963b2bd0f6Slogwang _NgDebugSockaddr(sg);
2973b2bd0f6Slogwang if (_gNgDebugLevel >= 3)
2983b2bd0f6Slogwang _NgDebugBytes(buf, len);
2993b2bd0f6Slogwang }
3003b2bd0f6Slogwang
3013b2bd0f6Slogwang /* Send packet */
3023b2bd0f6Slogwang if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
3033b2bd0f6Slogwang errnosv = errno;
3043b2bd0f6Slogwang if (_gNgDebugLevel >= 1)
3053b2bd0f6Slogwang NGLOG("sendto(%s)", sg->sg_data);
3063b2bd0f6Slogwang errno = errnosv;
3073b2bd0f6Slogwang return (-1);
3083b2bd0f6Slogwang }
3093b2bd0f6Slogwang
3103b2bd0f6Slogwang /* Done */
3113b2bd0f6Slogwang return (0);
3123b2bd0f6Slogwang }
3133b2bd0f6Slogwang
314