Deleted Added
full compact
ng_ksocket.c (68876) ng_ksocket.c (69922)
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 *
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: head/sys/netgraph/ng_ksocket.c 68876 2000-11-18 15:17:43Z dwmalone $
39 * $FreeBSD: head/sys/netgraph/ng_ksocket.c 69922 2000-12-12 18:52:14Z julian $
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 */
74struct ng_ksocket_private {
75 hook_p hook;
76 struct socket *so;
77};
78typedef struct ng_ksocket_private *priv_p;
79
80/* Netgraph node methods */
81static ng_constructor_t ng_ksocket_constructor;
82static ng_rcvmsg_t ng_ksocket_rcvmsg;
83static ng_shutdown_t ng_ksocket_rmnode;
84static ng_newhook_t ng_ksocket_newhook;
85static ng_rcvdata_t ng_ksocket_rcvdata;
86static ng_disconnect_t ng_ksocket_disconnect;
87
88/* Alias structure */
89struct ng_ksocket_alias {
90 const char *name;
91 const int value;
92 const int family;
93};
94
95/* Protocol family aliases */
96static 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 */
107static 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 */
117static 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 */
136static void ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
137static 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 */
145static int
146ng_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) ? 0 : sa->sa_len - SADATA_OFFSET;
153}
154
155/* Type for the variable length data portion of a generic struct sockaddr */
156static 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 */
162static const struct ng_parse_struct_info ng_parse_generic_sockaddr_type_info = {
163 {
164 { "len", &ng_parse_uint8_type },
165 { "family", &ng_parse_uint8_type },
166 { "data", &ng_ksocket_generic_sockdata_type },
167 { NULL }
168 }
169};
170static 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. */
178static int
179ng_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)) == 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 */
291static int
292ng_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 if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL)
310 return (ENOMEM);
311 slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken);
312 FREE(pathtoken, M_NETGRAPH);
313 if (slen >= cbuflen)
314 return (ERANGE);
315 *off += sun->sun_len;
316 return (0);
317 }
318
319 case PF_INET:
320 {
321 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
322
323 slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d",
324 ((const u_char *)&sin->sin_addr)[0],
325 ((const u_char *)&sin->sin_addr)[1],
326 ((const u_char *)&sin->sin_addr)[2],
327 ((const u_char *)&sin->sin_addr)[3]);
328 if (sin->sin_port != 0) {
329 slen += snprintf(cbuf + strlen(cbuf),
330 cbuflen - strlen(cbuf), ":%d",
331 (u_int)ntohs(sin->sin_port));
332 }
333 if (slen >= cbuflen)
334 return (ERANGE);
335 *off += sizeof(*sin);
336 return(0);
337 }
338
339#if 0
340 case PF_APPLETALK: /* XXX implement these someday */
341 case PF_INET6:
342 case PF_IPX:
343#endif
344
345 default:
346 return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
347 (&ng_ksocket_generic_sockaddr_type,
348 data, off, cbuf, cbuflen);
349 }
350}
351
352/* Parse type for struct sockaddr */
353static const struct ng_parse_type ng_ksocket_sockaddr_type = {
354 NULL,
355 NULL,
356 NULL,
357 &ng_ksocket_sockaddr_parse,
358 &ng_ksocket_sockaddr_unparse,
359 NULL /* no such thing as a default struct sockaddr */
360};
361
362/************************************************************************
363 STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
364 ************************************************************************/
365
366/* Get length of the struct ng_ksocket_sockopt value field, which is the
367 just the excess of the message argument portion over the length of
368 the struct ng_ksocket_sockopt. */
369static int
370ng_parse_sockoptval_getLength(const struct ng_parse_type *type,
371 const u_char *start, const u_char *buf)
372{
373 static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
374 const struct ng_ksocket_sockopt *sopt;
375 const struct ng_mesg *msg;
376
377 sopt = (const struct ng_ksocket_sockopt *)(buf - offset);
378 msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg));
379 return msg->header.arglen - sizeof(*sopt);
380}
381
382/* Parse type for the option value part of a struct ng_ksocket_sockopt
383 XXX Eventually, we should handle the different socket options specially.
384 XXX This would avoid byte order problems, eg an integer value of 1 is
385 XXX going to be "[1]" for little endian or "[3=1]" for big endian. */
386static const struct ng_parse_type ng_ksocket_sockoptval_type = {
387 &ng_parse_bytearray_type,
388 &ng_parse_sockoptval_getLength
389};
390
391/* Parse type for struct ng_ksocket_sockopt */
392static const struct ng_parse_struct_info ng_ksocket_sockopt_type_info
393 = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type);
394static const struct ng_parse_type ng_ksocket_sockopt_type = {
395 &ng_parse_struct_type,
396 &ng_ksocket_sockopt_type_info,
397};
398
399/* List of commands and how to convert arguments to/from ASCII */
400static const struct ng_cmdlist ng_ksocket_cmds[] = {
401 {
402 NGM_KSOCKET_COOKIE,
403 NGM_KSOCKET_BIND,
404 "bind",
405 &ng_ksocket_sockaddr_type,
406 NULL
407 },
408 {
409 NGM_KSOCKET_COOKIE,
410 NGM_KSOCKET_LISTEN,
411 "listen",
412 &ng_parse_int32_type,
413 NULL
414 },
415 {
416 NGM_KSOCKET_COOKIE,
417 NGM_KSOCKET_ACCEPT,
418 "accept",
419 NULL,
420 &ng_ksocket_sockaddr_type
421 },
422 {
423 NGM_KSOCKET_COOKIE,
424 NGM_KSOCKET_CONNECT,
425 "connect",
426 &ng_ksocket_sockaddr_type,
427 NULL
428 },
429 {
430 NGM_KSOCKET_COOKIE,
431 NGM_KSOCKET_GETNAME,
432 "getname",
433 NULL,
434 &ng_ksocket_sockaddr_type
435 },
436 {
437 NGM_KSOCKET_COOKIE,
438 NGM_KSOCKET_GETPEERNAME,
439 "getpeername",
440 NULL,
441 &ng_ksocket_sockaddr_type
442 },
443 {
444 NGM_KSOCKET_COOKIE,
445 NGM_KSOCKET_SETOPT,
446 "setopt",
447 &ng_ksocket_sockopt_type,
448 NULL
449 },
450 {
451 NGM_KSOCKET_COOKIE,
452 NGM_KSOCKET_GETOPT,
453 "getopt",
454 &ng_ksocket_sockopt_type,
455 &ng_ksocket_sockopt_type
456 },
457 { 0 }
458};
459
460/* Node type descriptor */
461static struct ng_type ng_ksocket_typestruct = {
462 NG_VERSION,
463 NG_KSOCKET_NODE_TYPE,
464 NULL,
465 ng_ksocket_constructor,
466 ng_ksocket_rcvmsg,
467 ng_ksocket_rmnode,
468 ng_ksocket_newhook,
469 NULL,
470 NULL,
471 ng_ksocket_rcvdata,
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 */
74struct ng_ksocket_private {
75 hook_p hook;
76 struct socket *so;
77};
78typedef struct ng_ksocket_private *priv_p;
79
80/* Netgraph node methods */
81static ng_constructor_t ng_ksocket_constructor;
82static ng_rcvmsg_t ng_ksocket_rcvmsg;
83static ng_shutdown_t ng_ksocket_rmnode;
84static ng_newhook_t ng_ksocket_newhook;
85static ng_rcvdata_t ng_ksocket_rcvdata;
86static ng_disconnect_t ng_ksocket_disconnect;
87
88/* Alias structure */
89struct ng_ksocket_alias {
90 const char *name;
91 const int value;
92 const int family;
93};
94
95/* Protocol family aliases */
96static 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 */
107static 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 */
117static 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 */
136static void ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
137static 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 */
145static int
146ng_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) ? 0 : sa->sa_len - SADATA_OFFSET;
153}
154
155/* Type for the variable length data portion of a generic struct sockaddr */
156static 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 */
162static const struct ng_parse_struct_info ng_parse_generic_sockaddr_type_info = {
163 {
164 { "len", &ng_parse_uint8_type },
165 { "family", &ng_parse_uint8_type },
166 { "data", &ng_ksocket_generic_sockdata_type },
167 { NULL }
168 }
169};
170static 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. */
178static int
179ng_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)) == 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 */
291static int
292ng_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 if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL)
310 return (ENOMEM);
311 slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken);
312 FREE(pathtoken, M_NETGRAPH);
313 if (slen >= cbuflen)
314 return (ERANGE);
315 *off += sun->sun_len;
316 return (0);
317 }
318
319 case PF_INET:
320 {
321 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
322
323 slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d",
324 ((const u_char *)&sin->sin_addr)[0],
325 ((const u_char *)&sin->sin_addr)[1],
326 ((const u_char *)&sin->sin_addr)[2],
327 ((const u_char *)&sin->sin_addr)[3]);
328 if (sin->sin_port != 0) {
329 slen += snprintf(cbuf + strlen(cbuf),
330 cbuflen - strlen(cbuf), ":%d",
331 (u_int)ntohs(sin->sin_port));
332 }
333 if (slen >= cbuflen)
334 return (ERANGE);
335 *off += sizeof(*sin);
336 return(0);
337 }
338
339#if 0
340 case PF_APPLETALK: /* XXX implement these someday */
341 case PF_INET6:
342 case PF_IPX:
343#endif
344
345 default:
346 return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
347 (&ng_ksocket_generic_sockaddr_type,
348 data, off, cbuf, cbuflen);
349 }
350}
351
352/* Parse type for struct sockaddr */
353static const struct ng_parse_type ng_ksocket_sockaddr_type = {
354 NULL,
355 NULL,
356 NULL,
357 &ng_ksocket_sockaddr_parse,
358 &ng_ksocket_sockaddr_unparse,
359 NULL /* no such thing as a default struct sockaddr */
360};
361
362/************************************************************************
363 STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
364 ************************************************************************/
365
366/* Get length of the struct ng_ksocket_sockopt value field, which is the
367 just the excess of the message argument portion over the length of
368 the struct ng_ksocket_sockopt. */
369static int
370ng_parse_sockoptval_getLength(const struct ng_parse_type *type,
371 const u_char *start, const u_char *buf)
372{
373 static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
374 const struct ng_ksocket_sockopt *sopt;
375 const struct ng_mesg *msg;
376
377 sopt = (const struct ng_ksocket_sockopt *)(buf - offset);
378 msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg));
379 return msg->header.arglen - sizeof(*sopt);
380}
381
382/* Parse type for the option value part of a struct ng_ksocket_sockopt
383 XXX Eventually, we should handle the different socket options specially.
384 XXX This would avoid byte order problems, eg an integer value of 1 is
385 XXX going to be "[1]" for little endian or "[3=1]" for big endian. */
386static const struct ng_parse_type ng_ksocket_sockoptval_type = {
387 &ng_parse_bytearray_type,
388 &ng_parse_sockoptval_getLength
389};
390
391/* Parse type for struct ng_ksocket_sockopt */
392static const struct ng_parse_struct_info ng_ksocket_sockopt_type_info
393 = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type);
394static const struct ng_parse_type ng_ksocket_sockopt_type = {
395 &ng_parse_struct_type,
396 &ng_ksocket_sockopt_type_info,
397};
398
399/* List of commands and how to convert arguments to/from ASCII */
400static const struct ng_cmdlist ng_ksocket_cmds[] = {
401 {
402 NGM_KSOCKET_COOKIE,
403 NGM_KSOCKET_BIND,
404 "bind",
405 &ng_ksocket_sockaddr_type,
406 NULL
407 },
408 {
409 NGM_KSOCKET_COOKIE,
410 NGM_KSOCKET_LISTEN,
411 "listen",
412 &ng_parse_int32_type,
413 NULL
414 },
415 {
416 NGM_KSOCKET_COOKIE,
417 NGM_KSOCKET_ACCEPT,
418 "accept",
419 NULL,
420 &ng_ksocket_sockaddr_type
421 },
422 {
423 NGM_KSOCKET_COOKIE,
424 NGM_KSOCKET_CONNECT,
425 "connect",
426 &ng_ksocket_sockaddr_type,
427 NULL
428 },
429 {
430 NGM_KSOCKET_COOKIE,
431 NGM_KSOCKET_GETNAME,
432 "getname",
433 NULL,
434 &ng_ksocket_sockaddr_type
435 },
436 {
437 NGM_KSOCKET_COOKIE,
438 NGM_KSOCKET_GETPEERNAME,
439 "getpeername",
440 NULL,
441 &ng_ksocket_sockaddr_type
442 },
443 {
444 NGM_KSOCKET_COOKIE,
445 NGM_KSOCKET_SETOPT,
446 "setopt",
447 &ng_ksocket_sockopt_type,
448 NULL
449 },
450 {
451 NGM_KSOCKET_COOKIE,
452 NGM_KSOCKET_GETOPT,
453 "getopt",
454 &ng_ksocket_sockopt_type,
455 &ng_ksocket_sockopt_type
456 },
457 { 0 }
458};
459
460/* Node type descriptor */
461static struct ng_type ng_ksocket_typestruct = {
462 NG_VERSION,
463 NG_KSOCKET_NODE_TYPE,
464 NULL,
465 ng_ksocket_constructor,
466 ng_ksocket_rcvmsg,
467 ng_ksocket_rmnode,
468 ng_ksocket_newhook,
469 NULL,
470 NULL,
471 ng_ksocket_rcvdata,
472 ng_ksocket_rcvdata,
473 ng_ksocket_disconnect,
474 ng_ksocket_cmds
475};
476NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
477
478#define ERROUT(x) do { error = (x); goto done; } while (0)
479
480/************************************************************************
481 NETGRAPH NODE STUFF
482 ************************************************************************/
483
484/*
485 * Node type constructor
486 */
487static int
488ng_ksocket_constructor(node_p *nodep)
489{
490 priv_p priv;
491 int error;
492
493 /* Allocate private structure */
494 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
495 if (priv == NULL)
496 return (ENOMEM);
497
498 /* Call generic node constructor */
499 if ((error = ng_make_node_common(&ng_ksocket_typestruct, nodep))) {
500 FREE(priv, M_NETGRAPH);
501 return (error);
502 }
503 (*nodep)->private = priv;
504
505 /* Done */
506 return (0);
507}
508
509/*
510 * Give our OK for a hook to be added. The hook name is of the
511 * form "<family>:<type>:<proto>" where the three components may
512 * be decimal numbers or else aliases from the above lists.
513 *
514 * Connecting a hook amounts to opening the socket. Disconnecting
515 * the hook closes the socket and destroys the node as well.
516 */
517static int
518ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
519{
520 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
521 const priv_p priv = node->private;
522 char *s1, *s2, name[NG_HOOKLEN+1];
523 int family, type, protocol, error;
524
525 /* Check if we're already connected */
526 if (priv->hook != NULL)
527 return (EISCONN);
528
529 /* Extract family, type, and protocol from hook name */
530 snprintf(name, sizeof(name), "%s", name0);
531 s1 = name;
532 if ((s2 = index(s1, '/')) == NULL)
533 return (EINVAL);
534 *s2++ = '\0';
535 if ((family = ng_ksocket_parse(ng_ksocket_families, s1, 0)) == -1)
536 return (EINVAL);
537 s1 = s2;
538 if ((s2 = index(s1, '/')) == NULL)
539 return (EINVAL);
540 *s2++ = '\0';
541 if ((type = ng_ksocket_parse(ng_ksocket_types, s1, 0)) == -1)
542 return (EINVAL);
543 s1 = s2;
544 if ((protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family)) == -1)
545 return (EINVAL);
546
547 /* Create the socket */
548 if ((error = socreate(family, &priv->so, type, protocol, p)) != 0)
549 return (error);
550
551 /* XXX call soreserve() ? */
552
553 /* Add our hook for incoming data */
554 priv->so->so_upcallarg = (caddr_t)node;
555 priv->so->so_upcall = ng_ksocket_incoming;
556 priv->so->so_rcv.sb_flags |= SB_UPCALL;
557
558 /* OK */
559 priv->hook = hook;
560 return (0);
561}
562
563/*
564 * Receive a control message
565 */
566static int
567ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
568 const char *raddr, struct ng_mesg **rptr, hook_p lasthook)
569{
570 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
571 const priv_p priv = node->private;
572 struct socket *const so = priv->so;
573 struct ng_mesg *resp = NULL;
574 int error = 0;
575
576 switch (msg->header.typecookie) {
577 case NGM_KSOCKET_COOKIE:
578 switch (msg->header.cmd) {
579 case NGM_KSOCKET_BIND:
580 {
581 struct sockaddr *const sa
582 = (struct sockaddr *)msg->data;
583
584 /* Sanity check */
585 if (msg->header.arglen < SADATA_OFFSET
586 || msg->header.arglen < sa->sa_len)
587 ERROUT(EINVAL);
588 if (so == NULL)
589 ERROUT(ENXIO);
590
591 /* Bind */
592 error = sobind(so, sa, p);
593 break;
594 }
595 case NGM_KSOCKET_LISTEN:
596 {
597 /* Sanity check */
598 if (msg->header.arglen != sizeof(int))
599 ERROUT(EINVAL);
600 if (so == NULL)
601 ERROUT(ENXIO);
602
603 /* Listen */
604 if ((error = solisten(so, *((int *)msg->data), p)) != 0)
605 break;
606
607 /* Notify sender when we get a connection attempt */
608 /* XXX implement me */
609 error = ENODEV;
610 break;
611 }
612
613 case NGM_KSOCKET_ACCEPT:
614 {
615 /* Sanity check */
616 if (msg->header.arglen != 0)
617 ERROUT(EINVAL);
618 if (so == NULL)
619 ERROUT(ENXIO);
620
621 /* Accept on the socket in a non-blocking way */
622 /* Create a new ksocket node for the new connection */
623 /* Return a response with the peer's sockaddr and
624 the absolute name of the newly created node */
625
626 /* XXX implement me */
627
628 error = ENODEV;
629 break;
630 }
631
632 case NGM_KSOCKET_CONNECT:
633 {
634 struct sockaddr *const sa
635 = (struct sockaddr *)msg->data;
636
637 /* Sanity check */
638 if (msg->header.arglen < SADATA_OFFSET
639 || msg->header.arglen < sa->sa_len)
640 ERROUT(EINVAL);
641 if (so == NULL)
642 ERROUT(ENXIO);
643
644 /* Do connect */
645 if ((so->so_state & SS_ISCONNECTING) != 0)
646 ERROUT(EALREADY);
647 if ((error = soconnect(so, sa, p)) != 0) {
648 so->so_state &= ~SS_ISCONNECTING;
649 ERROUT(error);
650 }
651 if ((so->so_state & SS_ISCONNECTING) != 0)
652 /* Notify sender when we connect */
653 /* XXX implement me */
654 ERROUT(EINPROGRESS);
655 break;
656 }
657
658 case NGM_KSOCKET_GETNAME:
659 case NGM_KSOCKET_GETPEERNAME:
660 {
661 int (*func)(struct socket *so, struct sockaddr **nam);
662 struct sockaddr *sa = NULL;
663 int len;
664
665 /* Sanity check */
666 if (msg->header.arglen != 0)
667 ERROUT(EINVAL);
668 if (so == NULL)
669 ERROUT(ENXIO);
670
671 /* Get function */
672 if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
673 if ((so->so_state
674 & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
675 ERROUT(ENOTCONN);
676 func = so->so_proto->pr_usrreqs->pru_peeraddr;
677 } else
678 func = so->so_proto->pr_usrreqs->pru_sockaddr;
679
680 /* Get local or peer address */
681 if ((error = (*func)(so, &sa)) != 0)
682 goto bail;
683 len = (sa == NULL) ? 0 : sa->sa_len;
684
685 /* Send it back in a response */
686 NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
687 if (resp == NULL) {
688 error = ENOMEM;
689 goto bail;
690 }
691 bcopy(sa, resp->data, len);
692
693 bail:
694 /* Cleanup */
695 if (sa != NULL)
696 FREE(sa, M_SONAME);
697 break;
698 }
699
700 case NGM_KSOCKET_GETOPT:
701 {
702 struct ng_ksocket_sockopt *ksopt =
703 (struct ng_ksocket_sockopt *)msg->data;
704 struct sockopt sopt;
705
706 /* Sanity check */
707 if (msg->header.arglen != sizeof(*ksopt))
708 ERROUT(EINVAL);
709 if (so == NULL)
710 ERROUT(ENXIO);
711
712 /* Get response with room for option value */
713 NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
714 + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
715 if (resp == NULL)
716 ERROUT(ENOMEM);
717
718 /* Get socket option, and put value in the response */
719 sopt.sopt_dir = SOPT_GET;
720 sopt.sopt_level = ksopt->level;
721 sopt.sopt_name = ksopt->name;
722 sopt.sopt_p = p;
723 sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
724 ksopt = (struct ng_ksocket_sockopt *)resp->data;
725 sopt.sopt_val = ksopt->value;
726 if ((error = sogetopt(so, &sopt)) != 0) {
727 FREE(resp, M_NETGRAPH);
728 break;
729 }
730
731 /* Set actual value length */
732 resp->header.arglen = sizeof(*ksopt)
733 + sopt.sopt_valsize;
734 break;
735 }
736
737 case NGM_KSOCKET_SETOPT:
738 {
739 struct ng_ksocket_sockopt *const ksopt =
740 (struct ng_ksocket_sockopt *)msg->data;
741 const int valsize = msg->header.arglen - sizeof(*ksopt);
742 struct sockopt sopt;
743
744 /* Sanity check */
745 if (valsize < 0)
746 ERROUT(EINVAL);
747 if (so == NULL)
748 ERROUT(ENXIO);
749
750 /* Set socket option */
751 sopt.sopt_dir = SOPT_SET;
752 sopt.sopt_level = ksopt->level;
753 sopt.sopt_name = ksopt->name;
754 sopt.sopt_val = ksopt->value;
755 sopt.sopt_valsize = valsize;
756 sopt.sopt_p = p;
757 error = sosetopt(so, &sopt);
758 break;
759 }
760
761 default:
762 error = EINVAL;
763 break;
764 }
765 break;
766 default:
767 error = EINVAL;
768 break;
769 }
770 if (rptr)
771 *rptr = resp;
772 else if (resp)
773 FREE(resp, M_NETGRAPH);
774
775done:
776 FREE(msg, M_NETGRAPH);
777 return (error);
778}
779
780/*
781 * Receive incoming data on our hook. Send it out the socket.
782 */
783static int
784ng_ksocket_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
472 ng_ksocket_disconnect,
473 ng_ksocket_cmds
474};
475NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
476
477#define ERROUT(x) do { error = (x); goto done; } while (0)
478
479/************************************************************************
480 NETGRAPH NODE STUFF
481 ************************************************************************/
482
483/*
484 * Node type constructor
485 */
486static int
487ng_ksocket_constructor(node_p *nodep)
488{
489 priv_p priv;
490 int error;
491
492 /* Allocate private structure */
493 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
494 if (priv == NULL)
495 return (ENOMEM);
496
497 /* Call generic node constructor */
498 if ((error = ng_make_node_common(&ng_ksocket_typestruct, nodep))) {
499 FREE(priv, M_NETGRAPH);
500 return (error);
501 }
502 (*nodep)->private = priv;
503
504 /* Done */
505 return (0);
506}
507
508/*
509 * Give our OK for a hook to be added. The hook name is of the
510 * form "<family>:<type>:<proto>" where the three components may
511 * be decimal numbers or else aliases from the above lists.
512 *
513 * Connecting a hook amounts to opening the socket. Disconnecting
514 * the hook closes the socket and destroys the node as well.
515 */
516static int
517ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
518{
519 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
520 const priv_p priv = node->private;
521 char *s1, *s2, name[NG_HOOKLEN+1];
522 int family, type, protocol, error;
523
524 /* Check if we're already connected */
525 if (priv->hook != NULL)
526 return (EISCONN);
527
528 /* Extract family, type, and protocol from hook name */
529 snprintf(name, sizeof(name), "%s", name0);
530 s1 = name;
531 if ((s2 = index(s1, '/')) == NULL)
532 return (EINVAL);
533 *s2++ = '\0';
534 if ((family = ng_ksocket_parse(ng_ksocket_families, s1, 0)) == -1)
535 return (EINVAL);
536 s1 = s2;
537 if ((s2 = index(s1, '/')) == NULL)
538 return (EINVAL);
539 *s2++ = '\0';
540 if ((type = ng_ksocket_parse(ng_ksocket_types, s1, 0)) == -1)
541 return (EINVAL);
542 s1 = s2;
543 if ((protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family)) == -1)
544 return (EINVAL);
545
546 /* Create the socket */
547 if ((error = socreate(family, &priv->so, type, protocol, p)) != 0)
548 return (error);
549
550 /* XXX call soreserve() ? */
551
552 /* Add our hook for incoming data */
553 priv->so->so_upcallarg = (caddr_t)node;
554 priv->so->so_upcall = ng_ksocket_incoming;
555 priv->so->so_rcv.sb_flags |= SB_UPCALL;
556
557 /* OK */
558 priv->hook = hook;
559 return (0);
560}
561
562/*
563 * Receive a control message
564 */
565static int
566ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
567 const char *raddr, struct ng_mesg **rptr, hook_p lasthook)
568{
569 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
570 const priv_p priv = node->private;
571 struct socket *const so = priv->so;
572 struct ng_mesg *resp = NULL;
573 int error = 0;
574
575 switch (msg->header.typecookie) {
576 case NGM_KSOCKET_COOKIE:
577 switch (msg->header.cmd) {
578 case NGM_KSOCKET_BIND:
579 {
580 struct sockaddr *const sa
581 = (struct sockaddr *)msg->data;
582
583 /* Sanity check */
584 if (msg->header.arglen < SADATA_OFFSET
585 || msg->header.arglen < sa->sa_len)
586 ERROUT(EINVAL);
587 if (so == NULL)
588 ERROUT(ENXIO);
589
590 /* Bind */
591 error = sobind(so, sa, p);
592 break;
593 }
594 case NGM_KSOCKET_LISTEN:
595 {
596 /* Sanity check */
597 if (msg->header.arglen != sizeof(int))
598 ERROUT(EINVAL);
599 if (so == NULL)
600 ERROUT(ENXIO);
601
602 /* Listen */
603 if ((error = solisten(so, *((int *)msg->data), p)) != 0)
604 break;
605
606 /* Notify sender when we get a connection attempt */
607 /* XXX implement me */
608 error = ENODEV;
609 break;
610 }
611
612 case NGM_KSOCKET_ACCEPT:
613 {
614 /* Sanity check */
615 if (msg->header.arglen != 0)
616 ERROUT(EINVAL);
617 if (so == NULL)
618 ERROUT(ENXIO);
619
620 /* Accept on the socket in a non-blocking way */
621 /* Create a new ksocket node for the new connection */
622 /* Return a response with the peer's sockaddr and
623 the absolute name of the newly created node */
624
625 /* XXX implement me */
626
627 error = ENODEV;
628 break;
629 }
630
631 case NGM_KSOCKET_CONNECT:
632 {
633 struct sockaddr *const sa
634 = (struct sockaddr *)msg->data;
635
636 /* Sanity check */
637 if (msg->header.arglen < SADATA_OFFSET
638 || msg->header.arglen < sa->sa_len)
639 ERROUT(EINVAL);
640 if (so == NULL)
641 ERROUT(ENXIO);
642
643 /* Do connect */
644 if ((so->so_state & SS_ISCONNECTING) != 0)
645 ERROUT(EALREADY);
646 if ((error = soconnect(so, sa, p)) != 0) {
647 so->so_state &= ~SS_ISCONNECTING;
648 ERROUT(error);
649 }
650 if ((so->so_state & SS_ISCONNECTING) != 0)
651 /* Notify sender when we connect */
652 /* XXX implement me */
653 ERROUT(EINPROGRESS);
654 break;
655 }
656
657 case NGM_KSOCKET_GETNAME:
658 case NGM_KSOCKET_GETPEERNAME:
659 {
660 int (*func)(struct socket *so, struct sockaddr **nam);
661 struct sockaddr *sa = NULL;
662 int len;
663
664 /* Sanity check */
665 if (msg->header.arglen != 0)
666 ERROUT(EINVAL);
667 if (so == NULL)
668 ERROUT(ENXIO);
669
670 /* Get function */
671 if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
672 if ((so->so_state
673 & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
674 ERROUT(ENOTCONN);
675 func = so->so_proto->pr_usrreqs->pru_peeraddr;
676 } else
677 func = so->so_proto->pr_usrreqs->pru_sockaddr;
678
679 /* Get local or peer address */
680 if ((error = (*func)(so, &sa)) != 0)
681 goto bail;
682 len = (sa == NULL) ? 0 : sa->sa_len;
683
684 /* Send it back in a response */
685 NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
686 if (resp == NULL) {
687 error = ENOMEM;
688 goto bail;
689 }
690 bcopy(sa, resp->data, len);
691
692 bail:
693 /* Cleanup */
694 if (sa != NULL)
695 FREE(sa, M_SONAME);
696 break;
697 }
698
699 case NGM_KSOCKET_GETOPT:
700 {
701 struct ng_ksocket_sockopt *ksopt =
702 (struct ng_ksocket_sockopt *)msg->data;
703 struct sockopt sopt;
704
705 /* Sanity check */
706 if (msg->header.arglen != sizeof(*ksopt))
707 ERROUT(EINVAL);
708 if (so == NULL)
709 ERROUT(ENXIO);
710
711 /* Get response with room for option value */
712 NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
713 + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
714 if (resp == NULL)
715 ERROUT(ENOMEM);
716
717 /* Get socket option, and put value in the response */
718 sopt.sopt_dir = SOPT_GET;
719 sopt.sopt_level = ksopt->level;
720 sopt.sopt_name = ksopt->name;
721 sopt.sopt_p = p;
722 sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
723 ksopt = (struct ng_ksocket_sockopt *)resp->data;
724 sopt.sopt_val = ksopt->value;
725 if ((error = sogetopt(so, &sopt)) != 0) {
726 FREE(resp, M_NETGRAPH);
727 break;
728 }
729
730 /* Set actual value length */
731 resp->header.arglen = sizeof(*ksopt)
732 + sopt.sopt_valsize;
733 break;
734 }
735
736 case NGM_KSOCKET_SETOPT:
737 {
738 struct ng_ksocket_sockopt *const ksopt =
739 (struct ng_ksocket_sockopt *)msg->data;
740 const int valsize = msg->header.arglen - sizeof(*ksopt);
741 struct sockopt sopt;
742
743 /* Sanity check */
744 if (valsize < 0)
745 ERROUT(EINVAL);
746 if (so == NULL)
747 ERROUT(ENXIO);
748
749 /* Set socket option */
750 sopt.sopt_dir = SOPT_SET;
751 sopt.sopt_level = ksopt->level;
752 sopt.sopt_name = ksopt->name;
753 sopt.sopt_val = ksopt->value;
754 sopt.sopt_valsize = valsize;
755 sopt.sopt_p = p;
756 error = sosetopt(so, &sopt);
757 break;
758 }
759
760 default:
761 error = EINVAL;
762 break;
763 }
764 break;
765 default:
766 error = EINVAL;
767 break;
768 }
769 if (rptr)
770 *rptr = resp;
771 else if (resp)
772 FREE(resp, M_NETGRAPH);
773
774done:
775 FREE(msg, M_NETGRAPH);
776 return (error);
777}
778
779/*
780 * Receive incoming data on our hook. Send it out the socket.
781 */
782static int
783ng_ksocket_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
785 struct mbuf **ret_m, meta_p *ret_meta)
784 struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp)
786{
787 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
788 const node_p node = hook->node;
789 const priv_p priv = node->private;
790 struct socket *const so = priv->so;
791 int error;
792
793 NG_FREE_META(meta);
794 error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, 0, 0, m, 0, 0, p);
795 return (error);
796}
797
798/*
799 * Destroy node
800 */
801static int
802ng_ksocket_rmnode(node_p node)
803{
804 const priv_p priv = node->private;
805
806 /* Close our socket (if any) */
807 if (priv->so != NULL) {
808
809 priv->so->so_upcall = NULL;
810 priv->so->so_rcv.sb_flags &= ~SB_UPCALL;
811 soclose(priv->so);
812 priv->so = NULL;
813 }
814
815 /* Take down netgraph node */
816 node->flags |= NG_INVALID;
817 ng_cutlinks(node);
818 ng_unname(node);
819 bzero(priv, sizeof(*priv));
820 FREE(priv, M_NETGRAPH);
821 node->private = NULL;
822 ng_unref(node); /* let the node escape */
823 return (0);
824}
825
826/*
827 * Hook disconnection
828 */
829static int
830ng_ksocket_disconnect(hook_p hook)
831{
832 KASSERT(hook->node->numhooks == 0,
833 ("%s: numhooks=%d?", __FUNCTION__, hook->node->numhooks));
834 ng_rmnode(hook->node);
835 return (0);
836}
837
838/************************************************************************
839 HELPER STUFF
840 ************************************************************************/
841
842/*
843 * When incoming data is appended to the socket, we get notified here.
844 */
845static void
846ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
847{
848 const node_p node = arg;
849 const priv_p priv = node->private;
850 meta_p meta = NULL;
851 struct mbuf *m;
852 struct uio auio;
853 int s, flags, error;
854
855 s = splnet();
856
857 /* Sanity check */
858 if ((node->flags & NG_INVALID) != 0) {
859 splx(s);
860 return;
861 }
862 KASSERT(so == priv->so, ("%s: wrong socket", __FUNCTION__));
863 KASSERT(priv->hook != NULL, ("%s: no hook", __FUNCTION__));
864
865 /* Read and forward available mbuf's */
866 auio.uio_procp = NULL;
867 auio.uio_resid = 1000000000;
868 flags = MSG_DONTWAIT;
869 do {
870 if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
871 (so, (struct sockaddr **)0, &auio, &m,
872 (struct mbuf **)0, &flags)) == 0
873 && m != NULL) {
874 struct mbuf *n;
875
876 /* Don't trust the various socket layers to get the
877 packet header and length correct (eg. kern/15175) */
878 for (n = m, m->m_pkthdr.len = 0; n; n = n->m_next)
879 m->m_pkthdr.len += n->m_len;
880 NG_SEND_DATA(error, priv->hook, m, meta);
881 }
882 } while (error == 0 && m != NULL);
883 splx(s);
884}
885
886/*
887 * Parse out either an integer value or an alias.
888 */
889static int
890ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
891 const char *s, int family)
892{
893 int k, val;
894 char *eptr;
895
896 /* Try aliases */
897 for (k = 0; aliases[k].name != NULL; k++) {
898 if (strcmp(s, aliases[k].name) == 0
899 && aliases[k].family == family)
900 return aliases[k].value;
901 }
902
903 /* Try parsing as a number */
904 val = (int)strtoul(s, &eptr, 10);
905 if (val < 0 || *eptr != '\0')
906 return (-1);
907 return (val);
908}
909
785{
786 struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
787 const node_p node = hook->node;
788 const priv_p priv = node->private;
789 struct socket *const so = priv->so;
790 int error;
791
792 NG_FREE_META(meta);
793 error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, 0, 0, m, 0, 0, p);
794 return (error);
795}
796
797/*
798 * Destroy node
799 */
800static int
801ng_ksocket_rmnode(node_p node)
802{
803 const priv_p priv = node->private;
804
805 /* Close our socket (if any) */
806 if (priv->so != NULL) {
807
808 priv->so->so_upcall = NULL;
809 priv->so->so_rcv.sb_flags &= ~SB_UPCALL;
810 soclose(priv->so);
811 priv->so = NULL;
812 }
813
814 /* Take down netgraph node */
815 node->flags |= NG_INVALID;
816 ng_cutlinks(node);
817 ng_unname(node);
818 bzero(priv, sizeof(*priv));
819 FREE(priv, M_NETGRAPH);
820 node->private = NULL;
821 ng_unref(node); /* let the node escape */
822 return (0);
823}
824
825/*
826 * Hook disconnection
827 */
828static int
829ng_ksocket_disconnect(hook_p hook)
830{
831 KASSERT(hook->node->numhooks == 0,
832 ("%s: numhooks=%d?", __FUNCTION__, hook->node->numhooks));
833 ng_rmnode(hook->node);
834 return (0);
835}
836
837/************************************************************************
838 HELPER STUFF
839 ************************************************************************/
840
841/*
842 * When incoming data is appended to the socket, we get notified here.
843 */
844static void
845ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
846{
847 const node_p node = arg;
848 const priv_p priv = node->private;
849 meta_p meta = NULL;
850 struct mbuf *m;
851 struct uio auio;
852 int s, flags, error;
853
854 s = splnet();
855
856 /* Sanity check */
857 if ((node->flags & NG_INVALID) != 0) {
858 splx(s);
859 return;
860 }
861 KASSERT(so == priv->so, ("%s: wrong socket", __FUNCTION__));
862 KASSERT(priv->hook != NULL, ("%s: no hook", __FUNCTION__));
863
864 /* Read and forward available mbuf's */
865 auio.uio_procp = NULL;
866 auio.uio_resid = 1000000000;
867 flags = MSG_DONTWAIT;
868 do {
869 if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
870 (so, (struct sockaddr **)0, &auio, &m,
871 (struct mbuf **)0, &flags)) == 0
872 && m != NULL) {
873 struct mbuf *n;
874
875 /* Don't trust the various socket layers to get the
876 packet header and length correct (eg. kern/15175) */
877 for (n = m, m->m_pkthdr.len = 0; n; n = n->m_next)
878 m->m_pkthdr.len += n->m_len;
879 NG_SEND_DATA(error, priv->hook, m, meta);
880 }
881 } while (error == 0 && m != NULL);
882 splx(s);
883}
884
885/*
886 * Parse out either an integer value or an alias.
887 */
888static int
889ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
890 const char *s, int family)
891{
892 int k, val;
893 char *eptr;
894
895 /* Try aliases */
896 for (k = 0; aliases[k].name != NULL; k++) {
897 if (strcmp(s, aliases[k].name) == 0
898 && aliases[k].family == family)
899 return aliases[k].value;
900 }
901
902 /* Try parsing as a number */
903 val = (int)strtoul(s, &eptr, 10);
904 if (val < 0 || *eptr != '\0')
905 return (-1);
906 return (val);
907}
908