5 * Copyright (c) 1996-1999 Whistle Communications, Inc.
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.
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
37 * Author: Archie Cobbs <archie@whistle.com>
40 * $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $
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.
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
53 #include <sys/malloc.h>
54 #include <sys/ctype.h>
55 #include <sys/protosw.h>
56 #include <sys/errno.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
62 #include <netgraph/ng_message.h>
63 #include <netgraph/netgraph.h>
64 #include <netgraph/ng_parse.h>
65 #include <netgraph/ng_ksocket.h>
67 #include <netinet/in.h>
68 #include <netatalk/at.h>
70 #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
71 #define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data))
73 /* Node private data */
74 struct ng_ksocket_private {
78 typedef struct ng_ksocket_private *priv_p;
80 /* Netgraph node methods */
81 static ng_constructor_t ng_ksocket_constructor;
82 static ng_rcvmsg_t ng_ksocket_rcvmsg;
83 static ng_shutdown_t ng_ksocket_rmnode;
84 static ng_newhook_t ng_ksocket_newhook;
85 static ng_rcvdata_t ng_ksocket_rcvdata;
86 static ng_disconnect_t ng_ksocket_disconnect;
89 struct ng_ksocket_alias {
95 /* Protocol family aliases */
96 static const struct ng_ksocket_alias ng_ksocket_families[] = {
97 { "local", PF_LOCAL },
99 { "inet6", PF_INET6 },
100 { "atalk", PF_APPLETALK },
106 /* Socket type aliases */
107 static const struct ng_ksocket_alias ng_ksocket_types[] = {
108 { "stream", SOCK_STREAM },
109 { "dgram", SOCK_DGRAM },
112 { "seqpacket", SOCK_SEQPACKET },
116 /* Protocol aliases */
117 static const struct ng_ksocket_alias ng_ksocket_protos[] = {
118 { "ip", IPPROTO_IP, PF_INET },
119 { "raw", IPPROTO_IP, PF_INET },
120 { "icmp", IPPROTO_ICMP, PF_INET },
121 { "igmp", IPPROTO_IGMP, PF_INET },
122 { "tcp", IPPROTO_TCP, PF_INET },
123 { "udp", IPPROTO_UDP, PF_INET },
124 { "gre", IPPROTO_GRE, PF_INET },
125 { "esp", IPPROTO_ESP, PF_INET },
126 { "ah", IPPROTO_AH, PF_INET },
127 { "swipe", IPPROTO_SWIPE, PF_INET },
128 { "encap", IPPROTO_ENCAP, PF_INET },
129 { "divert", IPPROTO_DIVERT, PF_INET },
130 { "ddp", ATPROTO_DDP, PF_APPLETALK },
131 { "aarp", ATPROTO_AARP, PF_APPLETALK },
135 /* Helper functions */
136 static void ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
137 static int ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
138 const char *s, int family);
140 /************************************************************************
141 STRUCT SOCKADDR PARSE TYPE
142 ************************************************************************/
144 /* Get the length of the data portion of a generic struct sockaddr */
146 ng_parse_generic_sockdata_getLength(const struct ng_parse_type *type,
147 const u_char *start, const u_char *buf)
149 const struct sockaddr *sa;
151 sa = (const struct sockaddr *)(buf - SADATA_OFFSET);
152 return sa->sa_len - SADATA_OFFSET;
155 /* Type for the variable length data portion of a generic struct sockaddr */
156 static const struct ng_parse_type ng_ksocket_generic_sockdata_type = {
157 &ng_parse_bytearray_type,
158 &ng_parse_generic_sockdata_getLength
161 /* Type for a generic struct sockaddr */
162 static const struct ng_parse_struct_info ng_parse_generic_sockaddr_type_info = {
164 { "len", &ng_parse_int8_type },
165 { "family", &ng_parse_int8_type },
166 { "data", &ng_ksocket_generic_sockdata_type },
170 static const struct ng_parse_type ng_ksocket_generic_sockaddr_type = {
171 &ng_parse_struct_type,
172 &ng_parse_generic_sockaddr_type_info
175 /* Convert a struct sockaddr from ASCII to binary. If its a protocol
176 family that we specially handle, do that, otherwise defer to the
177 generic parse type ng_ksocket_generic_sockaddr_type. */
179 ng_ksocket_sockaddr_parse(const struct ng_parse_type *type,
180 const char *s, int *off, const u_char *const start,
181 u_char *const buf, int *buflen)
183 struct sockaddr *const sa = (struct sockaddr *)buf;
184 enum ng_parse_token tok;
189 /* If next token is a left curly brace, use generic parse type */
190 if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) {
191 return (*ng_ksocket_generic_sockaddr_type.supertype->parse)
192 (&ng_ksocket_generic_sockaddr_type,
193 s, off, start, buf, buflen);
196 /* Get socket address family followed by a slash */
197 while (isspace(s[*off]))
199 if ((t = index(s + *off, '/')) == NULL)
201 if ((len = t - (s + *off)) > sizeof(fambuf) - 1)
203 strncpy(fambuf, s + *off, len);
206 if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1)
210 if (*buflen < SADATA_OFFSET)
212 sa->sa_family = family;
214 /* Set family-specific data and length */
215 switch (sa->sa_family) {
216 case PF_LOCAL: /* Get pathname */
218 const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
219 struct sockaddr_un *const sun = (struct sockaddr_un *)sa;
223 if ((path = ng_get_string_token(s, off, &toklen)) == NULL)
225 pathlen = strlen(path);
226 if (pathlen > SOCK_MAXADDRLEN) {
227 FREE(path, M_NETGRAPH);
230 if (*buflen < pathoff + pathlen) {
231 FREE(path, M_NETGRAPH);
235 bcopy(path, sun->sun_path, pathlen);
236 sun->sun_len = pathoff + pathlen;
237 FREE(path, M_NETGRAPH);
241 case PF_INET: /* Get an IP address with optional port */
243 struct sockaddr_in *const sin = (struct sockaddr_in *)sa;
246 /* Parse this: <ipaddress>[:port] */
247 for (i = 0; i < 4; i++) {
251 val = strtoul(s + *off, &eptr, 10);
252 if (val > 0xff || eptr == s + *off)
254 *off += (eptr - (s + *off));
255 ((u_char *)&sin->sin_addr)[i] = (u_char)val;
260 } else if (s[*off] == ':') {
262 val = strtoul(s + *off, &eptr, 10);
263 if (val > 0xffff || eptr == s + *off)
265 *off += (eptr - (s + *off));
266 sin->sin_port = htons(val);
270 bzero(&sin->sin_zero, sizeof(sin->sin_zero));
271 sin->sin_len = sizeof(*sin);
276 case PF_APPLETALK: /* XXX implement these someday */
286 *buflen = sa->sa_len;
290 /* Convert a struct sockaddr from binary to ASCII */
292 ng_ksocket_sockaddr_unparse(const struct ng_parse_type *type,
293 const u_char *data, int *off, char *cbuf, int cbuflen)
295 const struct sockaddr *sa = (const struct sockaddr *)(data + *off);
298 /* Output socket address, either in special or generic format */
299 switch (sa->sa_family) {
302 const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
303 const struct sockaddr_un *sun = (const struct sockaddr_un *)sa;
304 const int pathlen = sun->sun_len - pathoff;
305 char pathbuf[SOCK_MAXADDRLEN + 1];
308 bcopy(sun->sun_path, pathbuf, pathlen);
309 pathbuf[pathlen] = '\0';
310 if ((pathtoken = ng_encode_string(pathbuf)) == NULL)
312 slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken);
313 FREE(pathtoken, M_NETGRAPH);
316 *off += sun->sun_len;
322 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
324 slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d",
325 ((const u_char *)&sin->sin_addr)[0],
326 ((const u_char *)&sin->sin_addr)[1],
327 ((const u_char *)&sin->sin_addr)[2],
328 ((const u_char *)&sin->sin_addr)[3]);
329 if (sin->sin_port != 0) {
330 slen += snprintf(cbuf + strlen(cbuf),
331 cbuflen - strlen(cbuf), ":%d",
332 (u_int)ntohs(sin->sin_port));
336 *off += sizeof(*sin);
341 case PF_APPLETALK: /* XXX implement these someday */
347 return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
348 (&ng_ksocket_generic_sockaddr_type,
349 data, off, cbuf, cbuflen);
353 /* Parse type for struct sockaddr */
354 static const struct ng_parse_type ng_ksocket_sockaddr_type = {
358 &ng_ksocket_sockaddr_parse,
359 &ng_ksocket_sockaddr_unparse,
360 NULL /* no such thing as a default struct sockaddr */
363 /************************************************************************
364 STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
365 ************************************************************************/
367 /* Get length of the struct ng_ksocket_sockopt value field, which is the
368 just the excess of the message argument portion over the length of
369 the struct ng_ksocket_sockopt. */
371 ng_parse_sockoptval_getLength(const struct ng_parse_type *type,
372 const u_char *start, const u_char *buf)
374 static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
375 const struct ng_ksocket_sockopt *sopt;
376 const struct ng_mesg *msg;
378 sopt = (const struct ng_ksocket_sockopt *)(buf - offset);
379 msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg));
380 return msg->header.arglen - sizeof(*sopt);
383 /* Parse type for the option value part of a struct ng_ksocket_sockopt
384 XXX Eventually, we should handle the different socket options specially.
385 XXX This would avoid byte order problems, eg an integer value of 1 is
386 XXX going to be "[1]" for little endian or "[3=1]" for big endian. */
387 static const struct ng_parse_type ng_ksocket_sockoptval_type = {
388 &ng_parse_bytearray_type,
389 &ng_parse_sockoptval_getLength
392 /* Parse type for struct ng_ksocket_sockopt */
393 static const struct ng_parse_struct_info ng_ksocket_sockopt_type_info
394 = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type);
395 static const struct ng_parse_type ng_ksocket_sockopt_type = {
396 &ng_parse_struct_type,
397 &ng_ksocket_sockopt_type_info,
400 /* List of commands and how to convert arguments to/from ASCII */
401 static const struct ng_cmdlist ng_ksocket_cmds[] = {
406 &ng_ksocket_sockaddr_type,
413 &ng_parse_int32_type,
421 &ng_ksocket_sockaddr_type
427 &ng_ksocket_sockaddr_type,
435 &ng_ksocket_sockaddr_type
439 NGM_KSOCKET_GETPEERNAME,
442 &ng_ksocket_sockaddr_type
448 &ng_ksocket_sockopt_type,
455 &ng_ksocket_sockopt_type,
456 &ng_ksocket_sockopt_type
461 /* Node type descriptor */
462 static struct ng_type ng_ksocket_typestruct = {
464 NG_KSOCKET_NODE_TYPE,
466 ng_ksocket_constructor,
474 ng_ksocket_disconnect,
477 NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
479 #define ERROUT(x) do { error = (x); goto done; } while (0)
481 /************************************************************************
483 ************************************************************************/
486 * Node type constructor
489 ng_ksocket_constructor(node_p *nodep)
494 /* Allocate private structure */
495 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
498 bzero(priv, sizeof(*priv));
500 /* Call generic node constructor */
501 if ((error = ng_make_node_common(&ng_ksocket_typestruct, nodep))) {
502 FREE(priv, M_NETGRAPH);
505 (*nodep)->private = priv;
512 * Give our OK for a hook to be added. The hook name is of the
513 * form "<family>:<type>:<proto>" where the three components may
514 * be decimal numbers or else aliases from the above lists.
516 * Connecting a hook amounts to opening the socket. Disconnecting
517 * the hook closes the socket and destroys the node as well.
520 ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
522 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
523 const priv_p priv = node->private;
524 char *s1, *s2, name[NG_HOOKLEN+1];
525 int family, type, protocol, error;
527 /* Check if we're already connected */
528 if (priv->hook != NULL)
531 /* Extract family, type, and protocol from hook name */
532 snprintf(name, sizeof(name), "%s", name0);
534 if ((s2 = index(s1, '/')) == NULL)
537 if ((family = ng_ksocket_parse(ng_ksocket_families, s1, 0)) == -1)
540 if ((s2 = index(s1, '/')) == NULL)
543 if ((type = ng_ksocket_parse(ng_ksocket_types, s1, 0)) == -1)
546 if ((protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family)) == -1)
549 /* Create the socket */
550 if ((error = socreate(family, &priv->so, type, protocol, p)) != 0)
553 /* XXX call soreserve() ? */
555 /* Add our hook for incoming data */
556 priv->so->so_upcallarg = (caddr_t)node;
557 priv->so->so_upcall = ng_ksocket_incoming;
558 priv->so->so_rcv.sb_flags |= SB_UPCALL;
566 * Receive a control message
569 ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
570 const char *raddr, struct ng_mesg **rptr)
572 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
573 const priv_p priv = node->private;
574 struct socket *const so = priv->so;
575 struct ng_mesg *resp = NULL;
578 switch (msg->header.typecookie) {
579 case NGM_KSOCKET_COOKIE:
580 switch (msg->header.cmd) {
581 case NGM_KSOCKET_BIND:
583 struct sockaddr *const sa
584 = (struct sockaddr *)msg->data;
587 if (msg->header.arglen < SADATA_OFFSET
588 || msg->header.arglen < sa->sa_len)
594 error = sobind(so, sa, p);
597 case NGM_KSOCKET_LISTEN:
600 if (msg->header.arglen != sizeof(int))
606 if ((error = solisten(so, *((int *)msg->data), p)) != 0)
609 /* Notify sender when we get a connection attempt */
610 /* XXX implement me */
615 case NGM_KSOCKET_ACCEPT:
618 if (msg->header.arglen != 0)
623 /* Accept on the socket in a non-blocking way */
624 /* Create a new ksocket node for the new connection */
625 /* Return a response with the peer's sockaddr and
626 the absolute name of the newly created node */
628 /* XXX implement me */
634 case NGM_KSOCKET_CONNECT:
636 struct sockaddr *const sa
637 = (struct sockaddr *)msg->data;
640 if (msg->header.arglen < SADATA_OFFSET
641 || msg->header.arglen < sa->sa_len)
647 if ((so->so_state & SS_ISCONNECTING) != 0)
649 if ((error = soconnect(so, sa, p)) != 0) {
650 so->so_state &= ~SS_ISCONNECTING;
653 if ((so->so_state & SS_ISCONNECTING) != 0)
654 /* Notify sender when we connect */
655 /* XXX implement me */
660 case NGM_KSOCKET_GETNAME:
661 case NGM_KSOCKET_GETPEERNAME:
663 int (*func)(struct socket *so, struct sockaddr **nam);
664 struct sockaddr *sa = NULL;
668 if (msg->header.arglen != 0)
674 if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
676 & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
678 func = so->so_proto->pr_usrreqs->pru_peeraddr;
680 func = so->so_proto->pr_usrreqs->pru_sockaddr;
682 /* Get local or peer address */
683 if ((error = (*func)(so, &sa)) != 0)
685 len = (sa == NULL) ? 0 : sa->sa_len;
687 /* Send it back in a response */
688 NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
693 bcopy(sa, resp->data, len);
702 case NGM_KSOCKET_GETOPT:
704 struct ng_ksocket_sockopt *ksopt =
705 (struct ng_ksocket_sockopt *)msg->data;
709 if (msg->header.arglen != sizeof(*ksopt))
714 /* Get response with room for option value */
715 NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
716 + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
720 /* Get socket option, and put value in the response */
721 sopt.sopt_dir = SOPT_GET;
722 sopt.sopt_level = ksopt->level;
723 sopt.sopt_name = ksopt->name;
725 sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
726 ksopt = (struct ng_ksocket_sockopt *)resp->data;
727 sopt.sopt_val = ksopt->value;
728 if ((error = sogetopt(so, &sopt)) != 0) {
729 FREE(resp, M_NETGRAPH);
733 /* Set actual value length */
734 resp->header.arglen = sizeof(*ksopt)
739 case NGM_KSOCKET_SETOPT:
741 struct ng_ksocket_sockopt *const ksopt =
742 (struct ng_ksocket_sockopt *)msg->data;
743 const int valsize = msg->header.arglen - sizeof(*ksopt);
752 /* Set socket option */
753 sopt.sopt_dir = SOPT_SET;
754 sopt.sopt_level = ksopt->level;
755 sopt.sopt_name = ksopt->name;
756 sopt.sopt_val = ksopt->value;
757 sopt.sopt_valsize = valsize;
759 error = sosetopt(so, &sopt);
775 FREE(resp, M_NETGRAPH);
778 FREE(msg, M_NETGRAPH);
783 * Receive incoming data on our hook. Send it out the socket.
786 ng_ksocket_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
788 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
789 const node_p node = hook->node;
790 const priv_p priv = node->private;
791 struct socket *const so = priv->so;
795 error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, 0, 0, m, 0, 0, p);
803 ng_ksocket_rmnode(node_p node)
805 const priv_p priv = node->private;
807 /* Close our socket (if any) */
808 if (priv->so != NULL) {
810 priv->so->so_upcall = NULL;
811 priv->so->so_rcv.sb_flags &= ~SB_UPCALL;
816 /* Take down netgraph node */
817 node->flags |= NG_INVALID;
820 bzero(priv, sizeof(*priv));
821 FREE(priv, M_NETGRAPH);
822 node->private = NULL;
823 ng_unref(node); /* let the node escape */
831 ng_ksocket_disconnect(hook_p hook)
833 KASSERT(hook->node->numhooks == 0,
834 ("%s: numhooks=%d?", __FUNCTION__, hook->node->numhooks));
835 ng_rmnode(hook->node);
839 /************************************************************************
841 ************************************************************************/
844 * When incoming data is appended to the socket, we get notified here.
847 ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
849 const node_p node = arg;
850 const priv_p priv = node->private;
852 struct sockaddr *nam;
860 if ((node->flags & NG_INVALID) != 0) {
864 KASSERT(so == priv->so, ("%s: wrong socket", __FUNCTION__));
865 KASSERT(priv->hook != NULL, ("%s: no hook", __FUNCTION__));
867 /* Read and forward available mbuf's */
868 auio.uio_procp = NULL;
869 auio.uio_resid = 1000000000;
870 flags = MSG_DONTWAIT;
872 if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
873 (so, &nam, &auio, &m, (struct mbuf **)0, &flags)) == 0
877 /* Don't trust the various socket layers to get the
878 packet header and length correct (eg. kern/15175) */
879 for (n = m, m->m_pkthdr.len = 0; n; n = n->m_next)
880 m->m_pkthdr.len += n->m_len;
881 NG_SEND_DATA(error, priv->hook, m, meta);
883 } while (error == 0 && m != NULL);
888 * Parse out either an integer value or an alias.
891 ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
892 const char *s, int family)
898 for (k = 0; aliases[k].name != NULL; k++) {
899 if (strcmp(s, aliases[k].name) == 0
900 && aliases[k].family == family)
901 return aliases[k].value;
904 /* Try parsing as a number */
905 val = (int)strtoul(s, &eptr, 10);
906 if (val < 0 || *eptr != '\0')