1 /* 2 * sock.c 3 * 4 * Copyright (c) 1996-1999 Whistle Communications, Inc. 5 * All rights reserved. 6 * 7 * Subject to the following obligations and disclaimer of warranty, use and 8 * redistribution of this software, in source or object code forms, with or 9 * without modifications are expressly permitted by Whistle Communications; 10 * provided, however, that: 11 * 1. Any and all reproductions of the source or object code must include the 12 * copyright notice above and the following disclaimer of warranties; and 13 * 2. No rights are granted, in any manner or form, to use Whistle 14 * Communications, Inc. trademarks, including the mark "WHISTLE 15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 16 * such appears in the above copyright notice or in the software. 17 * 18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 34 * OF SUCH DAMAGE. 35 * 36 * Author: Archie Cobbs <[email protected]> 37 * 38 * $Whistle: sock.c,v 1.12 1999/01/20 00:57:23 archie Exp $ 39 */ 40 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 #include <sys/types.h> 45 #include <sys/socket.h> 46 #include <stdarg.h> 47 #include <netgraph/ng_message.h> 48 #include <netgraph/ng_socket.h> 49 50 #include "netgraph.h" 51 #include "internal.h" 52 53 /* The socket node type KLD */ 54 #define NG_SOCKET_KLD "ng_socket.ko" 55 56 /* 57 * Create a socket type node and give it the supplied name. 58 * Return data and control sockets corresponding to the node. 59 * Returns -1 if error and sets errno. 60 */ 61 int 62 NgMkSockNode(const char *name, int *csp, int *dsp) 63 { 64 char namebuf[NG_NODESIZ]; 65 int cs = -1; /* control socket */ 66 int ds = -1; /* data socket */ 67 int errnosv; 68 69 /* Empty name means no name */ 70 if (name && *name == 0) 71 name = NULL; 72 73 /* Create control socket; this also creates the netgraph node. 74 If we get an EAFNOSUPPORT then the socket node type is 75 not loaded, so load it and try again. */ 76 if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) { 77 #ifndef FSTACK 78 if (errno == EAFNOSUPPORT) { 79 if (kldload(NG_SOCKET_KLD) < 0) { 80 errnosv = errno; 81 if (_gNgDebugLevel >= 1) 82 NGLOG("can't load %s", NG_SOCKET_KLD); 83 goto errout; 84 } 85 cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL); 86 if (cs >= 0) 87 goto gotNode; 88 } 89 #endif 90 errnosv = errno; 91 if (_gNgDebugLevel >= 1) 92 NGLOG("socket"); 93 goto errout; 94 } 95 96 #ifndef FSTACK 97 gotNode: 98 #endif 99 /* Assign the node the desired name, if any */ 100 if (name != NULL) { 101 u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD]; 102 struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 103 104 /* Assign name */ 105 strlcpy(sg->sg_data, name, NG_NODESIZ); 106 sg->sg_family = AF_NETGRAPH; 107 sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 108 if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) { 109 errnosv = errno; 110 if (_gNgDebugLevel >= 1) 111 NGLOG("bind(%s)", sg->sg_data); 112 goto errout; 113 } 114 115 /* Save node name */ 116 strlcpy(namebuf, name, sizeof(namebuf)); 117 } else if (dsp != NULL) { 118 union { 119 u_char rbuf[sizeof(struct ng_mesg) + 120 sizeof(struct nodeinfo)]; 121 struct ng_mesg res; 122 } res; 123 struct nodeinfo *const ni = (struct nodeinfo *) res.res.data; 124 125 /* Find out the node ID */ 126 if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE, 127 NGM_NODEINFO, NULL, 0) < 0) { 128 errnosv = errno; 129 if (_gNgDebugLevel >= 1) 130 NGLOG("send nodeinfo"); 131 goto errout; 132 } 133 if (NgRecvMsg(cs, &res.res, sizeof(res.rbuf), NULL) < 0) { 134 errnosv = errno; 135 if (_gNgDebugLevel >= 1) 136 NGLOG("recv nodeinfo"); 137 goto errout; 138 } 139 140 /* Save node "name" */ 141 snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id); 142 } 143 144 /* Create data socket if desired */ 145 if (dsp != NULL) { 146 u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD]; 147 struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; 148 149 /* Create data socket, initially just "floating" */ 150 if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) { 151 errnosv = errno; 152 if (_gNgDebugLevel >= 1) 153 NGLOG("socket"); 154 goto errout; 155 } 156 157 /* Associate the data socket with the node */ 158 snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf); 159 sg->sg_family = AF_NETGRAPH; 160 sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 161 if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) { 162 errnosv = errno; 163 if (_gNgDebugLevel >= 1) 164 NGLOG("connect(%s)", sg->sg_data); 165 goto errout; 166 } 167 } 168 169 /* Return the socket(s) */ 170 if (csp) 171 *csp = cs; 172 else 173 close(cs); 174 if (dsp) 175 *dsp = ds; 176 return (0); 177 178 errout: 179 /* Failed */ 180 if (cs >= 0) 181 close(cs); 182 if (ds >= 0) 183 close(ds); 184 errno = errnosv; 185 return (-1); 186 } 187 188 /* 189 * Assign a globally unique name to a node 190 * Returns -1 if error and sets errno. 191 */ 192 int 193 NgNameNode(int cs, const char *path, const char *fmt, ...) 194 { 195 struct ngm_name ngn; 196 va_list args; 197 198 /* Build message arg */ 199 va_start(args, fmt); 200 vsnprintf(ngn.name, sizeof(ngn.name), fmt, args); 201 va_end(args); 202 203 /* Send message */ 204 if (NgSendMsg(cs, path, 205 NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) { 206 if (_gNgDebugLevel >= 1) 207 NGLOGX("%s: failed", __func__); 208 return (-1); 209 } 210 211 /* Done */ 212 return (0); 213 } 214 215 /* 216 * Read a packet from a data socket 217 * Returns -1 if error and sets errno. 218 */ 219 int 220 NgRecvData(int ds, u_char * buf, size_t len, char *hook) 221 { 222 u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD]; 223 struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf; 224 socklen_t fromlen = sizeof(frombuf); 225 int rtn, errnosv; 226 227 /* Read packet */ 228 rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen); 229 if (rtn < 0) { 230 errnosv = errno; 231 if (_gNgDebugLevel >= 1) 232 NGLOG("recvfrom"); 233 errno = errnosv; 234 return (-1); 235 } 236 237 /* Copy hook name */ 238 if (hook != NULL) 239 strlcpy(hook, from->sg_data, NG_HOOKSIZ); 240 241 /* Debugging */ 242 if (_gNgDebugLevel >= 2) { 243 NGLOGX("READ %s from hook \"%s\" (%d bytes)", 244 rtn ? "PACKET" : "EOF", from->sg_data, rtn); 245 if (_gNgDebugLevel >= 3) 246 _NgDebugBytes(buf, rtn); 247 } 248 249 /* Done */ 250 return (rtn); 251 } 252 253 /* 254 * Identical to NgRecvData() except buffer is dynamically allocated. 255 */ 256 int 257 NgAllocRecvData(int ds, u_char **buf, char *hook) 258 { 259 int len; 260 #ifndef FSTACK 261 socklen_t optlen; 262 263 optlen = sizeof(len); 264 if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 || 265 #else 266 len = NGCTL_DEFAULT_RCVBUF; 267 if ( 268 #endif 269 (*buf = malloc(len)) == NULL) 270 return (-1); 271 if ((len = NgRecvData(ds, *buf, len, hook)) < 0) 272 free(*buf); 273 return (len); 274 } 275 276 /* 277 * Write a packet to a data socket. The packet will be sent 278 * out the corresponding node on the specified hook. 279 * Returns -1 if error and sets errno. 280 */ 281 int 282 NgSendData(int ds, const char *hook, const u_char * buf, size_t len) 283 { 284 u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD]; 285 struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 286 int errnosv; 287 288 /* Set up destination hook */ 289 sg->sg_family = AF_NETGRAPH; 290 strlcpy(sg->sg_data, hook, NG_HOOKSIZ); 291 sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 292 293 /* Debugging */ 294 if (_gNgDebugLevel >= 2) { 295 NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len); 296 _NgDebugSockaddr(sg); 297 if (_gNgDebugLevel >= 3) 298 _NgDebugBytes(buf, len); 299 } 300 301 /* Send packet */ 302 if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) { 303 errnosv = errno; 304 if (_gNgDebugLevel >= 1) 305 NGLOG("sendto(%s)", sg->sg_data); 306 errno = errnosv; 307 return (-1); 308 } 309 310 /* Done */ 311 return (0); 312 } 313 314