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@freebsd.org>
38 *
39 * $FreeBSD$
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/mbuf.h>
52 #include <sys/proc.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>
59 #include <sys/uio.h>
60 #include <sys/un.h>
61
62 #include <netgraph/ng_message.h>
63 #include <netgraph/netgraph.h>
64 #include <netgraph/ng_parse.h>
65 #include <netgraph/ng_ksocket.h>
66
67 #include <netinet/in.h>
68 #include <netatalk/at.h>
69
70 #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
71 #define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data))
72
73 /* Node private data */
74 struct ng_ksocket_private {
75 hook_p hook;
76 struct socket *so;
77 };
78 typedef struct ng_ksocket_private *priv_p;
79
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;
87
88 /* Alias structure */
89 struct ng_ksocket_alias {
90 const char *name;
91 const int value;
92 const int family;
93 };
94
95 /* Protocol family aliases */
96 static const struct ng_ksocket_alias ng_ksocket_families[] = {
97 { "local", PF_LOCAL },
98 { "inet", PF_INET },
99 { "inet6", PF_INET6 },
100 { "atalk", PF_APPLETALK },
101 { "ipx", PF_IPX },
102 { "atm", PF_ATM },
103 { NULL, -1 },
104 };
105
106 /* Socket type aliases */
107 static const struct ng_ksocket_alias ng_ksocket_types[] = {
108 { "stream", SOCK_STREAM },
109 { "dgram", SOCK_DGRAM },
110 { "raw", SOCK_RAW },
111 { "rdm", SOCK_RDM },
112 { "seqpacket", SOCK_SEQPACKET },
113 { NULL, -1 },
114 };
115
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 },
132 { NULL, -1 },
133 };
134
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);
139
140 /************************************************************************
141 STRUCT SOCKADDR PARSE TYPE
142 ************************************************************************/
143
144 /* Get the length of the data portion of a generic struct sockaddr */
145 static int
146 ng_parse_generic_sockdata_getLength(const struct ng_parse_type *type,
147 const u_char *start, const u_char *buf)
148 {
149 const struct sockaddr *sa;
150
151 sa = (const struct sockaddr *)(buf - SADATA_OFFSET);
152 return sa->sa_len - SADATA_OFFSET;
153 }
154
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
159 };
160
161 /* Type for a generic struct sockaddr */
162 static const struct ng_parse_struct_info ng_parse_generic_sockaddr_type_info = {
163 {
164 { "len", &ng_parse_int8_type },
165 { "family", &ng_parse_int8_type },
166 { "data", &ng_ksocket_generic_sockdata_type },
167 { NULL }
168 }
169 };
170 static const struct ng_parse_type ng_ksocket_generic_sockaddr_type = {
171 &ng_parse_struct_type,
172 &ng_parse_generic_sockaddr_type_info
173 };
174
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. */
178 static int
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)
182 {
183 struct sockaddr *const sa = (struct sockaddr *)buf;
184 enum ng_parse_token tok;
185 char fambuf[32];
186 int family, len;
187 char *t;
188
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);
194 }
195
196 /* Get socket address family followed by a slash */
197 while (isspace(s[*off]))
198 (*off)++;
199 if ((t = index(s + *off, '/')) == NULL)
200 return (EINVAL);
201 if ((len = t - (s + *off)) > sizeof(fambuf) - 1)
202 return (EINVAL);
203 strncpy(fambuf, s + *off, len);
204 fambuf[len] = '\0';
205 *off += len + 1;
206 if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1)
207 return (EINVAL);
208
209 /* Set family */
210 if (*buflen < SADATA_OFFSET)
211 return (ERANGE);
212 sa->sa_family = family;
213
214 /* Set family-specific data and length */
215 switch (sa->sa_family) {
216 case PF_LOCAL: /* Get pathname */
217 {
218 const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
219 struct sockaddr_un *const sun = (struct sockaddr_un *)sa;
220 int toklen, pathlen;
221 char *path;
222
223 if ((path = ng_get_string_token(s, off, &toklen)) == NULL)
224 return (EINVAL);
225 pathlen = strlen(path);
226 if (pathlen > SOCK_MAXADDRLEN) {
227 FREE(path, M_NETGRAPH);
228 return (E2BIG);
229 }
230 if (*buflen < pathoff + pathlen) {
231 FREE(path, M_NETGRAPH);
232 return (ERANGE);
233 }
234 *off += toklen;
235 bcopy(path, sun->sun_path, pathlen);
236 sun->sun_len = pathoff + pathlen;
237 FREE(path, M_NETGRAPH);
238 break;
239 }
240
241 case PF_INET: /* Get an IP address with optional port */
242 {
243 struct sockaddr_in *const sin = (struct sockaddr_in *)sa;
244 int i;
245
246 /* Parse this: <ipaddress>[:port] */
247 for (i = 0; i < 4; i++) {
248 u_long val;
249 char *eptr;
250
251 val = strtoul(s + *off, &eptr, 10);
252 if (val > 0xff || eptr == s + *off)
253 return (EINVAL);
254 *off += (eptr - (s + *off));
255 ((u_char *)&sin->sin_addr)[i] = (u_char)val;
256 if (i < 3) {
257 if (s[*off] != '.')
258 return (EINVAL);
259 (*off)++;
260 } else if (s[*off] == ':') {
261 (*off)++;
262 val = strtoul(s + *off, &eptr, 10);
263 if (val > 0xffff || eptr == s + *off)
264 return (EINVAL);
265 *off += (eptr - (s + *off));
266 sin->sin_port = htons(val);
267 } else
268 sin->sin_port = 0;
269 }
270 bzero(&sin->sin_zero, sizeof(sin->sin_zero));
271 sin->sin_len = sizeof(*sin);
272 break;
273 }
274
275 #if 0
276 case PF_APPLETALK: /* XXX implement these someday */
277 case PF_INET6:
278 case PF_IPX:
279 #endif
280
281 default:
282 return (EINVAL);
283 }
284
285 /* Done */
286 *buflen = sa->sa_len;
287 return (0);
288 }
289
290 /* Convert a struct sockaddr from binary to ASCII */
291 static int
292 ng_ksocket_sockaddr_unparse(const struct ng_parse_type *type,
293 const u_char *data, int *off, char *cbuf, int cbuflen)
294 {
295 const struct sockaddr *sa = (const struct sockaddr *)(data + *off);
296 int slen = 0;
297
298 /* Output socket address, either in special or generic format */
299 switch (sa->sa_family) {
300 case PF_LOCAL:
301 {
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];
306 char *pathtoken;
307
308 bcopy(sun->sun_path, pathbuf, pathlen);
309 pathbuf[pathlen] = '\0';
310 if ((pathtoken = ng_encode_string(pathbuf)) == NULL)
311 return (ENOMEM);
312 slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken);
313 FREE(pathtoken, M_NETGRAPH);
314 if (slen >= cbuflen)
315 return (ERANGE);
316 *off += sun->sun_len;
317 return (0);
318 }
319
320 case PF_INET:
321 {
322 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
323
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));
333 }
334 if (slen >= cbuflen)
335 return (ERANGE);
336 *off += sizeof(*sin);
337 return(0);
338 }
339
340 #if 0
341 case PF_APPLETALK: /* XXX implement these someday */
342 case PF_INET6:
343 case PF_IPX:
344 #endif
345
346 default:
347 return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
348 (&ng_ksocket_generic_sockaddr_type,
349 data, off, cbuf, cbuflen);
350 }
351 }
352
353 /* Parse type for struct sockaddr */
354 static const struct ng_parse_type ng_ksocket_sockaddr_type = {
355 NULL,
356 NULL,
357 NULL,
358 &ng_ksocket_sockaddr_parse,
359 &ng_ksocket_sockaddr_unparse,
360 NULL /* no such thing as a default struct sockaddr */
361 };
362
363 /************************************************************************
364 STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
365 ************************************************************************/
366
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. */
370 static int
371 ng_parse_sockoptval_getLength(const struct ng_parse_type *type,
372 const u_char *start, const u_char *buf)
373 {
374 static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
375 const struct ng_ksocket_sockopt *sopt;
376 const struct ng_mesg *msg;
377
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);
381 }
382
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
390 };
391
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,
398 };
399
400 /* List of commands and how to convert arguments to/from ASCII */
401 static const struct ng_cmdlist ng_ksocket_cmds[] = {
402 {
403 NGM_KSOCKET_COOKIE,
404 NGM_KSOCKET_BIND,
405 "bind",
406 &ng_ksocket_sockaddr_type,
407 NULL
408 },
409 {
410 NGM_KSOCKET_COOKIE,
411 NGM_KSOCKET_LISTEN,
412 "listen",
413 &ng_parse_int32_type,
414 NULL
415 },
416 {
417 NGM_KSOCKET_COOKIE,
418 NGM_KSOCKET_ACCEPT,
419 "accept",
420 NULL,
421 &ng_ksocket_sockaddr_type
422 },
423 {
424 NGM_KSOCKET_COOKIE,
425 NGM_KSOCKET_CONNECT,
426 "connect",
427 &ng_ksocket_sockaddr_type,
428 NULL
429 },
430 {
431 NGM_KSOCKET_COOKIE,
432 NGM_KSOCKET_GETNAME,
433 "getname",
434 NULL,
435 &ng_ksocket_sockaddr_type
436 },
437 {
438 NGM_KSOCKET_COOKIE,
439 NGM_KSOCKET_GETPEERNAME,
440 "getpeername",
441 NULL,
442 &ng_ksocket_sockaddr_type
443 },
444 {
445 NGM_KSOCKET_COOKIE,
446 NGM_KSOCKET_SETOPT,
447 "setopt",
448 &ng_ksocket_sockopt_type,
449 NULL
450 },
451 {
452 NGM_KSOCKET_COOKIE,
453 NGM_KSOCKET_GETOPT,
454 "getopt",
455 &ng_ksocket_sockopt_type,
456 &ng_ksocket_sockopt_type
457 },
458 { 0 }
459 };
460
461 /* Node type descriptor */
462 static struct ng_type ng_ksocket_typestruct = {
463 NG_VERSION,
464 NG_KSOCKET_NODE_TYPE,
465 NULL,
466 ng_ksocket_constructor,
467 ng_ksocket_rcvmsg,
468 ng_ksocket_rmnode,
469 ng_ksocket_newhook,
470 NULL,
471 NULL,
472 ng_ksocket_rcvdata,
473 ng_ksocket_rcvdata,
474 ng_ksocket_disconnect,
475 ng_ksocket_cmds
476 };
477 NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
478
479 #define ERROUT(x) do { error = (x); goto done; } while (0)
480
481 /************************************************************************
482 NETGRAPH NODE STUFF
483 ************************************************************************/
484
485 /*
486 * Node type constructor
487 */
488 static int
489 ng_ksocket_constructor(node_p *nodep)
490 {
491 priv_p priv;
492 int error;
493
494 /* Allocate private structure */
495 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
496 if (priv == NULL)
497 return (ENOMEM);
498 bzero(priv, sizeof(*priv));
499
500 /* Call generic node constructor */
501 if ((error = ng_make_node_common(&ng_ksocket_typestruct, nodep))) {
502 FREE(priv, M_NETGRAPH);
503 return (error);
504 }
505 (*nodep)->private = priv;
506
507 /* Done */
508 return (0);
509 }
510
511 /*
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.
515 *
516 * Connecting a hook amounts to opening the socket. Disconnecting
517 * the hook closes the socket and destroys the node as well.
518 */
519 static int
520 ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
521 {
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;
526
527 /* Check if we're already connected */
528 if (priv->hook != NULL)
529 return (EISCONN);
530
531 /* Extract family, type, and protocol from hook name */
532 snprintf(name, sizeof(name), "%s", name0);
533 s1 = name;
534 if ((s2 = index(s1, '/')) == NULL)
535 return (EINVAL);
536 *s2++ = '\0';
537 if ((family = ng_ksocket_parse(ng_ksocket_families, s1, 0)) == -1)
538 return (EINVAL);
539 s1 = s2;
540 if ((s2 = index(s1, '/')) == NULL)
541 return (EINVAL);
542 *s2++ = '\0';
543 if ((type = ng_ksocket_parse(ng_ksocket_types, s1, 0)) == -1)
544 return (EINVAL);
545 s1 = s2;
546 if ((protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family)) == -1)
547 return (EINVAL);
548
549 /* Create the socket */
550 if ((error = socreate(family, &priv->so, type, protocol, p)) != 0)
551 return (error);
552
553 /* XXX call soreserve() ? */
554
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;
559
560 /* OK */
561 priv->hook = hook;
562 return (0);
563 }
564
565 /*
566 * Receive a control message
567 */
568 static int
569 ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
570 const char *raddr, struct ng_mesg **rptr)
571 {
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;
576 int error = 0;
577
578 switch (msg->header.typecookie) {
579 case NGM_KSOCKET_COOKIE:
580 switch (msg->header.cmd) {
581 case NGM_KSOCKET_BIND:
582 {
583 struct sockaddr *const sa
584 = (struct sockaddr *)msg->data;
585
586 /* Sanity check */
587 if (msg->header.arglen < SADATA_OFFSET
588 || msg->header.arglen < sa->sa_len)
589 ERROUT(EINVAL);
590 if (so == NULL)
591 ERROUT(ENXIO);
592
593 /* Bind */
594 error = sobind(so, sa, p);
595 break;
596 }
597 case NGM_KSOCKET_LISTEN:
598 {
599 /* Sanity check */
600 if (msg->header.arglen != sizeof(int))
601 ERROUT(EINVAL);
602 if (so == NULL)
603 ERROUT(ENXIO);
604
605 /* Listen */
606 if ((error = solisten(so, *((int *)msg->data), p)) != 0)
607 break;
608
609 /* Notify sender when we get a connection attempt */
610 /* XXX implement me */
611 error = ENODEV;
612 break;
613 }
614
615 case NGM_KSOCKET_ACCEPT:
616 {
617 /* Sanity check */
618 if (msg->header.arglen != 0)
619 ERROUT(EINVAL);
620 if (so == NULL)
621 ERROUT(ENXIO);
622
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 */
627
628 /* XXX implement me */
629
630 error = ENODEV;
631 break;
632 }
633
634 case NGM_KSOCKET_CONNECT:
635 {
636 struct sockaddr *const sa
637 = (struct sockaddr *)msg->data;
638
639 /* Sanity check */
640 if (msg->header.arglen < SADATA_OFFSET
641 || msg->header.arglen < sa->sa_len)
642 ERROUT(EINVAL);
643 if (so == NULL)
644 ERROUT(ENXIO);
645
646 /* Do connect */
647 if ((so->so_state & SS_ISCONNECTING) != 0)
648 ERROUT(EALREADY);
649 if ((error = soconnect(so, sa, p)) != 0) {
650 so->so_state &= ~SS_ISCONNECTING;
651 ERROUT(error);
652 }
653 if ((so->so_state & SS_ISCONNECTING) != 0)
654 /* Notify sender when we connect */
655 /* XXX implement me */
656 ERROUT(EINPROGRESS);
657 break;
658 }
659
660 case NGM_KSOCKET_GETNAME:
661 case NGM_KSOCKET_GETPEERNAME:
662 {
663 int (*func)(struct socket *so, struct sockaddr **nam);
664 struct sockaddr *sa = NULL;
665 int len;
666
667 /* Sanity check */
668 if (msg->header.arglen != 0)
669 ERROUT(EINVAL);
670 if (so == NULL)
671 ERROUT(ENXIO);
672
673 /* Get function */
674 if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
675 if ((so->so_state
676 & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
677 ERROUT(ENOTCONN);
678 func = so->so_proto->pr_usrreqs->pru_peeraddr;
679 } else
680 func = so->so_proto->pr_usrreqs->pru_sockaddr;
681
682 /* Get local or peer address */
683 if ((error = (*func)(so, &sa)) != 0)
684 goto bail;
685 len = (sa == NULL) ? 0 : sa->sa_len;
686
687 /* Send it back in a response */
688 NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
689 if (resp == NULL) {
690 error = ENOMEM;
691 goto bail;
692 }
693 bcopy(sa, resp->data, len);
694
695 bail:
696 /* Cleanup */
697 if (sa != NULL)
698 FREE(sa, M_SONAME);
699 break;
700 }
701
702 case NGM_KSOCKET_GETOPT:
703 {
704 struct ng_ksocket_sockopt *ksopt =
705 (struct ng_ksocket_sockopt *)msg->data;
706 struct sockopt sopt;
707
708 /* Sanity check */
709 if (msg->header.arglen != sizeof(*ksopt))
710 ERROUT(EINVAL);
711 if (so == NULL)
712 ERROUT(ENXIO);
713
714 /* Get response with room for option value */
715 NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
716 + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
717 if (resp == NULL)
718 ERROUT(ENOMEM);
719
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;
724 sopt.sopt_p = p;
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);
730 break;
731 }
732
733 /* Set actual value length */
734 resp->header.arglen = sizeof(*ksopt)
735 + sopt.sopt_valsize;
736 break;
737 }
738
739 case NGM_KSOCKET_SETOPT:
740 {
741 struct ng_ksocket_sockopt *const ksopt =
742 (struct ng_ksocket_sockopt *)msg->data;
743 const int valsize = msg->header.arglen - sizeof(*ksopt);
744 struct sockopt sopt;
745
746 /* Sanity check */
747 if (valsize < 0)
748 ERROUT(EINVAL);
749 if (so == NULL)
750 ERROUT(ENXIO);
751
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;
758 sopt.sopt_p = p;
759 error = sosetopt(so, &sopt);
760 break;
761 }
762
763 default:
764 error = EINVAL;
765 break;
766 }
767 break;
768 default:
769 error = EINVAL;
770 break;
771 }
772 if (rptr)
773 *rptr = resp;
774 else if (resp)
775 FREE(resp, M_NETGRAPH);
776
777 done:
778 FREE(msg, M_NETGRAPH);
779 return (error);
780 }
781
782 /*
783 * Receive incoming data on our hook. Send it out the socket.
784 */
785 static int
786 ng_ksocket_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
787 {
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;
792 int error;
793
794 NG_FREE_META(meta);
795 error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, 0, 0, m, 0, 0, p);
796 return (error);
797 }
798
799 /*
800 * Destroy node
801 */
802 static int
803 ng_ksocket_rmnode(node_p node)
804 {
805 const priv_p priv = node->private;
806
807 /* Close our socket (if any) */
808 if (priv->so != NULL) {
809
810 priv->so->so_upcall = NULL;
811 priv->so->so_rcv.sb_flags &= ~SB_UPCALL;
812 soclose(priv->so);
813 priv->so = NULL;
814 }
815
816 /* Take down netgraph node */
817 node->flags |= NG_INVALID;
818 ng_cutlinks(node);
819 ng_unname(node);
820 bzero(priv, sizeof(*priv));
821 FREE(priv, M_NETGRAPH);
822 node->private = NULL;
823 ng_unref(node); /* let the node escape */
824 return (0);
825 }
826
827 /*
828 * Hook disconnection
829 */
830 static int
831 ng_ksocket_disconnect(hook_p hook)
832 {
833 KASSERT(hook->node->numhooks == 0,
834 ("%s: numhooks=%d?", __FUNCTION__, hook->node->numhooks));
835 ng_rmnode(hook->node);
836 return (0);
837 }
838
839 /************************************************************************
840 HELPER STUFF
841 ************************************************************************/
842
843 /*
844 * When incoming data is appended to the socket, we get notified here.
845 */
846 static void
847 ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
848 {
849 const node_p node = arg;
850 const priv_p priv = node->private;
851 meta_p meta = NULL;
852 struct sockaddr *nam;
853 struct mbuf *m;
854 struct uio auio;
855 int s, flags, error;
856
857 s = splnet();
858
859 /* Sanity check */
860 if ((node->flags & NG_INVALID) != 0) {
861 splx(s);
862 return;
863 }
864 KASSERT(so == priv->so, ("%s: wrong socket", __FUNCTION__));
865 KASSERT(priv->hook != NULL, ("%s: no hook", __FUNCTION__));
866
867 /* Read and forward available mbuf's */
868 auio.uio_procp = NULL;
869 auio.uio_resid = 1000000000;
870 flags = MSG_DONTWAIT;
871 do {
872 if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
873 (so, &nam, &auio, &m, (struct mbuf **)0, &flags)) == 0
874 && m != NULL) {
875 struct mbuf *n;
876
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);
882 }
883 } while (error == 0 && m != NULL);
884 splx(s);
885 }
886
887 /*
888 * Parse out either an integer value or an alias.
889 */
890 static int
891 ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
892 const char *s, int family)
893 {
894 int k, val;
895 char *eptr;
896
897 /* Try aliases */
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;
902 }
903
904 /* Try parsing as a number */
905 val = (int)strtoul(s, &eptr, 10);
906 if (val < 0 || *eptr != '\0')
907 return (-1);
908 return (val);
909 }
910
Cache object: a8859b203806bb1b319ff77c1b5c0298
|