ng_ksocket.c revision 53404
1 2/* 3 * ng_ksocket.c 4 * 5 * Copyright (c) 1996-1999 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 * 37 * Author: Archie Cobbs <archie@whistle.com> 38 * 39 * $FreeBSD: head/sys/netgraph/ng_ksocket.c 53404 1999-11-19 05:45:11Z archie $ 40 * $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $ 41 */ 42 43/* 44 * Kernel socket node type. This node type is basically a kernel-mode 45 * version of a socket... kindof like the reverse of the socket node type. 46 */ 47 48#include <sys/param.h> 49#include <sys/systm.h> 50#include <sys/kernel.h> 51#include <sys/conf.h> 52#include <sys/mbuf.h> 53#include <sys/proc.h> 54#include <sys/malloc.h> 55#include <sys/protosw.h> 56#include <sys/errno.h> 57#include <sys/socket.h> 58#include <sys/socketvar.h> 59#include <sys/syslog.h> 60#include <sys/uio.h> 61 62#include <netgraph/ng_message.h> 63#include <netgraph/netgraph.h> 64#include <netgraph/ng_ksocket.h> 65 66#include <netinet/in.h> 67#include <netatalk/at.h> 68 69/* Node private data */ 70struct ng_ksocket_private { 71 hook_p hook; 72 struct socket *so; 73}; 74typedef struct ng_ksocket_private *priv_p; 75 76/* Netgraph node methods */ 77static ng_constructor_t ng_ksocket_constructor; 78static ng_rcvmsg_t ng_ksocket_rcvmsg; 79static ng_shutdown_t ng_ksocket_rmnode; 80static ng_newhook_t ng_ksocket_newhook; 81static ng_rcvdata_t ng_ksocket_rcvdata; 82static ng_disconnect_t ng_ksocket_disconnect; 83 84/* Alias structure */ 85struct ng_ksocket_alias { 86 const char *name; 87 const int value; 88 const int family; 89}; 90 91/* Helper functions */ 92static void ng_ksocket_incoming(struct socket *so, void *arg, int waitflag); 93static int ng_ksocket_parse(const struct ng_ksocket_alias *aliases, 94 const char *s, int family); 95 96/* Node type descriptor */ 97static struct ng_type ng_ksocket_typestruct = { 98 NG_VERSION, 99 NG_KSOCKET_NODE_TYPE, 100 NULL, 101 ng_ksocket_constructor, 102 ng_ksocket_rcvmsg, 103 ng_ksocket_rmnode, 104 ng_ksocket_newhook, 105 NULL, 106 NULL, 107 ng_ksocket_rcvdata, 108 ng_ksocket_rcvdata, 109 ng_ksocket_disconnect 110}; 111NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct); 112 113/* Protocol family aliases */ 114static const struct ng_ksocket_alias ng_ksocket_families[] = { 115 { "local", PF_LOCAL }, 116 { "inet", PF_INET }, 117 { "inet6", PF_INET6 }, 118 { "atalk", PF_APPLETALK }, 119 { "ipx", PF_IPX }, 120 { "atm", PF_ATM }, 121 { NULL, -1 }, 122}; 123 124/* Socket type aliases */ 125static const struct ng_ksocket_alias ng_ksocket_types[] = { 126 { "stream", SOCK_STREAM }, 127 { "dgram", SOCK_DGRAM }, 128 { "raw", SOCK_RAW }, 129 { "rdm", SOCK_RDM }, 130 { "seqpacket", SOCK_SEQPACKET }, 131 { NULL, -1 }, 132}; 133 134/* Protocol aliases */ 135static const struct ng_ksocket_alias ng_ksocket_protos[] = { 136 { "ip", IPPROTO_IP, PF_INET }, 137 { "raw", IPPROTO_IP, PF_INET }, 138 { "icmp", IPPROTO_ICMP, PF_INET }, 139 { "igmp", IPPROTO_IGMP, PF_INET }, 140 { "tcp", IPPROTO_TCP, PF_INET }, 141 { "udp", IPPROTO_UDP, PF_INET }, 142 { "gre", IPPROTO_GRE, PF_INET }, 143 { "esp", IPPROTO_ESP, PF_INET }, 144 { "ah", IPPROTO_AH, PF_INET }, 145 { "swipe", IPPROTO_SWIPE, PF_INET }, 146 { "encap", IPPROTO_ENCAP, PF_INET }, 147 { "divert", IPPROTO_DIVERT, PF_INET }, 148 { "ddp", ATPROTO_DDP, PF_APPLETALK }, 149 { "aarp", ATPROTO_AARP, PF_APPLETALK }, 150 { NULL, -1 }, 151}; 152 153#define ERROUT(x) do { error = (x); goto done; } while (0) 154 155/************************************************************************ 156 NETGRAPH NODE STUFF 157 ************************************************************************/ 158 159/* 160 * Node type constructor 161 */ 162static int 163ng_ksocket_constructor(node_p *nodep) 164{ 165 priv_p priv; 166 int error; 167 168 /* Allocate private structure */ 169 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK); 170 if (priv == NULL) 171 return (ENOMEM); 172 bzero(priv, sizeof(*priv)); 173 174 /* Call generic node constructor */ 175 if ((error = ng_make_node_common(&ng_ksocket_typestruct, nodep))) { 176 FREE(priv, M_NETGRAPH); 177 return (error); 178 } 179 (*nodep)->private = priv; 180 181 /* Done */ 182 return (0); 183} 184 185/* 186 * Give our OK for a hook to be added. The hook name is of the 187 * form "<family>:<type>:<proto>" where the three components may 188 * be decimal numbers or else aliases from the above lists. 189 * 190 * Connecting a hook amounts to opening the socket. Disconnecting 191 * the hook closes the socket and destroys the node as well. 192 */ 193static int 194ng_ksocket_newhook(node_p node, hook_p hook, const char *name0) 195{ 196 const priv_p priv = node->private; 197 char *s1, *s2, name[NG_HOOKLEN+1]; 198 int family, type, protocol, error; 199 struct proc *p = &proc0; /* XXX help what to do here */ 200 201 /* Check if we're already connected */ 202 if (priv->hook != NULL) 203 return (EISCONN); 204 205 /* Extract family, type, and protocol from hook name */ 206 snprintf(name, sizeof(name), "%s", name0); 207 s1 = name; 208 if ((s2 = index(s1, '/')) == NULL) 209 return (EINVAL); 210 *s2++ = '\0'; 211 if ((family = ng_ksocket_parse(ng_ksocket_families, s1, 0)) == -1) 212 return (EINVAL); 213 s1 = s2; 214 if ((s2 = index(s1, '/')) == NULL) 215 return (EINVAL); 216 *s2++ = '\0'; 217 if ((type = ng_ksocket_parse(ng_ksocket_types, s1, 0)) == -1) 218 return (EINVAL); 219 s1 = s2; 220 if ((protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family)) == -1) 221 return (EINVAL); 222 223 /* Create the socket */ 224 if ((error = socreate(family, &priv->so, type, protocol, p)) != 0) 225 return (error); 226 227 /* XXX call soreserve() ? */ 228 229 /* Add our hook for incoming data */ 230 priv->so->so_upcallarg = (caddr_t)node; 231 priv->so->so_upcall = ng_ksocket_incoming; 232 priv->so->so_rcv.sb_flags |= SB_UPCALL; 233 234 /* OK */ 235 priv->hook = hook; 236 return (0); 237} 238 239/* 240 * Receive a control message 241 */ 242static int 243ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg, 244 const char *raddr, struct ng_mesg **rptr) 245{ 246 const priv_p priv = node->private; 247 struct ng_mesg *resp = NULL; 248 struct proc *p = &proc0; 249 int error = 0; 250 251 switch (msg->header.typecookie) { 252 case NGM_KSOCKET_COOKIE: 253 switch (msg->header.cmd) { 254 case NGM_KSOCKET_BIND: 255 { 256 struct sockaddr *sa = (struct sockaddr *)msg->data; 257 struct socket *const so = priv->so; 258 259 /* Must have a connected hook first */ 260 if (priv->hook == NULL) 261 ERROUT(ENETDOWN); 262 263 /* Set and sanity check sockaddr length */ 264 if (msg->header.arglen > SOCK_MAXADDRLEN) 265 ERROUT(ENAMETOOLONG); 266 sa->sa_len = msg->header.arglen; 267 error = sobind(so, sa, p); 268 break; 269 } 270 case NGM_KSOCKET_LISTEN: 271 { 272 struct socket *const so = priv->so; 273 int backlog; 274 275 /* Must have a connected hook first */ 276 if (priv->hook == NULL) 277 ERROUT(ENETDOWN); 278 279 /* Get backlog argument */ 280 if (msg->header.arglen != sizeof(int)) 281 ERROUT(EINVAL); 282 backlog = *((int *)msg->data); 283 284 /* Do listen */ 285 if ((error = solisten(so, backlog, p)) != 0) 286 break; 287 288 /* Notify sender when we get a connection attempt */ 289 /* XXX implement me */ 290 break; 291 } 292 293 case NGM_KSOCKET_ACCEPT: 294 { 295 ERROUT(ENODEV); /* XXX implement me */ 296 break; 297 } 298 299 case NGM_KSOCKET_CONNECT: 300 { 301 struct socket *const so = priv->so; 302 struct sockaddr *sa = (struct sockaddr *)msg->data; 303 304 /* Must have a connected hook first */ 305 if (priv->hook == NULL) 306 ERROUT(ENETDOWN); 307 308 /* Set and sanity check sockaddr length */ 309 if (msg->header.arglen > SOCK_MAXADDRLEN) 310 ERROUT(ENAMETOOLONG); 311 sa->sa_len = msg->header.arglen; 312 313 /* Do connect */ 314 if ((so->so_state & SS_ISCONNECTING) != 0) 315 ERROUT(EALREADY); 316 if ((error = soconnect(so, sa, p)) != 0) { 317 so->so_state &= ~SS_ISCONNECTING; 318 ERROUT(error); 319 } 320 if ((so->so_state & SS_ISCONNECTING) != 0) 321 /* Notify sender when we connect */ 322 /* XXX implement me */ 323 ERROUT(EINPROGRESS); 324 break; 325 } 326 327 case NGM_KSOCKET_GETNAME: 328 { 329 ERROUT(ENODEV); /* XXX implement me */ 330 break; 331 } 332 333 case NGM_KSOCKET_GETPEERNAME: 334 { 335 ERROUT(ENODEV); /* XXX implement me */ 336 break; 337 } 338 339 case NGM_KSOCKET_GETOPT: 340 { 341 ERROUT(ENODEV); /* XXX implement me */ 342 break; 343 } 344 345 case NGM_KSOCKET_SETOPT: 346 { 347 ERROUT(ENODEV); /* XXX implement me */ 348 break; 349 } 350 351 default: 352 error = EINVAL; 353 break; 354 } 355 break; 356 default: 357 error = EINVAL; 358 break; 359 } 360 if (rptr) 361 *rptr = resp; 362 else if (resp) 363 FREE(resp, M_NETGRAPH); 364 365done: 366 FREE(msg, M_NETGRAPH); 367 return (error); 368} 369 370/* 371 * Receive incoming data on our hook. Send it out the socket. 372 */ 373static int 374ng_ksocket_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 375{ 376 const node_p node = hook->node; 377 const priv_p priv = node->private; 378 struct socket *const so = priv->so; 379 struct proc *p = &proc0; 380 int error; 381 382 NG_FREE_META(meta); 383 error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, 0, 0, m, 0, 0, p); 384 return (error); 385} 386 387/* 388 * Destroy node 389 */ 390static int 391ng_ksocket_rmnode(node_p node) 392{ 393 const priv_p priv = node->private; 394 395 /* Close our socket (if any) */ 396 if (priv->so != NULL) { 397 soclose(priv->so); 398 priv->so = NULL; 399 } 400 401 /* Take down netgraph node */ 402 node->flags |= NG_INVALID; 403 ng_cutlinks(node); 404 ng_unname(node); 405 bzero(priv, sizeof(*priv)); 406 FREE(priv, M_NETGRAPH); 407 node->private = NULL; 408 ng_unref(node); /* let the node escape */ 409 return (0); 410} 411 412/* 413 * Hook disconnection 414 */ 415static int 416ng_ksocket_disconnect(hook_p hook) 417{ 418 KASSERT(hook->node->numhooks == 0, 419 ("%s: numhooks=%d?", __FUNCTION__, hook->node->numhooks)); 420 ng_rmnode(hook->node); 421 return (0); 422} 423 424/************************************************************************ 425 HELPER STUFF 426 ************************************************************************/ 427 428/* 429 * When incoming data is appended to the socket, we get notified here. 430 */ 431static void 432ng_ksocket_incoming(struct socket *so, void *arg, int waitflag) 433{ 434 const node_p node = arg; 435 const priv_p priv = node->private; 436 meta_p meta = NULL; 437 struct sockaddr *nam; 438 struct mbuf *m; 439 struct uio auio; 440 int s, flags, error; 441 442 s = splnet(); 443 444 /* Sanity check */ 445 if ((node->flags & NG_INVALID) != 0) { 446 splx(s); 447 return; 448 } 449 KASSERT(so == priv->so, ("%s: wrong socket", __FUNCTION__)); 450 KASSERT(priv->hook != NULL, ("%s: no hook", __FUNCTION__)); 451 452 /* Read and forward available mbuf's */ 453 auio.uio_procp = NULL; 454 auio.uio_resid = 1000000000; 455 flags = MSG_DONTWAIT; 456 do { 457 if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive) 458 (so, &nam, &auio, &m, (struct mbuf **)0, &flags)) == 0) 459 NG_SEND_DATA(error, priv->hook, m, meta); 460 } while (error == 0 && m != NULL); 461 splx(s); 462} 463 464/* 465 * Parse out either an integer value or an alias. 466 */ 467static int 468ng_ksocket_parse(const struct ng_ksocket_alias *aliases, 469 const char *s, int family) 470{ 471 int k, val; 472 const char *eptr; 473 474 /* Try aliases */ 475 for (k = 0; aliases[k].name != NULL; k++) { 476 if (strcmp(s, aliases[k].name) == 0 477 && aliases[k].family == family) 478 return aliases[k].value; 479 } 480 481 /* Try parsing as a number */ 482 val = (int)strtoul(s, &eptr, 10); 483 if (val <= 0 || *eptr != '\0') 484 return (-1); 485 return (val); 486} 487 488