Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/ng_ksocket.c
34376 views
1
/*
2
* ng_ksocket.c
3
*/
4
5
/*-
6
* Copyright (c) 1996-1999 Whistle Communications, Inc.
7
* All rights reserved.
8
*
9
* Subject to the following obligations and disclaimer of warranty, use and
10
* redistribution of this software, in source or object code forms, with or
11
* without modifications are expressly permitted by Whistle Communications;
12
* provided, however, that:
13
* 1. Any and all reproductions of the source or object code must include the
14
* copyright notice above and the following disclaimer of warranties; and
15
* 2. No rights are granted, in any manner or form, to use Whistle
16
* Communications, Inc. trademarks, including the mark "WHISTLE
17
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18
* such appears in the above copyright notice or in the software.
19
*
20
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35
* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36
* OF SUCH DAMAGE.
37
*
38
* Author: Archie Cobbs <[email protected]>
39
* $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $
40
*/
41
42
/*
43
* Kernel socket node type. This node type is basically a kernel-mode
44
* version of a socket... kindof like the reverse of the socket node type.
45
*/
46
47
#include "opt_inet6.h"
48
49
#include <sys/param.h>
50
#include <sys/systm.h>
51
#include <sys/kernel.h>
52
#include <sys/mbuf.h>
53
#include <sys/proc.h>
54
#include <sys/malloc.h>
55
#include <sys/ctype.h>
56
#include <sys/protosw.h>
57
#include <sys/errno.h>
58
#include <sys/socket.h>
59
#include <sys/socketvar.h>
60
#include <sys/uio.h>
61
#include <sys/un.h>
62
63
#include <net/if.h>
64
#include <net/if_var.h>
65
66
#include <netgraph/ng_message.h>
67
#include <netgraph/netgraph.h>
68
#include <netgraph/ng_parse.h>
69
#include <netgraph/ng_ksocket.h>
70
71
#include <netinet/in.h>
72
#include <netinet/ip.h>
73
74
#include <netinet6/scope6_var.h>
75
76
#ifdef NG_SEPARATE_MALLOC
77
static MALLOC_DEFINE(M_NETGRAPH_KSOCKET, "netgraph_ksock",
78
"netgraph ksock node");
79
#else
80
#define M_NETGRAPH_KSOCKET M_NETGRAPH
81
#endif
82
83
#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
84
#define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data))
85
86
/* Node private data */
87
struct ng_ksocket_private {
88
node_p node;
89
hook_p hook;
90
struct socket *so;
91
int fn_sent; /* FN call on incoming event was sent */
92
LIST_HEAD(, ng_ksocket_private) embryos;
93
LIST_ENTRY(ng_ksocket_private) siblings;
94
u_int32_t flags;
95
u_int32_t response_token;
96
ng_ID_t response_addr;
97
};
98
typedef struct ng_ksocket_private *priv_p;
99
100
/* Flags for priv_p */
101
#define KSF_CONNECTING 0x00000001 /* Waiting for connection complete */
102
#define KSF_ACCEPTING 0x00000002 /* Waiting for accept complete */
103
#define KSF_EOFSEEN 0x00000004 /* Have sent 0-length EOF mbuf */
104
#define KSF_CLONED 0x00000008 /* Cloned from an accepting socket */
105
#define KSF_EMBRYONIC 0x00000010 /* Cloned node with no hooks yet */
106
107
/* Netgraph node methods */
108
static ng_constructor_t ng_ksocket_constructor;
109
static ng_rcvmsg_t ng_ksocket_rcvmsg;
110
static ng_shutdown_t ng_ksocket_shutdown;
111
static ng_newhook_t ng_ksocket_newhook;
112
static ng_rcvdata_t ng_ksocket_rcvdata;
113
static ng_connect_t ng_ksocket_connect;
114
static ng_disconnect_t ng_ksocket_disconnect;
115
116
/* Alias structure */
117
struct ng_ksocket_alias {
118
const char *name;
119
const int value;
120
const int family;
121
};
122
123
/* Protocol family aliases */
124
static const struct ng_ksocket_alias ng_ksocket_families[] = {
125
{ "local", PF_LOCAL },
126
{ "inet", PF_INET },
127
{ "inet6", PF_INET6 },
128
{ "atm", PF_ATM },
129
{ "divert", PF_DIVERT },
130
{ NULL, -1 },
131
};
132
133
/* Socket type aliases */
134
static const struct ng_ksocket_alias ng_ksocket_types[] = {
135
{ "stream", SOCK_STREAM },
136
{ "dgram", SOCK_DGRAM },
137
{ "raw", SOCK_RAW },
138
{ "rdm", SOCK_RDM },
139
{ "seqpacket", SOCK_SEQPACKET },
140
{ NULL, -1 },
141
};
142
143
/* Protocol aliases */
144
static const struct ng_ksocket_alias ng_ksocket_protos[] = {
145
{ "ip", IPPROTO_IP, PF_INET },
146
{ "raw", IPPROTO_RAW, PF_INET },
147
{ "icmp", IPPROTO_ICMP, PF_INET },
148
{ "igmp", IPPROTO_IGMP, PF_INET },
149
{ "tcp", IPPROTO_TCP, PF_INET },
150
{ "udp", IPPROTO_UDP, PF_INET },
151
{ "gre", IPPROTO_GRE, PF_INET },
152
{ "esp", IPPROTO_ESP, PF_INET },
153
{ "ah", IPPROTO_AH, PF_INET },
154
{ "swipe", IPPROTO_SWIPE, PF_INET },
155
{ "encap", IPPROTO_ENCAP, PF_INET },
156
{ "pim", IPPROTO_PIM, PF_INET },
157
{ "ip6", IPPROTO_IPV6, PF_INET6 },
158
{ "raw6", IPPROTO_RAW, PF_INET6 },
159
{ "icmp6", IPPROTO_ICMPV6, PF_INET6 },
160
{ "igmp6", IPPROTO_IGMP, PF_INET6 },
161
{ "tcp6", IPPROTO_TCP, PF_INET6 },
162
{ "udp6", IPPROTO_UDP, PF_INET6 },
163
{ "gre6", IPPROTO_GRE, PF_INET6 },
164
{ "esp6", IPPROTO_ESP, PF_INET6 },
165
{ "ah6", IPPROTO_AH, PF_INET6 },
166
{ "swipe6", IPPROTO_SWIPE, PF_INET6 },
167
{ "encap6", IPPROTO_ENCAP, PF_INET6 },
168
{ "divert6", IPPROTO_DIVERT, PF_INET6 },
169
{ "pim6", IPPROTO_PIM, PF_INET6 },
170
{ NULL, -1 },
171
};
172
173
/* Helper functions */
174
static int ng_ksocket_accept(priv_p);
175
static int ng_ksocket_listen_upcall(struct socket *so, void *arg,
176
int waitflag);
177
static void ng_ksocket_listen_upcall2(node_p node, hook_p hook,
178
void *arg1, int arg2);
179
static int ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
180
static int ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
181
const char *s, int family);
182
static void ng_ksocket_incoming2(node_p node, hook_p hook,
183
void *arg1, int arg2);
184
185
/************************************************************************
186
STRUCT SOCKADDR PARSE TYPE
187
************************************************************************/
188
189
/* Get the length of the data portion of a generic struct sockaddr */
190
static int
191
ng_parse_generic_sockdata_getLength(const struct ng_parse_type *type,
192
const u_char *start, const u_char *buf)
193
{
194
const struct sockaddr *sa;
195
196
sa = (const struct sockaddr *)(buf - SADATA_OFFSET);
197
return (sa->sa_len < SADATA_OFFSET) ? 0 : sa->sa_len - SADATA_OFFSET;
198
}
199
200
/* Type for the variable length data portion of a generic struct sockaddr */
201
static const struct ng_parse_type ng_ksocket_generic_sockdata_type = {
202
&ng_parse_bytearray_type,
203
&ng_parse_generic_sockdata_getLength
204
};
205
206
/* Type for a generic struct sockaddr */
207
static const struct ng_parse_struct_field
208
ng_parse_generic_sockaddr_type_fields[] = {
209
{ "len", &ng_parse_uint8_type },
210
{ "family", &ng_parse_uint8_type },
211
{ "data", &ng_ksocket_generic_sockdata_type },
212
{ NULL }
213
};
214
static const struct ng_parse_type ng_ksocket_generic_sockaddr_type = {
215
&ng_parse_struct_type,
216
&ng_parse_generic_sockaddr_type_fields
217
};
218
219
/* Convert a struct sockaddr from ASCII to binary. If its a protocol
220
family that we specially handle, do that, otherwise defer to the
221
generic parse type ng_ksocket_generic_sockaddr_type. */
222
static int
223
ng_ksocket_sockaddr_parse(const struct ng_parse_type *type,
224
const char *s, int *off, const u_char *const start,
225
u_char *const buf, int *buflen)
226
{
227
struct sockaddr *const sa = (struct sockaddr *)buf;
228
enum ng_parse_token tok;
229
char fambuf[32];
230
int family, len;
231
char *t;
232
233
/* If next token is a left curly brace, use generic parse type */
234
if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) {
235
return (*ng_ksocket_generic_sockaddr_type.supertype->parse)
236
(&ng_ksocket_generic_sockaddr_type,
237
s, off, start, buf, buflen);
238
}
239
240
/* Get socket address family followed by a slash */
241
while (isspace(s[*off]))
242
(*off)++;
243
if ((t = strchr(s + *off, '/')) == NULL)
244
return (EINVAL);
245
if ((len = t - (s + *off)) > sizeof(fambuf) - 1)
246
return (EINVAL);
247
strncpy(fambuf, s + *off, len);
248
fambuf[len] = '\0';
249
*off += len + 1;
250
if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1)
251
return (EINVAL);
252
253
/* Set family */
254
if (*buflen < SADATA_OFFSET)
255
return (ERANGE);
256
sa->sa_family = family;
257
258
/* Set family-specific data and length */
259
switch (sa->sa_family) {
260
case PF_LOCAL: /* Get pathname */
261
{
262
const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
263
struct sockaddr_un *const sun = (struct sockaddr_un *)sa;
264
int toklen, pathlen;
265
char *path;
266
267
if ((path = ng_get_string_token(s, off, &toklen, NULL)) == NULL)
268
return (EINVAL);
269
pathlen = strlen(path);
270
if (pathlen > SOCK_MAXADDRLEN) {
271
free(path, M_NETGRAPH_KSOCKET);
272
return (E2BIG);
273
}
274
if (*buflen < pathoff + pathlen) {
275
free(path, M_NETGRAPH_KSOCKET);
276
return (ERANGE);
277
}
278
*off += toklen;
279
bcopy(path, sun->sun_path, pathlen);
280
sun->sun_len = pathoff + pathlen;
281
free(path, M_NETGRAPH_KSOCKET);
282
break;
283
}
284
285
case PF_INET: /* Get an IP address with optional port */
286
{
287
struct sockaddr_in *const sin = (struct sockaddr_in *)sa;
288
int i;
289
290
/* Parse this: <ipaddress>[:port] */
291
for (i = 0; i < 4; i++) {
292
u_long val;
293
char *eptr;
294
295
val = strtoul(s + *off, &eptr, 10);
296
if (val > 0xff || eptr == s + *off)
297
return (EINVAL);
298
*off += (eptr - (s + *off));
299
((u_char *)&sin->sin_addr)[i] = (u_char)val;
300
if (i < 3) {
301
if (s[*off] != '.')
302
return (EINVAL);
303
(*off)++;
304
} else if (s[*off] == ':') {
305
(*off)++;
306
val = strtoul(s + *off, &eptr, 10);
307
if (val > 0xffff || eptr == s + *off)
308
return (EINVAL);
309
*off += (eptr - (s + *off));
310
sin->sin_port = htons(val);
311
} else
312
sin->sin_port = 0;
313
}
314
bzero(&sin->sin_zero, sizeof(sin->sin_zero));
315
sin->sin_len = sizeof(*sin);
316
break;
317
}
318
#ifdef INET6
319
case PF_INET6:
320
{
321
struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)sa;
322
char *eptr;
323
char addr[INET6_ADDRSTRLEN];
324
char ifname[16];
325
u_long port;
326
bool hasifname = true;
327
328
/* RFC 3986 Section 3.2.2, Validate IP literal within square brackets. */
329
if (s[*off] == '[' && (strstr(&s[*off], "]")))
330
(*off)++;
331
else
332
return (EINVAL);
333
if ((eptr = strstr(&s[*off], "%")) == NULL) {
334
hasifname = false;
335
eptr = strstr(&s[*off], "]");
336
}
337
snprintf(addr, eptr - (s + *off) + 1, "%s", &s[*off]);
338
*off += (eptr - (s + *off));
339
if (!inet_pton(AF_INET6, addr, &sin6->sin6_addr))
340
return (EINVAL);
341
342
if (hasifname) {
343
uint16_t scope;
344
345
eptr = strstr(&s[*off], "]");
346
(*off)++;
347
snprintf(ifname, eptr - (s + *off) + 1, "%s", &s[*off]);
348
*off += (eptr - (s + *off));
349
350
if (sin6->sin6_addr.s6_addr16[0] != IPV6_ADDR_INT16_ULL)
351
return (EINVAL);
352
scope = in6_getscope(&sin6->sin6_addr);
353
sin6->sin6_scope_id =
354
in6_getscopezone(ifunit(ifname), scope);
355
}
356
357
(*off)++;
358
if (s[*off] == ':') {
359
(*off)++;
360
port = strtoul(s + *off, &eptr, 10);
361
if (port > 0xffff || eptr == s + *off)
362
return (EINVAL);
363
*off += (eptr - (s + *off));
364
sin6->sin6_port = htons(port);
365
} else
366
sin6->sin6_port = 0;
367
368
sin6->sin6_len = sizeof(*sin6);
369
break;
370
}
371
#endif /* INET6 */
372
default:
373
return (EINVAL);
374
}
375
376
/* Done */
377
*buflen = sa->sa_len;
378
return (0);
379
}
380
381
/* Convert a struct sockaddr from binary to ASCII */
382
static int
383
ng_ksocket_sockaddr_unparse(const struct ng_parse_type *type,
384
const u_char *data, int *off, char *cbuf, int cbuflen)
385
{
386
const struct sockaddr *sa = (const struct sockaddr *)(data + *off);
387
int slen = 0;
388
389
/* Output socket address, either in special or generic format */
390
switch (sa->sa_family) {
391
case PF_LOCAL:
392
{
393
const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
394
const struct sockaddr_un *sun = (const struct sockaddr_un *)sa;
395
const int pathlen = sun->sun_len - pathoff;
396
char pathbuf[SOCK_MAXADDRLEN + 1];
397
char *pathtoken;
398
399
bcopy(sun->sun_path, pathbuf, pathlen);
400
if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL)
401
return (ENOMEM);
402
slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken);
403
free(pathtoken, M_NETGRAPH_KSOCKET);
404
if (slen >= cbuflen)
405
return (ERANGE);
406
*off += sun->sun_len;
407
return (0);
408
}
409
410
case PF_INET:
411
{
412
const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
413
414
slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d",
415
((const u_char *)&sin->sin_addr)[0],
416
((const u_char *)&sin->sin_addr)[1],
417
((const u_char *)&sin->sin_addr)[2],
418
((const u_char *)&sin->sin_addr)[3]);
419
if (sin->sin_port != 0) {
420
slen += snprintf(cbuf + strlen(cbuf),
421
cbuflen - strlen(cbuf), ":%d",
422
(u_int)ntohs(sin->sin_port));
423
}
424
if (slen >= cbuflen)
425
return (ERANGE);
426
*off += sizeof(*sin);
427
return(0);
428
}
429
#ifdef INET6
430
case PF_INET6:
431
{
432
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
433
char addr[INET6_ADDRSTRLEN];
434
435
inet_ntop(AF_INET6, &sin6->sin6_addr, addr, INET6_ADDRSTRLEN);
436
slen += snprintf(cbuf, cbuflen, "inet6/[%s]", addr);
437
438
if (sin6->sin6_port != 0) {
439
slen += snprintf(cbuf + strlen(cbuf),
440
cbuflen - strlen(cbuf), ":%d",
441
(u_int)ntohs(sin6->sin6_port));
442
}
443
if (slen >= cbuflen)
444
return (ERANGE);
445
*off += sizeof(*sin6);
446
return(0);
447
}
448
#endif /* INET6 */
449
default:
450
return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
451
(&ng_ksocket_generic_sockaddr_type,
452
data, off, cbuf, cbuflen);
453
}
454
}
455
456
/* Parse type for struct sockaddr */
457
static const struct ng_parse_type ng_ksocket_sockaddr_type = {
458
NULL,
459
NULL,
460
NULL,
461
&ng_ksocket_sockaddr_parse,
462
&ng_ksocket_sockaddr_unparse,
463
NULL /* no such thing as a default struct sockaddr */
464
};
465
466
/************************************************************************
467
STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
468
************************************************************************/
469
470
/* Get length of the struct ng_ksocket_sockopt value field, which is the
471
just the excess of the message argument portion over the length of
472
the struct ng_ksocket_sockopt. */
473
static int
474
ng_parse_sockoptval_getLength(const struct ng_parse_type *type,
475
const u_char *start, const u_char *buf)
476
{
477
static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
478
const struct ng_ksocket_sockopt *sopt;
479
const struct ng_mesg *msg;
480
481
sopt = (const struct ng_ksocket_sockopt *)(buf - offset);
482
msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg));
483
return msg->header.arglen - sizeof(*sopt);
484
}
485
486
/* Parse type for the option value part of a struct ng_ksocket_sockopt
487
XXX Eventually, we should handle the different socket options specially.
488
XXX This would avoid byte order problems, eg an integer value of 1 is
489
XXX going to be "[1]" for little endian or "[3=1]" for big endian. */
490
static const struct ng_parse_type ng_ksocket_sockoptval_type = {
491
&ng_parse_bytearray_type,
492
&ng_parse_sockoptval_getLength
493
};
494
495
/* Parse type for struct ng_ksocket_sockopt */
496
static const struct ng_parse_struct_field ng_ksocket_sockopt_type_fields[]
497
= NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type);
498
static const struct ng_parse_type ng_ksocket_sockopt_type = {
499
&ng_parse_struct_type,
500
&ng_ksocket_sockopt_type_fields
501
};
502
503
/* Parse type for struct ng_ksocket_accept */
504
static const struct ng_parse_struct_field ng_ksocket_accept_type_fields[]
505
= NGM_KSOCKET_ACCEPT_INFO;
506
static const struct ng_parse_type ng_ksocket_accept_type = {
507
&ng_parse_struct_type,
508
&ng_ksocket_accept_type_fields
509
};
510
511
/* List of commands and how to convert arguments to/from ASCII */
512
static const struct ng_cmdlist ng_ksocket_cmds[] = {
513
{
514
NGM_KSOCKET_COOKIE,
515
NGM_KSOCKET_BIND,
516
"bind",
517
&ng_ksocket_sockaddr_type,
518
NULL
519
},
520
{
521
NGM_KSOCKET_COOKIE,
522
NGM_KSOCKET_LISTEN,
523
"listen",
524
&ng_parse_int32_type,
525
NULL
526
},
527
{
528
NGM_KSOCKET_COOKIE,
529
NGM_KSOCKET_ACCEPT,
530
"accept",
531
NULL,
532
&ng_ksocket_accept_type
533
},
534
{
535
NGM_KSOCKET_COOKIE,
536
NGM_KSOCKET_CONNECT,
537
"connect",
538
&ng_ksocket_sockaddr_type,
539
&ng_parse_int32_type
540
},
541
{
542
NGM_KSOCKET_COOKIE,
543
NGM_KSOCKET_GETNAME,
544
"getname",
545
NULL,
546
&ng_ksocket_sockaddr_type
547
},
548
{
549
NGM_KSOCKET_COOKIE,
550
NGM_KSOCKET_GETPEERNAME,
551
"getpeername",
552
NULL,
553
&ng_ksocket_sockaddr_type
554
},
555
{
556
NGM_KSOCKET_COOKIE,
557
NGM_KSOCKET_SETOPT,
558
"setopt",
559
&ng_ksocket_sockopt_type,
560
NULL
561
},
562
{
563
NGM_KSOCKET_COOKIE,
564
NGM_KSOCKET_GETOPT,
565
"getopt",
566
&ng_ksocket_sockopt_type,
567
&ng_ksocket_sockopt_type
568
},
569
{ 0 }
570
};
571
572
/* Node type descriptor */
573
static struct ng_type ng_ksocket_typestruct = {
574
.version = NG_ABI_VERSION,
575
.name = NG_KSOCKET_NODE_TYPE,
576
.constructor = ng_ksocket_constructor,
577
.rcvmsg = ng_ksocket_rcvmsg,
578
.shutdown = ng_ksocket_shutdown,
579
.newhook = ng_ksocket_newhook,
580
.connect = ng_ksocket_connect,
581
.rcvdata = ng_ksocket_rcvdata,
582
.disconnect = ng_ksocket_disconnect,
583
.cmdlist = ng_ksocket_cmds,
584
};
585
NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
586
587
#define ERROUT(x) do { error = (x); goto done; } while (0)
588
589
/************************************************************************
590
NETGRAPH NODE STUFF
591
************************************************************************/
592
593
/*
594
* Node type constructor
595
* The NODE part is assumed to be all set up.
596
* There is already a reference to the node for us.
597
*/
598
static int
599
ng_ksocket_constructor(node_p node)
600
{
601
priv_p priv;
602
603
/* Allocate private structure */
604
priv = malloc(sizeof(*priv), M_NETGRAPH_KSOCKET, M_NOWAIT | M_ZERO);
605
if (priv == NULL)
606
return (ENOMEM);
607
608
LIST_INIT(&priv->embryos);
609
/* cross link them */
610
priv->node = node;
611
NG_NODE_SET_PRIVATE(node, priv);
612
613
/* Done */
614
return (0);
615
}
616
617
/*
618
* Give our OK for a hook to be added. The hook name is of the
619
* form "<family>/<type>/<proto>" where the three components may
620
* be decimal numbers or else aliases from the above lists.
621
*
622
* Connecting a hook amounts to opening the socket. Disconnecting
623
* the hook closes the socket and destroys the node as well.
624
*/
625
static int
626
ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
627
{
628
struct thread *td = curthread; /* XXX broken */
629
const priv_p priv = NG_NODE_PRIVATE(node);
630
char *s1, *s2, name[NG_HOOKSIZ];
631
int family, type, protocol, error;
632
633
/* Check if we're already connected */
634
if (priv->hook != NULL)
635
return (EISCONN);
636
637
if (priv->flags & KSF_CLONED) {
638
if (priv->flags & KSF_EMBRYONIC) {
639
/* Remove ourselves from our parent's embryo list */
640
LIST_REMOVE(priv, siblings);
641
priv->flags &= ~KSF_EMBRYONIC;
642
}
643
} else {
644
/* Extract family, type, and protocol from hook name */
645
snprintf(name, sizeof(name), "%s", name0);
646
s1 = name;
647
if ((s2 = strchr(s1, '/')) == NULL)
648
return (EINVAL);
649
*s2++ = '\0';
650
family = ng_ksocket_parse(ng_ksocket_families, s1, 0);
651
if (family == -1)
652
return (EINVAL);
653
s1 = s2;
654
if ((s2 = strchr(s1, '/')) == NULL)
655
return (EINVAL);
656
*s2++ = '\0';
657
type = ng_ksocket_parse(ng_ksocket_types, s1, 0);
658
if (type == -1)
659
return (EINVAL);
660
s1 = s2;
661
protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family);
662
if (protocol == -1)
663
return (EINVAL);
664
665
/* Create the socket */
666
error = socreate(family, &priv->so, type, protocol,
667
td->td_ucred, td);
668
if (error != 0)
669
return (error);
670
671
/* XXX call soreserve() ? */
672
}
673
674
/* OK */
675
priv->hook = hook;
676
677
/*
678
* In case of misconfigured routing a packet may reenter
679
* ksocket node recursively. Decouple stack to avoid possible
680
* panics about sleeping with locks held.
681
*/
682
NG_HOOK_FORCE_QUEUE(hook);
683
684
return(0);
685
}
686
687
static int
688
ng_ksocket_connect(hook_p hook)
689
{
690
node_p node = NG_HOOK_NODE(hook);
691
const priv_p priv = NG_NODE_PRIVATE(node);
692
struct socket *const so = priv->so;
693
694
/* Add our hook for incoming data and other events */
695
SOCK_RECVBUF_LOCK(so);
696
soupcall_set(priv->so, SO_RCV, ng_ksocket_incoming, node);
697
SOCK_RECVBUF_UNLOCK(so);
698
SOCK_SENDBUF_LOCK(so);
699
soupcall_set(priv->so, SO_SND, ng_ksocket_incoming, node);
700
SOCK_SENDBUF_UNLOCK(so);
701
SOCK_LOCK(priv->so);
702
priv->so->so_state |= SS_NBIO;
703
SOCK_UNLOCK(priv->so);
704
/*
705
* --Original comment--
706
* On a cloned socket we may have already received one or more
707
* upcalls which we couldn't handle without a hook. Handle
708
* those now.
709
* We cannot call the upcall function directly
710
* from here, because until this function has returned our
711
* hook isn't connected.
712
*
713
* ---meta comment for -current ---
714
* XXX This is dubius.
715
* Upcalls between the time that the hook was
716
* first created and now (on another processesor) will
717
* be earlier on the queue than the request to finalise the hook.
718
* By the time the hook is finalised,
719
* The queued upcalls will have happened and the code
720
* will have discarded them because of a lack of a hook.
721
* (socket not open).
722
*
723
* This is a bad byproduct of the complicated way in which hooks
724
* are now created (3 daisy chained async events).
725
*
726
* Since we are a netgraph operation
727
* We know that we hold a lock on this node. This forces the
728
* request we make below to be queued rather than implemented
729
* immediately which will cause the upcall function to be called a bit
730
* later.
731
* However, as we will run any waiting queued operations immediately
732
* after doing this one, if we have not finalised the other end
733
* of the hook, those queued operations will fail.
734
*/
735
if (priv->flags & KSF_CLONED) {
736
ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_NOWAIT);
737
}
738
739
return (0);
740
}
741
742
/*
743
* Receive a control message
744
*/
745
static int
746
ng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook)
747
{
748
struct thread *td = curthread; /* XXX broken */
749
const priv_p priv = NG_NODE_PRIVATE(node);
750
struct socket *const so = priv->so;
751
struct ng_mesg *resp = NULL;
752
int error = 0;
753
struct ng_mesg *msg;
754
755
NGI_GET_MSG(item, msg);
756
switch (msg->header.typecookie) {
757
case NGM_KSOCKET_COOKIE:
758
switch (msg->header.cmd) {
759
case NGM_KSOCKET_BIND:
760
{
761
struct sockaddr *const sa
762
= (struct sockaddr *)msg->data;
763
764
/* Sanity check */
765
if (msg->header.arglen < SADATA_OFFSET
766
|| msg->header.arglen < sa->sa_len)
767
ERROUT(EINVAL);
768
if (so == NULL)
769
ERROUT(ENXIO);
770
771
/* Bind */
772
error = sobind(so, sa, td);
773
break;
774
}
775
case NGM_KSOCKET_LISTEN:
776
{
777
/* Sanity check */
778
if (msg->header.arglen != sizeof(int32_t))
779
ERROUT(EINVAL);
780
if (so == NULL)
781
ERROUT(ENXIO);
782
783
/* Listen */
784
so->so_state |= SS_NBIO;
785
error = solisten(so, *((int32_t *)msg->data), td);
786
if (error == 0) {
787
SOLISTEN_LOCK(so);
788
solisten_upcall_set(so,
789
ng_ksocket_listen_upcall, priv);
790
SOLISTEN_UNLOCK(so);
791
}
792
break;
793
}
794
795
case NGM_KSOCKET_ACCEPT:
796
{
797
/* Sanity check */
798
if (msg->header.arglen != 0)
799
ERROUT(EINVAL);
800
if (so == NULL)
801
ERROUT(ENXIO);
802
803
/* Make sure the socket is capable of accepting */
804
if (!(so->so_options & SO_ACCEPTCONN))
805
ERROUT(EINVAL);
806
if (priv->flags & KSF_ACCEPTING)
807
ERROUT(EALREADY);
808
809
/*
810
* If a connection is already complete, take it.
811
* Otherwise let the upcall function deal with
812
* the connection when it comes in. Don't return
813
* EWOULDBLOCK, per ng_ksocket(4) documentation.
814
*/
815
error = ng_ksocket_accept(priv);
816
if (error == EWOULDBLOCK)
817
error = 0;
818
if (error != 0)
819
ERROUT(error);
820
821
priv->response_token = msg->header.token;
822
priv->response_addr = NGI_RETADDR(item);
823
break;
824
}
825
826
case NGM_KSOCKET_CONNECT:
827
{
828
struct sockaddr *const sa
829
= (struct sockaddr *)msg->data;
830
831
/* Sanity check */
832
if (msg->header.arglen < SADATA_OFFSET
833
|| msg->header.arglen < sa->sa_len)
834
ERROUT(EINVAL);
835
if (so == NULL)
836
ERROUT(ENXIO);
837
838
/* Do connect */
839
if ((so->so_state & SS_ISCONNECTING) != 0)
840
ERROUT(EALREADY);
841
if ((error = soconnect(so, sa, td)) != 0) {
842
so->so_state &= ~SS_ISCONNECTING;
843
ERROUT(error);
844
}
845
if ((so->so_state & SS_ISCONNECTING) != 0) {
846
/* We will notify the sender when we connect */
847
priv->response_token = msg->header.token;
848
priv->response_addr = NGI_RETADDR(item);
849
priv->flags |= KSF_CONNECTING;
850
ERROUT(EINPROGRESS);
851
}
852
break;
853
}
854
855
case NGM_KSOCKET_GETNAME:
856
case NGM_KSOCKET_GETPEERNAME:
857
{
858
int (*func)(struct socket *so, struct sockaddr *sa);
859
struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
860
861
/* Sanity check */
862
if (msg->header.arglen != 0)
863
ERROUT(EINVAL);
864
if (so == NULL)
865
ERROUT(ENXIO);
866
867
/* Get function */
868
if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
869
if ((so->so_state & SS_ISCONNECTED) == 0)
870
ERROUT(ENOTCONN);
871
func = sopeeraddr;
872
} else
873
func = sosockaddr;
874
875
/* Get local or peer address */
876
error = (*func)(so, (struct sockaddr *)&ss);
877
if (error)
878
break;
879
880
/* Send it back in a response */
881
NG_MKRESPONSE(resp, msg, ss.ss_len, M_NOWAIT);
882
if (resp != NULL)
883
bcopy(&ss, resp->data, ss.ss_len);
884
else
885
error = ENOMEM;
886
887
break;
888
}
889
890
case NGM_KSOCKET_GETOPT:
891
{
892
struct ng_ksocket_sockopt *ksopt =
893
(struct ng_ksocket_sockopt *)msg->data;
894
struct sockopt sopt;
895
896
/* Sanity check */
897
if (msg->header.arglen != sizeof(*ksopt))
898
ERROUT(EINVAL);
899
if (so == NULL)
900
ERROUT(ENXIO);
901
902
/* Get response with room for option value */
903
NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
904
+ NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
905
if (resp == NULL)
906
ERROUT(ENOMEM);
907
908
/* Get socket option, and put value in the response */
909
sopt.sopt_dir = SOPT_GET;
910
sopt.sopt_level = ksopt->level;
911
sopt.sopt_name = ksopt->name;
912
sopt.sopt_td = NULL;
913
sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
914
ksopt = (struct ng_ksocket_sockopt *)resp->data;
915
sopt.sopt_val = ksopt->value;
916
if ((error = sogetopt(so, &sopt)) != 0) {
917
NG_FREE_MSG(resp);
918
break;
919
}
920
921
/* Set actual value length */
922
resp->header.arglen = sizeof(*ksopt)
923
+ sopt.sopt_valsize;
924
break;
925
}
926
927
case NGM_KSOCKET_SETOPT:
928
{
929
struct ng_ksocket_sockopt *const ksopt =
930
(struct ng_ksocket_sockopt *)msg->data;
931
const int valsize = msg->header.arglen - sizeof(*ksopt);
932
struct sockopt sopt;
933
934
/* Sanity check */
935
if (valsize < 0)
936
ERROUT(EINVAL);
937
if (so == NULL)
938
ERROUT(ENXIO);
939
940
/* Set socket option */
941
sopt.sopt_dir = SOPT_SET;
942
sopt.sopt_level = ksopt->level;
943
sopt.sopt_name = ksopt->name;
944
sopt.sopt_val = ksopt->value;
945
sopt.sopt_valsize = valsize;
946
sopt.sopt_td = NULL;
947
error = sosetopt(so, &sopt);
948
break;
949
}
950
951
default:
952
error = EINVAL;
953
break;
954
}
955
break;
956
default:
957
error = EINVAL;
958
break;
959
}
960
done:
961
NG_RESPOND_MSG(error, node, item, resp);
962
NG_FREE_MSG(msg);
963
return (error);
964
}
965
966
/*
967
* Receive incoming data on our hook. Send it out the socket.
968
*/
969
static int
970
ng_ksocket_rcvdata(hook_p hook, item_p item)
971
{
972
struct thread *td = curthread; /* XXX broken */
973
const node_p node = NG_HOOK_NODE(hook);
974
const priv_p priv = NG_NODE_PRIVATE(node);
975
struct socket *const so = priv->so;
976
struct sockaddr *sa = NULL;
977
int error;
978
struct mbuf *m;
979
#ifdef ALIGNED_POINTER
980
struct mbuf *n;
981
#endif /* ALIGNED_POINTER */
982
struct sa_tag *stag;
983
984
/* Extract data */
985
NGI_GET_M(item, m);
986
NG_FREE_ITEM(item);
987
#ifdef ALIGNED_POINTER
988
if (!ALIGNED_POINTER(mtod(m, caddr_t), uint32_t)) {
989
n = m_defrag(m, M_NOWAIT);
990
if (n == NULL) {
991
m_freem(m);
992
return (ENOBUFS);
993
}
994
m = n;
995
}
996
#endif /* ALIGNED_POINTER */
997
/*
998
* Look if socket address is stored in packet tags.
999
* If sockaddr is ours, or provided by a third party (zero id),
1000
* then we accept it.
1001
*/
1002
if (((stag = (struct sa_tag *)m_tag_locate(m, NGM_KSOCKET_COOKIE,
1003
NG_KSOCKET_TAG_SOCKADDR, NULL)) != NULL) &&
1004
(stag->id == NG_NODE_ID(node) || stag->id == 0))
1005
sa = &stag->sa;
1006
1007
/* Reset specific mbuf flags to prevent addressing problems. */
1008
m->m_flags &= ~(M_BCAST|M_MCAST);
1009
1010
/* Send packet */
1011
error = sosend(so, sa, 0, m, 0, 0, td);
1012
1013
return (error);
1014
}
1015
1016
/*
1017
* Destroy node
1018
*/
1019
static int
1020
ng_ksocket_shutdown(node_p node)
1021
{
1022
const priv_p priv = NG_NODE_PRIVATE(node);
1023
struct socket *so = priv->so;
1024
priv_p embryo;
1025
1026
/* Close our socket (if any) */
1027
if (priv->so != NULL) {
1028
if (SOLISTENING(so)) {
1029
SOLISTEN_LOCK(so);
1030
solisten_upcall_set(so, NULL, NULL);
1031
SOLISTEN_UNLOCK(so);
1032
} else {
1033
SOCK_RECVBUF_LOCK(so);
1034
soupcall_clear(so, SO_RCV);
1035
SOCK_RECVBUF_UNLOCK(so);
1036
SOCK_SENDBUF_LOCK(so);
1037
soupcall_clear(so, SO_SND);
1038
SOCK_SENDBUF_UNLOCK(so);
1039
}
1040
soclose(so);
1041
priv->so = NULL;
1042
}
1043
1044
/* If we are an embryo, take ourselves out of the parent's list */
1045
if (priv->flags & KSF_EMBRYONIC) {
1046
LIST_REMOVE(priv, siblings);
1047
priv->flags &= ~KSF_EMBRYONIC;
1048
}
1049
1050
/* Remove any embryonic children we have */
1051
while (!LIST_EMPTY(&priv->embryos)) {
1052
embryo = LIST_FIRST(&priv->embryos);
1053
ng_rmnode_self(embryo->node);
1054
}
1055
1056
/* Take down netgraph node */
1057
bzero(priv, sizeof(*priv));
1058
free(priv, M_NETGRAPH_KSOCKET);
1059
NG_NODE_SET_PRIVATE(node, NULL);
1060
NG_NODE_UNREF(node); /* let the node escape */
1061
return (0);
1062
}
1063
1064
/*
1065
* Hook disconnection
1066
*/
1067
static int
1068
ng_ksocket_disconnect(hook_p hook)
1069
{
1070
KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0,
1071
("%s: numhooks=%d?", __func__,
1072
NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook))));
1073
if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))
1074
ng_rmnode_self(NG_HOOK_NODE(hook));
1075
return (0);
1076
}
1077
1078
/************************************************************************
1079
HELPER STUFF
1080
************************************************************************/
1081
/*
1082
* You should not "just call" a netgraph node function from an external
1083
* asynchronous event. This is because in doing so you are ignoring the
1084
* locking on the netgraph nodes. Instead call your function via ng_send_fn().
1085
* This will call the function you chose, but will first do all the
1086
* locking rigmarole. Your function MAY only be called at some distant future
1087
* time (several millisecs away) so don't give it any arguments
1088
* that may be revoked soon (e.g. on your stack).
1089
*
1090
* To decouple stack, we use queue version of ng_send_fn().
1091
*/
1092
1093
static int
1094
ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
1095
{
1096
const node_p node = arg;
1097
const priv_p priv = NG_NODE_PRIVATE(node);
1098
int wait = ((waitflag & M_WAITOK) ? NG_WAITOK : 0) | NG_QUEUE;
1099
1100
/*
1101
* Even if node is not locked, as soon as we are called, we assume
1102
* it exist and it's private area is valid. With some care we can
1103
* access it. Mark node that incoming event for it was sent to
1104
* avoid unneded queue trashing.
1105
*/
1106
if (atomic_cmpset_int(&priv->fn_sent, 0, 1) &&
1107
ng_send_fn1(node, NULL, &ng_ksocket_incoming2, so, 0, wait)) {
1108
atomic_store_rel_int(&priv->fn_sent, 0);
1109
}
1110
return (SU_OK);
1111
}
1112
1113
/*
1114
* When incoming data is appended to the socket, we get notified here.
1115
* This is also called whenever a significant event occurs for the socket.
1116
* Our original caller may have queued this even some time ago and
1117
* we cannot trust that he even still exists. The node however is being
1118
* held with a reference by the queueing code and guarantied to be valid.
1119
*/
1120
static void
1121
ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2)
1122
{
1123
struct socket *so = arg1;
1124
const priv_p priv = NG_NODE_PRIVATE(node);
1125
struct ng_mesg *response;
1126
int error;
1127
1128
KASSERT(so == priv->so, ("%s: wrong socket", __func__));
1129
1130
/* Allow next incoming event to be queued. */
1131
atomic_store_rel_int(&priv->fn_sent, 0);
1132
1133
/* Check whether a pending connect operation has completed */
1134
if (priv->flags & KSF_CONNECTING) {
1135
if ((error = so->so_error) != 0) {
1136
so->so_error = 0;
1137
so->so_state &= ~SS_ISCONNECTING;
1138
}
1139
if (!(so->so_state & SS_ISCONNECTING)) {
1140
NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE,
1141
NGM_KSOCKET_CONNECT, sizeof(int32_t), M_NOWAIT);
1142
if (response != NULL) {
1143
response->header.flags |= NGF_RESP;
1144
response->header.token = priv->response_token;
1145
*(int32_t *)response->data = error;
1146
/*
1147
* send an async "response" message
1148
* to the node that set us up
1149
* (if it still exists)
1150
*/
1151
NG_SEND_MSG_ID(error, node,
1152
response, priv->response_addr, 0);
1153
}
1154
priv->flags &= ~KSF_CONNECTING;
1155
}
1156
}
1157
1158
/*
1159
* If we don't have a hook, we must handle data events later. When
1160
* the hook gets created and is connected, this upcall function
1161
* will be called again.
1162
*/
1163
if (priv->hook == NULL)
1164
return;
1165
1166
/* Read and forward available mbufs. */
1167
while (1) {
1168
struct uio uio;
1169
struct sockaddr *sa;
1170
struct mbuf *m;
1171
int flags;
1172
1173
/* Try to get next packet from socket. */
1174
uio.uio_td = NULL;
1175
uio.uio_resid = IP_MAXPACKET;
1176
flags = MSG_DONTWAIT;
1177
sa = NULL;
1178
if ((error = soreceive(so, (so->so_state & SS_ISCONNECTED) ?
1179
NULL : &sa, &uio, &m, NULL, &flags)) != 0)
1180
break;
1181
1182
/* See if we got anything. */
1183
if (flags & MSG_TRUNC) {
1184
m_freem(m);
1185
m = NULL;
1186
}
1187
if (m == NULL) {
1188
if (sa != NULL)
1189
free(sa, M_SONAME);
1190
break;
1191
}
1192
1193
KASSERT(m->m_nextpkt == NULL, ("%s: nextpkt", __func__));
1194
1195
/*
1196
* Stream sockets do not have packet boundaries, so
1197
* we have to allocate a header mbuf and attach the
1198
* stream of data to it.
1199
*/
1200
if (so->so_type == SOCK_STREAM) {
1201
struct mbuf *mh;
1202
1203
mh = m_gethdr(M_NOWAIT, MT_DATA);
1204
if (mh == NULL) {
1205
m_freem(m);
1206
if (sa != NULL)
1207
free(sa, M_SONAME);
1208
break;
1209
}
1210
1211
mh->m_next = m;
1212
for (; m; m = m->m_next)
1213
mh->m_pkthdr.len += m->m_len;
1214
m = mh;
1215
}
1216
1217
/* Put peer's socket address (if any) into a tag */
1218
if (sa != NULL) {
1219
struct sa_tag *stag;
1220
1221
stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE,
1222
NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) +
1223
sa->sa_len, M_NOWAIT);
1224
if (stag == NULL) {
1225
free(sa, M_SONAME);
1226
goto sendit;
1227
}
1228
bcopy(sa, &stag->sa, sa->sa_len);
1229
free(sa, M_SONAME);
1230
stag->id = NG_NODE_ID(node);
1231
m_tag_prepend(m, &stag->tag);
1232
}
1233
1234
sendit: /* Forward data with optional peer sockaddr as packet tag */
1235
NG_SEND_DATA_ONLY(error, priv->hook, m);
1236
}
1237
1238
/*
1239
* If the peer has closed the connection, forward a 0-length mbuf
1240
* to indicate end-of-file.
1241
*/
1242
if (so->so_rcv.sb_state & SBS_CANTRCVMORE &&
1243
!(priv->flags & KSF_EOFSEEN)) {
1244
struct mbuf *m;
1245
1246
m = m_gethdr(M_NOWAIT, MT_DATA);
1247
if (m != NULL)
1248
NG_SEND_DATA_ONLY(error, priv->hook, m);
1249
priv->flags |= KSF_EOFSEEN;
1250
}
1251
}
1252
1253
static int
1254
ng_ksocket_accept(priv_p priv)
1255
{
1256
struct socket *const head = priv->so;
1257
struct socket *so;
1258
struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
1259
struct ng_mesg *resp;
1260
struct ng_ksocket_accept *resp_data;
1261
node_p node;
1262
priv_p priv2;
1263
int len;
1264
int error;
1265
1266
SOLISTEN_LOCK(head);
1267
error = solisten_dequeue(head, &so, SOCK_NONBLOCK);
1268
if (error == EWOULDBLOCK) {
1269
priv->flags |= KSF_ACCEPTING;
1270
return (error);
1271
}
1272
priv->flags &= ~KSF_ACCEPTING;
1273
if (error)
1274
return (error);
1275
1276
if ((error = soaccept(so, (struct sockaddr *)&ss)) != 0)
1277
return (error);
1278
1279
len = OFFSETOF(struct ng_ksocket_accept, addr);
1280
len += ss.ss_len;
1281
1282
NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len,
1283
M_NOWAIT);
1284
if (resp == NULL) {
1285
soclose(so);
1286
goto out;
1287
}
1288
resp->header.flags |= NGF_RESP;
1289
resp->header.token = priv->response_token;
1290
1291
/* Clone a ksocket node to wrap the new socket */
1292
error = ng_make_node_common(&ng_ksocket_typestruct, &node);
1293
if (error) {
1294
free(resp, M_NETGRAPH);
1295
soclose(so);
1296
goto out;
1297
}
1298
1299
if (ng_ksocket_constructor(node) != 0) {
1300
NG_NODE_UNREF(node);
1301
free(resp, M_NETGRAPH);
1302
soclose(so);
1303
goto out;
1304
}
1305
1306
priv2 = NG_NODE_PRIVATE(node);
1307
priv2->so = so;
1308
priv2->flags |= KSF_CLONED | KSF_EMBRYONIC;
1309
1310
/*
1311
* Insert the cloned node into a list of embryonic children
1312
* on the parent node. When a hook is created on the cloned
1313
* node it will be removed from this list. When the parent
1314
* is destroyed it will destroy any embryonic children it has.
1315
*/
1316
LIST_INSERT_HEAD(&priv->embryos, priv2, siblings);
1317
1318
SOCK_RECVBUF_LOCK(so);
1319
soupcall_set(so, SO_RCV, ng_ksocket_incoming, node);
1320
SOCK_RECVBUF_UNLOCK(so);
1321
SOCK_SENDBUF_LOCK(so);
1322
soupcall_set(so, SO_SND, ng_ksocket_incoming, node);
1323
SOCK_SENDBUF_UNLOCK(so);
1324
1325
/* Fill in the response data and send it or return it to the caller */
1326
resp_data = (struct ng_ksocket_accept *)resp->data;
1327
resp_data->nodeid = NG_NODE_ID(node);
1328
bcopy(&ss, &resp_data->addr, ss.ss_len);
1329
NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0);
1330
1331
out:
1332
1333
return (0);
1334
}
1335
1336
static int
1337
ng_ksocket_listen_upcall(struct socket *so, void *arg, int waitflag)
1338
{
1339
priv_p priv = arg;
1340
int wait = ((waitflag & M_WAITOK) ? NG_WAITOK : 0) | NG_QUEUE;
1341
1342
ng_send_fn1(priv->node, NULL, &ng_ksocket_listen_upcall2, priv, 0,
1343
wait);
1344
return (SU_OK);
1345
}
1346
1347
static void
1348
ng_ksocket_listen_upcall2(node_p node, hook_p hook, void *arg1, int arg2)
1349
{
1350
const priv_p priv = NG_NODE_PRIVATE(node);
1351
1352
(void )ng_ksocket_accept(priv);
1353
}
1354
1355
/*
1356
* Parse out either an integer value or an alias.
1357
*/
1358
static int
1359
ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
1360
const char *s, int family)
1361
{
1362
int k, val;
1363
char *eptr;
1364
1365
/* Try aliases */
1366
for (k = 0; aliases[k].name != NULL; k++) {
1367
if (strcmp(s, aliases[k].name) == 0
1368
&& aliases[k].family == family)
1369
return aliases[k].value;
1370
}
1371
1372
/* Try parsing as a number */
1373
val = (int)strtoul(s, &eptr, 10);
1374
if (val < 0 || *eptr != '\0')
1375
return (-1);
1376
return (val);
1377
}
1378
1379