Deleted Added
full compact
ng_socket.c (69922) ng_socket.c (70159)
1
2/*
3 * ng_socket.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: Julian Elischer <julian@freebsd.org>
38 *
1
2/*
3 * ng_socket.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: Julian Elischer <julian@freebsd.org>
38 *
39 * $FreeBSD: head/sys/netgraph/ng_socket.c 69922 2000-12-12 18:52:14Z julian $
39 * $FreeBSD: head/sys/netgraph/ng_socket.c 70159 2000-12-18 20:03:32Z julian $
40 * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $
41 */
42
43/*
44 * Netgraph socket nodes
45 *
46 * There are two types of netgraph sockets, control and data.
47 * Control sockets have a netgraph node, but data sockets are
48 * parasitic on control sockets, and have no node of their own.
49 */
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/domain.h>
54#include <sys/errno.h>
55#include <sys/kernel.h>
56#include <sys/filedesc.h>
57#include <sys/malloc.h>
58#include <sys/queue.h>
59#include <sys/mbuf.h>
60#include <sys/protosw.h>
61#include <sys/socket.h>
62#include <sys/socketvar.h>
63#include <sys/sysctl.h>
64#ifdef NOTYET
65#include <sys/vnode.h>
66#endif
67#include <netgraph/ng_message.h>
68#include <netgraph/netgraph.h>
69#include <netgraph/ng_socketvar.h>
70#include <netgraph/ng_socket.h>
71
72/*
73 * It's Ascii-art time!
74 * +-------------+ +-------------+
75 * |socket (ctl)| |socket (data)|
76 * +-------------+ +-------------+
77 * ^ ^
78 * | |
79 * v v
80 * +-----------+ +-----------+
81 * |pcb (ctl)| |pcb (data)|
82 * +-----------+ +-----------+
83 * ^ ^
84 * | |
85 * v v
86 * +--------------------------+
87 * | Socket type private |
88 * | data |
89 * +--------------------------+
90 * ^
91 * |
92 * v
93 * +----------------+
94 * | struct ng_node |
95 * +----------------+
96 */
97
98/* Netgraph node methods */
99static ng_constructor_t ngs_constructor;
100static ng_rcvmsg_t ngs_rcvmsg;
101static ng_shutdown_t ngs_rmnode;
102static ng_newhook_t ngs_newhook;
103static ng_rcvdata_t ngs_rcvdata;
104static ng_disconnect_t ngs_disconnect;
105
106/* Internal methods */
107static int ng_attach_data(struct socket *so);
108static int ng_attach_cntl(struct socket *so);
109static int ng_attach_common(struct socket *so, int type);
110static void ng_detach_common(struct ngpcb *pcbp, int type);
111/*static int ng_internalize(struct mbuf *m, struct proc *p); */
112
113static int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
114static int ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp);
115static int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
116
117static int ngs_mod_event(module_t mod, int event, void *data);
118static int ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg,
119 struct sockaddr_ng *addr);
120
121/* Netgraph type descriptor */
122static struct ng_type typestruct = {
40 * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $
41 */
42
43/*
44 * Netgraph socket nodes
45 *
46 * There are two types of netgraph sockets, control and data.
47 * Control sockets have a netgraph node, but data sockets are
48 * parasitic on control sockets, and have no node of their own.
49 */
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/domain.h>
54#include <sys/errno.h>
55#include <sys/kernel.h>
56#include <sys/filedesc.h>
57#include <sys/malloc.h>
58#include <sys/queue.h>
59#include <sys/mbuf.h>
60#include <sys/protosw.h>
61#include <sys/socket.h>
62#include <sys/socketvar.h>
63#include <sys/sysctl.h>
64#ifdef NOTYET
65#include <sys/vnode.h>
66#endif
67#include <netgraph/ng_message.h>
68#include <netgraph/netgraph.h>
69#include <netgraph/ng_socketvar.h>
70#include <netgraph/ng_socket.h>
71
72/*
73 * It's Ascii-art time!
74 * +-------------+ +-------------+
75 * |socket (ctl)| |socket (data)|
76 * +-------------+ +-------------+
77 * ^ ^
78 * | |
79 * v v
80 * +-----------+ +-----------+
81 * |pcb (ctl)| |pcb (data)|
82 * +-----------+ +-----------+
83 * ^ ^
84 * | |
85 * v v
86 * +--------------------------+
87 * | Socket type private |
88 * | data |
89 * +--------------------------+
90 * ^
91 * |
92 * v
93 * +----------------+
94 * | struct ng_node |
95 * +----------------+
96 */
97
98/* Netgraph node methods */
99static ng_constructor_t ngs_constructor;
100static ng_rcvmsg_t ngs_rcvmsg;
101static ng_shutdown_t ngs_rmnode;
102static ng_newhook_t ngs_newhook;
103static ng_rcvdata_t ngs_rcvdata;
104static ng_disconnect_t ngs_disconnect;
105
106/* Internal methods */
107static int ng_attach_data(struct socket *so);
108static int ng_attach_cntl(struct socket *so);
109static int ng_attach_common(struct socket *so, int type);
110static void ng_detach_common(struct ngpcb *pcbp, int type);
111/*static int ng_internalize(struct mbuf *m, struct proc *p); */
112
113static int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
114static int ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp);
115static int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
116
117static int ngs_mod_event(module_t mod, int event, void *data);
118static int ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg,
119 struct sockaddr_ng *addr);
120
121/* Netgraph type descriptor */
122static struct ng_type typestruct = {
123 NG_VERSION,
123 NG_ABI_VERSION,
124 NG_SOCKET_NODE_TYPE,
125 ngs_mod_event,
126 ngs_constructor,
127 ngs_rcvmsg,
128 ngs_rmnode,
129 ngs_newhook,
130 NULL,
131 NULL,
132 ngs_rcvdata,
133 ngs_disconnect,
134 NULL
135};
136NETGRAPH_INIT(socket, &typestruct);
137
138/* Buffer space */
139static u_long ngpdg_sendspace = 20 * 1024; /* really max datagram size */
140static u_long ngpdg_recvspace = 20 * 1024;
141
142/* List of all sockets */
143LIST_HEAD(, ngpcb) ngsocklist;
144
145#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb)
146
147/* If getting unexplained errors returned, set this to "Debugger("X"); */
148#ifndef TRAP_ERROR
149#define TRAP_ERROR
150#endif
151
152/***************************************************************
153 Control sockets
154***************************************************************/
155
156static int
157ngc_attach(struct socket *so, int proto, struct proc *p)
158{
159 struct ngpcb *const pcbp = sotongpcb(so);
160
161 if (suser(p))
162 return (EPERM);
163 if (pcbp != NULL)
164 return (EISCONN);
165 return (ng_attach_cntl(so));
166}
167
168static int
169ngc_detach(struct socket *so)
170{
171 struct ngpcb *const pcbp = sotongpcb(so);
172
173 if (pcbp == NULL)
174 return (EINVAL);
175 ng_detach_common(pcbp, NG_CONTROL);
176 return (0);
177}
178
179static int
180ngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
181 struct mbuf *control, struct proc *p)
182{
183 struct ngpcb *const pcbp = sotongpcb(so);
184 struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
185 struct ng_mesg *resp;
186 struct mbuf *m0;
187 char *msg, *path = NULL;
188 int len, error = 0;
189
190 if (pcbp == NULL) {
191 error = EINVAL;
192 goto release;
193 }
194#ifdef NOTYET
195 if (control && (error = ng_internalize(control, p))) {
196 if (pcbp->sockdata == NULL) {
197 error = ENOTCONN;
198 goto release;
199 }
200 }
201#else /* NOTYET */
202 if (control) {
203 error = EINVAL;
204 goto release;
205 }
206#endif /* NOTYET */
207
208 /* Require destination as there may be >= 1 hooks on this node */
209 if (addr == NULL) {
210 error = EDESTADDRREQ;
211 goto release;
212 }
213
214 /* Allocate an expendable buffer for the path, chop off
215 * the sockaddr header, and make sure it's NUL terminated */
216 len = sap->sg_len - 2;
217 MALLOC(path, char *, len + 1, M_NETGRAPH, M_WAITOK);
218 if (path == NULL) {
219 error = ENOMEM;
220 goto release;
221 }
222 bcopy(sap->sg_data, path, len);
223 path[len] = '\0';
224
225 /* Move the actual message out of mbufs into a linear buffer.
226 * Start by adding up the size of the data. (could use mh_len?) */
227 for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
228 len += m0->m_len;
229
230 /* Move the data into a linear buffer as well. Messages are not
231 * delivered in mbufs. */
232 MALLOC(msg, char *, len + 1, M_NETGRAPH, M_WAITOK);
233 if (msg == NULL) {
234 error = ENOMEM;
235 goto release;
236 }
237 m_copydata(m, 0, len, msg);
238
239 /* The callee will free the msg when done. The addr is our business. */
240 error = ng_send_msg(pcbp->sockdata->node,
241 (struct ng_mesg *) msg, path, NULL, NULL, &resp);
242
243 /* If the callee responded with a synchronous response, then put it
244 * back on the receive side of the socket; sap is source address. */
245 if (error == 0 && resp != NULL)
246 error = ship_msg(pcbp, resp, sap);
247
248release:
249 if (path != NULL)
250 FREE(path, M_NETGRAPH);
251 if (control != NULL)
252 m_freem(control);
253 if (m != NULL)
254 m_freem(m);
255 return (error);
256}
257
258static int
259ngc_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
260{
261 struct ngpcb *const pcbp = sotongpcb(so);
262
263 if (pcbp == 0)
264 return (EINVAL);
265 return (ng_bind(nam, pcbp));
266}
267
268static int
269ngc_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
270{
271 struct ngpcb *const pcbp = sotongpcb(so);
272
273 if (pcbp == 0)
274 return (EINVAL);
275 return (ng_connect_cntl(nam, pcbp));
276}
277
278/***************************************************************
279 Data sockets
280***************************************************************/
281
282static int
283ngd_attach(struct socket *so, int proto, struct proc *p)
284{
285 struct ngpcb *const pcbp = sotongpcb(so);
286
287 if (pcbp != NULL)
288 return (EISCONN);
289 return (ng_attach_data(so));
290}
291
292static int
293ngd_detach(struct socket *so)
294{
295 struct ngpcb *const pcbp = sotongpcb(so);
296
297 if (pcbp == NULL)
298 return (EINVAL);
299 ng_detach_common(pcbp, NG_DATA);
300 return (0);
301}
302
303static int
304ngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
305 struct mbuf *control, struct proc *p)
306{
307 struct ngpcb *const pcbp = sotongpcb(so);
308 struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
309 int len, error;
310 hook_p hook = NULL;
311 char hookname[NG_HOOKLEN + 1];
312
313 if ((pcbp == NULL) || (control != NULL)) {
314 error = EINVAL;
315 goto release;
316 }
317 if (pcbp->sockdata == NULL) {
318 error = ENOTCONN;
319 goto release;
320 }
321 /*
322 * If the user used any of these ways to not specify an address
323 * then handle specially.
324 */
325 if ((sap == NULL)
326 || ((len = sap->sg_len) <= 2)
327 || (*sap->sg_data == '\0')) {
328 if (pcbp->sockdata->node->numhooks != 1) {
329 error = EDESTADDRREQ;
330 goto release;
331 }
332 /*
333 * if exactly one hook exists, just use it.
334 * Special case to allow write(2) to work on an ng_socket.
335 */
336 hook = LIST_FIRST(&pcbp->sockdata->node->hooks);
337 } else {
338 if (len > NG_HOOKLEN) {
339 error = EINVAL;
340 goto release;
341 }
342
343 /*
344 * chop off the sockaddr header, and make sure it's NUL
345 * terminated
346 */
347 bcopy(sap->sg_data, hookname, len);
348 hookname[len] = '\0';
349
350 /* Find the correct hook from 'hookname' */
351 LIST_FOREACH(hook, &pcbp->sockdata->node->hooks, hooks) {
352 if (strcmp(hookname, hook->name) == 0)
353 break;
354 }
355 if (hook == NULL)
356 error = EHOSTUNREACH;
357 }
358
359 /* Send data (OK if hook is NULL) */
360 NG_SEND_DATA_ONLY(error, hook, m); /* makes m NULL */
361
362release:
363 if (control != NULL)
364 m_freem(control);
365 if (m != NULL)
366 m_freem(m);
367 return (error);
368}
369
370static int
371ngd_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
372{
373 struct ngpcb *const pcbp = sotongpcb(so);
374
375 if (pcbp == 0)
376 return (EINVAL);
377 return (ng_connect_data(nam, pcbp));
378}
379
380/*
381 * Used for both data and control sockets
382 */
383static int
384ng_setsockaddr(struct socket *so, struct sockaddr **addr)
385{
386 struct ngpcb *pcbp;
387 struct sockaddr_ng *sg;
388 int sg_len, namelen, s;
389
390 /* Why isn't sg_data a `char[1]' ? :-( */
391 sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1;
392
393 s = splnet();
394 pcbp = sotongpcb(so);
395 if ((pcbp == NULL) || (pcbp->sockdata == NULL)) {
396 splx(s);
397 return (EINVAL);
398 }
399
400 namelen = 0; /* silence compiler ! */
401
402 if (pcbp->sockdata->node->name != NULL)
403 sg_len += namelen = strlen(pcbp->sockdata->node->name);
404
405 MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK | M_ZERO);
406
407 if (pcbp->sockdata->node->name != NULL)
408 bcopy(pcbp->sockdata->node->name, sg->sg_data, namelen);
409 splx(s);
410
411 sg->sg_len = sg_len;
412 sg->sg_family = AF_NETGRAPH;
413 *addr = (struct sockaddr *)sg;
414
415 return (0);
416}
417
418/*
419 * Attach a socket to it's protocol specific partner.
420 * For a control socket, actually create a netgraph node and attach
421 * to it as well.
422 */
423
424static int
425ng_attach_cntl(struct socket *so)
426{
427 struct ngsock *privdata;
428 struct ngpcb *pcbp;
429 int error;
430
431 /* Setup protocol control block */
432 if ((error = ng_attach_common(so, NG_CONTROL)) != 0)
433 return (error);
434 pcbp = sotongpcb(so);
435
436 /* Allocate node private info */
437 MALLOC(privdata, struct ngsock *,
438 sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO);
439 if (privdata == NULL) {
440 ng_detach_common(pcbp, NG_CONTROL);
441 return (ENOMEM);
442 }
443
444 /* Make the generic node components */
445 if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) {
446 FREE(privdata, M_NETGRAPH);
447 ng_detach_common(pcbp, NG_CONTROL);
448 return (error);
449 }
450 privdata->node->private = privdata;
451
452 /* Link the pcb and the node private data */
453 privdata->ctlsock = pcbp;
454 pcbp->sockdata = privdata;
455 privdata->refs++;
456 return (0);
457}
458
459static int
460ng_attach_data(struct socket *so)
461{
462 return(ng_attach_common(so, NG_DATA));
463}
464
465/*
466 * Set up a socket protocol control block.
467 * This code is shared between control and data sockets.
468 */
469static int
470ng_attach_common(struct socket *so, int type)
471{
472 struct ngpcb *pcbp;
473 int error;
474
475 /* Standard socket setup stuff */
476 error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
477 if (error)
478 return (error);
479
480 /* Allocate the pcb */
481 MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK | M_ZERO);
482 if (pcbp == NULL)
483 return (ENOMEM);
484 pcbp->type = type;
485
486 /* Link the pcb and the socket */
487 so->so_pcb = (caddr_t) pcbp;
488 pcbp->ng_socket = so;
489
490 /* Add the socket to linked list */
491 LIST_INSERT_HEAD(&ngsocklist, pcbp, socks);
492 return (0);
493}
494
495/*
496 * Disassociate the socket from it's protocol specific
497 * partner. If it's attached to a node's private data structure,
498 * then unlink from that too. If we were the last socket attached to it,
499 * then shut down the entire node. Shared code for control and data sockets.
500 */
501static void
502ng_detach_common(struct ngpcb *pcbp, int which)
503{
504 struct ngsock *sockdata;
505
506 if (pcbp->sockdata) {
507 sockdata = pcbp->sockdata;
508 pcbp->sockdata = NULL;
509 switch (which) {
510 case NG_CONTROL:
511 sockdata->ctlsock = NULL;
512 break;
513 case NG_DATA:
514 sockdata->datasock = NULL;
515 break;
516 default:
517 panic(__FUNCTION__);
518 }
519 if ((--sockdata->refs == 0) && (sockdata->node != NULL))
520 ng_rmnode(sockdata->node);
521 }
522 pcbp->ng_socket->so_pcb = NULL;
523 pcbp->ng_socket = NULL;
524 LIST_REMOVE(pcbp, socks);
525 FREE(pcbp, M_PCB);
526}
527
528#ifdef NOTYET
529/*
530 * File descriptors can be passed into a AF_NETGRAPH socket.
531 * Note, that file descriptors cannot be passed OUT.
532 * Only character device descriptors are accepted.
533 * Character devices are useful to connect a graph to a device,
534 * which after all is the purpose of this whole system.
535 */
536static int
537ng_internalize(struct mbuf *control, struct proc *p)
538{
539 struct filedesc *fdp = p->p_fd;
540 struct cmsghdr *cm = mtod(control, struct cmsghdr *);
541 struct file *fp;
542 struct vnode *vn;
543 int oldfds;
544 int fd;
545
546 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
547 cm->cmsg_len != control->m_len) {
548 TRAP_ERROR;
549 return (EINVAL);
550 }
551
552 /* Check there is only one FD. XXX what would more than one signify? */
553 oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int);
554 if (oldfds != 1) {
555 TRAP_ERROR;
556 return (EINVAL);
557 }
558
559 /* Check that the FD given is legit. and change it to a pointer to a
560 * struct file. */
561 fd = *(int *) (cm + 1);
562 if ((unsigned) fd >= fdp->fd_nfiles
563 || (fp = fdp->fd_ofiles[fd]) == NULL) {
564 return (EBADF);
565 }
566
567 /* Depending on what kind of resource it is, act differently. For
568 * devices, we treat it as a file. For a AF_NETGRAPH socket,
569 * shortcut straight to the node. */
570 switch (fp->f_type) {
571 case DTYPE_VNODE:
572 vn = (struct vnode *) fp->f_data;
573 if (vn && (vn->v_type == VCHR)) {
574 /* for a VCHR, actually reference the FILE */
575 fp->f_count++;
576 /* XXX then what :) */
577 /* how to pass on to other modules? */
578 } else {
579 TRAP_ERROR;
580 return (EINVAL);
581 }
582 break;
583 default:
584 TRAP_ERROR;
585 return (EINVAL);
586 }
587 return (0);
588}
589#endif /* NOTYET */
590
591/*
592 * Connect the data socket to a named control socket node.
593 */
594static int
595ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
596{
597 struct sockaddr_ng *sap;
598 node_p farnode;
599 struct ngsock *sockdata;
600 int error;
601
602 /* If we are already connected, don't do it again */
603 if (pcbp->sockdata != NULL)
604 return (EISCONN);
605
606 /* Find the target (victim) and check it doesn't already have a data
607 * socket. Also check it is a 'socket' type node. */
608 sap = (struct sockaddr_ng *) nam;
609 if ((error = ng_path2node(NULL, sap->sg_data, &farnode, NULL)))
610 return (error);
611
612 if (strcmp(farnode->type->name, NG_SOCKET_NODE_TYPE) != 0)
613 return (EINVAL);
614 sockdata = farnode->private;
615 if (sockdata->datasock != NULL)
616 return (EADDRINUSE);
617
618 /* Link the PCB and the private data struct. and note the extra
619 * reference */
620 sockdata->datasock = pcbp;
621 pcbp->sockdata = sockdata;
622 sockdata->refs++;
623 return (0);
624}
625
626/*
627 * Connect the existing control socket node to a named node:hook.
628 * The hook we use on this end is the same name as the remote node name.
629 */
630static int
631ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp)
632{
633 struct ngsock *const sockdata = pcbp->sockdata;
634 struct sockaddr_ng *sap;
635 char *node, *hook;
636 node_p farnode;
637 int rtn, error;
638
639 sap = (struct sockaddr_ng *) nam;
640 rtn = ng_path_parse(sap->sg_data, &node, NULL, &hook);
641 if (rtn < 0 || node == NULL || hook == NULL) {
642 TRAP_ERROR;
643 return (EINVAL);
644 }
645 farnode = ng_findname(sockdata->node, node);
646 if (farnode == NULL) {
647 TRAP_ERROR;
648 return (EADDRNOTAVAIL);
649 }
650
651 /* Connect, using a hook name the same as the far node name. */
652 error = ng_con_nodes(sockdata->node, node, farnode, hook);
653 return error;
654}
655
656/*
657 * Binding a socket means giving the corresponding node a name
658 */
659static int
660ng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
661{
662 struct ngsock *const sockdata = pcbp->sockdata;
663 struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
664
665 if (sockdata == NULL) {
666 TRAP_ERROR;
667 return (EINVAL);
668 }
669 if ((sap->sg_len < 4)
670 || (sap->sg_len > (NG_NODELEN + 3))
671 || (sap->sg_data[0] == '\0')
672 || (sap->sg_data[sap->sg_len - 3] != '\0')) {
673 TRAP_ERROR;
674 return (EINVAL);
675 }
676 return (ng_name_node(sockdata->node, sap->sg_data));
677}
678
679/*
680 * Take a message and pass it up to the control socket associated
681 * with the node.
682 */
683static int
684ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr)
685{
686 struct socket *const so = pcbp->ng_socket;
687 struct mbuf *mdata;
688 int msglen;
689
690 /* Copy the message itself into an mbuf chain */
691 msglen = sizeof(struct ng_mesg) + msg->header.arglen;
692 mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL);
693
694 /* Here we free the message, as we are the end of the line.
695 * We need to do that regardless of whether we got mbufs. */
696 FREE(msg, M_NETGRAPH);
697
698 if (mdata == NULL) {
699 TRAP_ERROR;
700 return (ENOBUFS);
701 }
702
703 /* Send it up to the socket */
704 if (sbappendaddr(&so->so_rcv,
705 (struct sockaddr *) addr, mdata, NULL) == 0) {
706 TRAP_ERROR;
707 m_freem(mdata);
708 return (ENOBUFS);
709 }
710 sorwakeup(so);
711 return (0);
712}
713
714/*
715 * You can only create new nodes from the socket end of things.
716 */
717static int
718ngs_constructor(node_p *nodep)
719{
720 return (EINVAL);
721}
722
723/*
724 * We allow any hook to be connected to the node.
725 * There is no per-hook private information though.
726 */
727static int
728ngs_newhook(node_p node, hook_p hook, const char *name)
729{
730 hook->private = node->private;
731 return (0);
732}
733
734/*
735 * Incoming messages get passed up to the control socket.
736 * Unless they are for us specifically (socket_type)
737 */
738static int
739ngs_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
740 struct ng_mesg **resp, hook_p lasthook)
741{
742 struct ngsock *const sockdata = node->private;
743 struct ngpcb *const pcbp = sockdata->ctlsock;
744 struct sockaddr_ng *addr;
745 int addrlen;
746 int error = 0;
747
748 /* Only allow mesgs to be passed if we have the control socket.
749 * Data sockets can only support the generic messages. */
750 if (pcbp == NULL) {
751 TRAP_ERROR;
752 return (EINVAL);
753 }
754
755 if (msg->header.typecookie == NGM_SOCKET_COOKIE) {
756 switch (msg->header.cmd) {
757 case NGM_SOCK_CMD_NOLINGER:
758 sockdata->flags |= NGS_FLAG_NOLINGER;
759 break;
760 case NGM_SOCK_CMD_LINGER:
761 sockdata->flags &= ~NGS_FLAG_NOLINGER;
762 break;
763 default:
764 error = EINVAL; /* unknown command */
765 }
766 /* Free the message and return */
767 FREE(msg, M_NETGRAPH);
768 return(error);
769
770 }
771 /* Get the return address into a sockaddr */
772 if ((retaddr == NULL) || (*retaddr == '\0'))
773 retaddr = "";
774 addrlen = strlen(retaddr);
775 MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH, M_NOWAIT);
776 if (addr == NULL) {
777 TRAP_ERROR;
778 return (ENOMEM);
779 }
780 addr->sg_len = addrlen + 3;
781 addr->sg_family = AF_NETGRAPH;
782 bcopy(retaddr, addr->sg_data, addrlen);
783 addr->sg_data[addrlen] = '\0';
784
785 /* Send it up */
786 error = ship_msg(pcbp, msg, addr);
787 FREE(addr, M_NETGRAPH);
788 return (error);
789}
790
791/*
792 * Receive data on a hook
793 */
794static int
795ngs_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
796 struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp)
797{
798 struct ngsock *const sockdata = hook->node->private;
799 struct ngpcb *const pcbp = sockdata->datasock;
800 struct socket *so;
801 struct sockaddr_ng *addr;
802 char *addrbuf[NG_HOOKLEN + 1 + 4];
803 int addrlen;
804
805 /* If there is no data socket, black-hole it */
806 if (pcbp == NULL) {
807 NG_FREE_DATA(m, meta);
808 return (0);
809 }
810 so = pcbp->ng_socket;
811
812 /* Get the return address into a sockaddr. */
813 addrlen = strlen(hook->name); /* <= NG_HOOKLEN */
814 addr = (struct sockaddr_ng *) addrbuf;
815 addr->sg_len = addrlen + 3;
816 addr->sg_family = AF_NETGRAPH;
817 bcopy(hook->name, addr->sg_data, addrlen);
818 addr->sg_data[addrlen] = '\0';
819
820 /* We have no use for the meta data, free/clear it now. */
821 NG_FREE_META(meta);
822
823 /* Try to tell the socket which hook it came in on */
824 if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) {
825 m_freem(m);
826 TRAP_ERROR;
827 return (ENOBUFS);
828 }
829 sorwakeup(so);
830 return (0);
831}
832
833/*
834 * Hook disconnection
835 *
836 * For this type, removal of the last link destroys the node
837 * if the NOLINGER flag is set.
838 */
839static int
840ngs_disconnect(hook_p hook)
841{
842 struct ngsock *const sockdata = hook->node->private;
843
844 if ((sockdata->flags & NGS_FLAG_NOLINGER )
845 && (hook->node->numhooks == 0)) {
846 ng_rmnode(hook->node);
847 }
848 return (0);
849}
850
851/*
852 * Do local shutdown processing.
853 * In this case, that involves making sure the socket
854 * knows we should be shutting down.
855 */
856static int
857ngs_rmnode(node_p node)
858{
859 struct ngsock *const sockdata = node->private;
860 struct ngpcb *const dpcbp = sockdata->datasock;
861 struct ngpcb *const pcbp = sockdata->ctlsock;
862
863 ng_cutlinks(node);
864 ng_unname(node);
865
866 if (dpcbp != NULL) {
867 soisdisconnected(dpcbp->ng_socket);
868 dpcbp->sockdata = NULL;
869 sockdata->datasock = NULL;
870 sockdata->refs--;
871 }
872 if (pcbp != NULL) {
873 soisdisconnected(pcbp->ng_socket);
874 pcbp->sockdata = NULL;
875 sockdata->ctlsock = NULL;
876 sockdata->refs--;
877 }
878 node->private = NULL;
879 ng_unref(node);
880 FREE(sockdata, M_NETGRAPH);
881 return (0);
882}
883
884/*
885 * Control and data socket type descriptors
886 */
887
888static struct pr_usrreqs ngc_usrreqs = {
889 NULL, /* abort */
890 pru_accept_notsupp,
891 ngc_attach,
892 ngc_bind,
893 ngc_connect,
894 pru_connect2_notsupp,
895 pru_control_notsupp,
896 ngc_detach,
897 NULL, /* disconnect */
898 pru_listen_notsupp,
899 NULL, /* setpeeraddr */
900 pru_rcvd_notsupp,
901 pru_rcvoob_notsupp,
902 ngc_send,
903 pru_sense_null,
904 NULL, /* shutdown */
905 ng_setsockaddr,
906 sosend,
907 soreceive,
908 sopoll
909};
910
911static struct pr_usrreqs ngd_usrreqs = {
912 NULL, /* abort */
913 pru_accept_notsupp,
914 ngd_attach,
915 NULL, /* bind */
916 ngd_connect,
917 pru_connect2_notsupp,
918 pru_control_notsupp,
919 ngd_detach,
920 NULL, /* disconnect */
921 pru_listen_notsupp,
922 NULL, /* setpeeraddr */
923 pru_rcvd_notsupp,
924 pru_rcvoob_notsupp,
925 ngd_send,
926 pru_sense_null,
927 NULL, /* shutdown */
928 ng_setsockaddr,
929 sosend,
930 soreceive,
931 sopoll
932};
933
934/*
935 * Definitions of protocols supported in the NETGRAPH domain.
936 */
937
938extern struct domain ngdomain; /* stop compiler warnings */
939
940static struct protosw ngsw[] = {
941 {
942 SOCK_DGRAM,
943 &ngdomain,
944 NG_CONTROL,
945 PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,
946 0, 0, 0, 0,
947 NULL,
948 0, 0, 0, 0,
949 &ngc_usrreqs
950 },
951 {
952 SOCK_DGRAM,
953 &ngdomain,
954 NG_DATA,
955 PR_ATOMIC | PR_ADDR,
956 0, 0, 0, 0,
957 NULL,
958 0, 0, 0, 0,
959 &ngd_usrreqs
960 }
961};
962
963struct domain ngdomain = {
964 AF_NETGRAPH,
965 "netgraph",
966 0,
967 NULL,
968 NULL,
969 ngsw,
970 &ngsw[sizeof(ngsw) / sizeof(ngsw[0])],
971 0,
972 NULL,
973 0,
974 0
975};
976
977/*
978 * Handle loading and unloading for this node type
979 * This is to handle auxiliary linkages (e.g protocol domain addition).
980 */
981static int
982ngs_mod_event(module_t mod, int event, void *data)
983{
984 int error = 0;
985
986 switch (event) {
987 case MOD_LOAD:
988 /* Register protocol domain */
989 net_add_domain(&ngdomain);
990 break;
991 case MOD_UNLOAD:
992 /* Insure there are no open netgraph sockets */
993 if (!LIST_EMPTY(&ngsocklist)) {
994 error = EBUSY;
995 break;
996 }
997
998#ifdef NOTYET
999 /* Unregister protocol domain XXX can't do this yet.. */
1000 if ((error = net_rm_domain(&ngdomain)) != 0)
1001 break;
1002#else
1003 error = EBUSY;
1004#endif
1005 break;
1006 default:
1007 error = EOPNOTSUPP;
1008 break;
1009 }
1010 return (error);
1011}
1012
1013SYSCTL_NODE(_net, AF_NETGRAPH, graph, CTLFLAG_RW, 0, "netgraph Family");
1014SYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, "");
1015SYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA");
1016SYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, "");
1017SYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL");
1018SYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, "");
1019
124 NG_SOCKET_NODE_TYPE,
125 ngs_mod_event,
126 ngs_constructor,
127 ngs_rcvmsg,
128 ngs_rmnode,
129 ngs_newhook,
130 NULL,
131 NULL,
132 ngs_rcvdata,
133 ngs_disconnect,
134 NULL
135};
136NETGRAPH_INIT(socket, &typestruct);
137
138/* Buffer space */
139static u_long ngpdg_sendspace = 20 * 1024; /* really max datagram size */
140static u_long ngpdg_recvspace = 20 * 1024;
141
142/* List of all sockets */
143LIST_HEAD(, ngpcb) ngsocklist;
144
145#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb)
146
147/* If getting unexplained errors returned, set this to "Debugger("X"); */
148#ifndef TRAP_ERROR
149#define TRAP_ERROR
150#endif
151
152/***************************************************************
153 Control sockets
154***************************************************************/
155
156static int
157ngc_attach(struct socket *so, int proto, struct proc *p)
158{
159 struct ngpcb *const pcbp = sotongpcb(so);
160
161 if (suser(p))
162 return (EPERM);
163 if (pcbp != NULL)
164 return (EISCONN);
165 return (ng_attach_cntl(so));
166}
167
168static int
169ngc_detach(struct socket *so)
170{
171 struct ngpcb *const pcbp = sotongpcb(so);
172
173 if (pcbp == NULL)
174 return (EINVAL);
175 ng_detach_common(pcbp, NG_CONTROL);
176 return (0);
177}
178
179static int
180ngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
181 struct mbuf *control, struct proc *p)
182{
183 struct ngpcb *const pcbp = sotongpcb(so);
184 struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
185 struct ng_mesg *resp;
186 struct mbuf *m0;
187 char *msg, *path = NULL;
188 int len, error = 0;
189
190 if (pcbp == NULL) {
191 error = EINVAL;
192 goto release;
193 }
194#ifdef NOTYET
195 if (control && (error = ng_internalize(control, p))) {
196 if (pcbp->sockdata == NULL) {
197 error = ENOTCONN;
198 goto release;
199 }
200 }
201#else /* NOTYET */
202 if (control) {
203 error = EINVAL;
204 goto release;
205 }
206#endif /* NOTYET */
207
208 /* Require destination as there may be >= 1 hooks on this node */
209 if (addr == NULL) {
210 error = EDESTADDRREQ;
211 goto release;
212 }
213
214 /* Allocate an expendable buffer for the path, chop off
215 * the sockaddr header, and make sure it's NUL terminated */
216 len = sap->sg_len - 2;
217 MALLOC(path, char *, len + 1, M_NETGRAPH, M_WAITOK);
218 if (path == NULL) {
219 error = ENOMEM;
220 goto release;
221 }
222 bcopy(sap->sg_data, path, len);
223 path[len] = '\0';
224
225 /* Move the actual message out of mbufs into a linear buffer.
226 * Start by adding up the size of the data. (could use mh_len?) */
227 for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
228 len += m0->m_len;
229
230 /* Move the data into a linear buffer as well. Messages are not
231 * delivered in mbufs. */
232 MALLOC(msg, char *, len + 1, M_NETGRAPH, M_WAITOK);
233 if (msg == NULL) {
234 error = ENOMEM;
235 goto release;
236 }
237 m_copydata(m, 0, len, msg);
238
239 /* The callee will free the msg when done. The addr is our business. */
240 error = ng_send_msg(pcbp->sockdata->node,
241 (struct ng_mesg *) msg, path, NULL, NULL, &resp);
242
243 /* If the callee responded with a synchronous response, then put it
244 * back on the receive side of the socket; sap is source address. */
245 if (error == 0 && resp != NULL)
246 error = ship_msg(pcbp, resp, sap);
247
248release:
249 if (path != NULL)
250 FREE(path, M_NETGRAPH);
251 if (control != NULL)
252 m_freem(control);
253 if (m != NULL)
254 m_freem(m);
255 return (error);
256}
257
258static int
259ngc_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
260{
261 struct ngpcb *const pcbp = sotongpcb(so);
262
263 if (pcbp == 0)
264 return (EINVAL);
265 return (ng_bind(nam, pcbp));
266}
267
268static int
269ngc_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
270{
271 struct ngpcb *const pcbp = sotongpcb(so);
272
273 if (pcbp == 0)
274 return (EINVAL);
275 return (ng_connect_cntl(nam, pcbp));
276}
277
278/***************************************************************
279 Data sockets
280***************************************************************/
281
282static int
283ngd_attach(struct socket *so, int proto, struct proc *p)
284{
285 struct ngpcb *const pcbp = sotongpcb(so);
286
287 if (pcbp != NULL)
288 return (EISCONN);
289 return (ng_attach_data(so));
290}
291
292static int
293ngd_detach(struct socket *so)
294{
295 struct ngpcb *const pcbp = sotongpcb(so);
296
297 if (pcbp == NULL)
298 return (EINVAL);
299 ng_detach_common(pcbp, NG_DATA);
300 return (0);
301}
302
303static int
304ngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
305 struct mbuf *control, struct proc *p)
306{
307 struct ngpcb *const pcbp = sotongpcb(so);
308 struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
309 int len, error;
310 hook_p hook = NULL;
311 char hookname[NG_HOOKLEN + 1];
312
313 if ((pcbp == NULL) || (control != NULL)) {
314 error = EINVAL;
315 goto release;
316 }
317 if (pcbp->sockdata == NULL) {
318 error = ENOTCONN;
319 goto release;
320 }
321 /*
322 * If the user used any of these ways to not specify an address
323 * then handle specially.
324 */
325 if ((sap == NULL)
326 || ((len = sap->sg_len) <= 2)
327 || (*sap->sg_data == '\0')) {
328 if (pcbp->sockdata->node->numhooks != 1) {
329 error = EDESTADDRREQ;
330 goto release;
331 }
332 /*
333 * if exactly one hook exists, just use it.
334 * Special case to allow write(2) to work on an ng_socket.
335 */
336 hook = LIST_FIRST(&pcbp->sockdata->node->hooks);
337 } else {
338 if (len > NG_HOOKLEN) {
339 error = EINVAL;
340 goto release;
341 }
342
343 /*
344 * chop off the sockaddr header, and make sure it's NUL
345 * terminated
346 */
347 bcopy(sap->sg_data, hookname, len);
348 hookname[len] = '\0';
349
350 /* Find the correct hook from 'hookname' */
351 LIST_FOREACH(hook, &pcbp->sockdata->node->hooks, hooks) {
352 if (strcmp(hookname, hook->name) == 0)
353 break;
354 }
355 if (hook == NULL)
356 error = EHOSTUNREACH;
357 }
358
359 /* Send data (OK if hook is NULL) */
360 NG_SEND_DATA_ONLY(error, hook, m); /* makes m NULL */
361
362release:
363 if (control != NULL)
364 m_freem(control);
365 if (m != NULL)
366 m_freem(m);
367 return (error);
368}
369
370static int
371ngd_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
372{
373 struct ngpcb *const pcbp = sotongpcb(so);
374
375 if (pcbp == 0)
376 return (EINVAL);
377 return (ng_connect_data(nam, pcbp));
378}
379
380/*
381 * Used for both data and control sockets
382 */
383static int
384ng_setsockaddr(struct socket *so, struct sockaddr **addr)
385{
386 struct ngpcb *pcbp;
387 struct sockaddr_ng *sg;
388 int sg_len, namelen, s;
389
390 /* Why isn't sg_data a `char[1]' ? :-( */
391 sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1;
392
393 s = splnet();
394 pcbp = sotongpcb(so);
395 if ((pcbp == NULL) || (pcbp->sockdata == NULL)) {
396 splx(s);
397 return (EINVAL);
398 }
399
400 namelen = 0; /* silence compiler ! */
401
402 if (pcbp->sockdata->node->name != NULL)
403 sg_len += namelen = strlen(pcbp->sockdata->node->name);
404
405 MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK | M_ZERO);
406
407 if (pcbp->sockdata->node->name != NULL)
408 bcopy(pcbp->sockdata->node->name, sg->sg_data, namelen);
409 splx(s);
410
411 sg->sg_len = sg_len;
412 sg->sg_family = AF_NETGRAPH;
413 *addr = (struct sockaddr *)sg;
414
415 return (0);
416}
417
418/*
419 * Attach a socket to it's protocol specific partner.
420 * For a control socket, actually create a netgraph node and attach
421 * to it as well.
422 */
423
424static int
425ng_attach_cntl(struct socket *so)
426{
427 struct ngsock *privdata;
428 struct ngpcb *pcbp;
429 int error;
430
431 /* Setup protocol control block */
432 if ((error = ng_attach_common(so, NG_CONTROL)) != 0)
433 return (error);
434 pcbp = sotongpcb(so);
435
436 /* Allocate node private info */
437 MALLOC(privdata, struct ngsock *,
438 sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO);
439 if (privdata == NULL) {
440 ng_detach_common(pcbp, NG_CONTROL);
441 return (ENOMEM);
442 }
443
444 /* Make the generic node components */
445 if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) {
446 FREE(privdata, M_NETGRAPH);
447 ng_detach_common(pcbp, NG_CONTROL);
448 return (error);
449 }
450 privdata->node->private = privdata;
451
452 /* Link the pcb and the node private data */
453 privdata->ctlsock = pcbp;
454 pcbp->sockdata = privdata;
455 privdata->refs++;
456 return (0);
457}
458
459static int
460ng_attach_data(struct socket *so)
461{
462 return(ng_attach_common(so, NG_DATA));
463}
464
465/*
466 * Set up a socket protocol control block.
467 * This code is shared between control and data sockets.
468 */
469static int
470ng_attach_common(struct socket *so, int type)
471{
472 struct ngpcb *pcbp;
473 int error;
474
475 /* Standard socket setup stuff */
476 error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
477 if (error)
478 return (error);
479
480 /* Allocate the pcb */
481 MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK | M_ZERO);
482 if (pcbp == NULL)
483 return (ENOMEM);
484 pcbp->type = type;
485
486 /* Link the pcb and the socket */
487 so->so_pcb = (caddr_t) pcbp;
488 pcbp->ng_socket = so;
489
490 /* Add the socket to linked list */
491 LIST_INSERT_HEAD(&ngsocklist, pcbp, socks);
492 return (0);
493}
494
495/*
496 * Disassociate the socket from it's protocol specific
497 * partner. If it's attached to a node's private data structure,
498 * then unlink from that too. If we were the last socket attached to it,
499 * then shut down the entire node. Shared code for control and data sockets.
500 */
501static void
502ng_detach_common(struct ngpcb *pcbp, int which)
503{
504 struct ngsock *sockdata;
505
506 if (pcbp->sockdata) {
507 sockdata = pcbp->sockdata;
508 pcbp->sockdata = NULL;
509 switch (which) {
510 case NG_CONTROL:
511 sockdata->ctlsock = NULL;
512 break;
513 case NG_DATA:
514 sockdata->datasock = NULL;
515 break;
516 default:
517 panic(__FUNCTION__);
518 }
519 if ((--sockdata->refs == 0) && (sockdata->node != NULL))
520 ng_rmnode(sockdata->node);
521 }
522 pcbp->ng_socket->so_pcb = NULL;
523 pcbp->ng_socket = NULL;
524 LIST_REMOVE(pcbp, socks);
525 FREE(pcbp, M_PCB);
526}
527
528#ifdef NOTYET
529/*
530 * File descriptors can be passed into a AF_NETGRAPH socket.
531 * Note, that file descriptors cannot be passed OUT.
532 * Only character device descriptors are accepted.
533 * Character devices are useful to connect a graph to a device,
534 * which after all is the purpose of this whole system.
535 */
536static int
537ng_internalize(struct mbuf *control, struct proc *p)
538{
539 struct filedesc *fdp = p->p_fd;
540 struct cmsghdr *cm = mtod(control, struct cmsghdr *);
541 struct file *fp;
542 struct vnode *vn;
543 int oldfds;
544 int fd;
545
546 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
547 cm->cmsg_len != control->m_len) {
548 TRAP_ERROR;
549 return (EINVAL);
550 }
551
552 /* Check there is only one FD. XXX what would more than one signify? */
553 oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int);
554 if (oldfds != 1) {
555 TRAP_ERROR;
556 return (EINVAL);
557 }
558
559 /* Check that the FD given is legit. and change it to a pointer to a
560 * struct file. */
561 fd = *(int *) (cm + 1);
562 if ((unsigned) fd >= fdp->fd_nfiles
563 || (fp = fdp->fd_ofiles[fd]) == NULL) {
564 return (EBADF);
565 }
566
567 /* Depending on what kind of resource it is, act differently. For
568 * devices, we treat it as a file. For a AF_NETGRAPH socket,
569 * shortcut straight to the node. */
570 switch (fp->f_type) {
571 case DTYPE_VNODE:
572 vn = (struct vnode *) fp->f_data;
573 if (vn && (vn->v_type == VCHR)) {
574 /* for a VCHR, actually reference the FILE */
575 fp->f_count++;
576 /* XXX then what :) */
577 /* how to pass on to other modules? */
578 } else {
579 TRAP_ERROR;
580 return (EINVAL);
581 }
582 break;
583 default:
584 TRAP_ERROR;
585 return (EINVAL);
586 }
587 return (0);
588}
589#endif /* NOTYET */
590
591/*
592 * Connect the data socket to a named control socket node.
593 */
594static int
595ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
596{
597 struct sockaddr_ng *sap;
598 node_p farnode;
599 struct ngsock *sockdata;
600 int error;
601
602 /* If we are already connected, don't do it again */
603 if (pcbp->sockdata != NULL)
604 return (EISCONN);
605
606 /* Find the target (victim) and check it doesn't already have a data
607 * socket. Also check it is a 'socket' type node. */
608 sap = (struct sockaddr_ng *) nam;
609 if ((error = ng_path2node(NULL, sap->sg_data, &farnode, NULL)))
610 return (error);
611
612 if (strcmp(farnode->type->name, NG_SOCKET_NODE_TYPE) != 0)
613 return (EINVAL);
614 sockdata = farnode->private;
615 if (sockdata->datasock != NULL)
616 return (EADDRINUSE);
617
618 /* Link the PCB and the private data struct. and note the extra
619 * reference */
620 sockdata->datasock = pcbp;
621 pcbp->sockdata = sockdata;
622 sockdata->refs++;
623 return (0);
624}
625
626/*
627 * Connect the existing control socket node to a named node:hook.
628 * The hook we use on this end is the same name as the remote node name.
629 */
630static int
631ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp)
632{
633 struct ngsock *const sockdata = pcbp->sockdata;
634 struct sockaddr_ng *sap;
635 char *node, *hook;
636 node_p farnode;
637 int rtn, error;
638
639 sap = (struct sockaddr_ng *) nam;
640 rtn = ng_path_parse(sap->sg_data, &node, NULL, &hook);
641 if (rtn < 0 || node == NULL || hook == NULL) {
642 TRAP_ERROR;
643 return (EINVAL);
644 }
645 farnode = ng_findname(sockdata->node, node);
646 if (farnode == NULL) {
647 TRAP_ERROR;
648 return (EADDRNOTAVAIL);
649 }
650
651 /* Connect, using a hook name the same as the far node name. */
652 error = ng_con_nodes(sockdata->node, node, farnode, hook);
653 return error;
654}
655
656/*
657 * Binding a socket means giving the corresponding node a name
658 */
659static int
660ng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
661{
662 struct ngsock *const sockdata = pcbp->sockdata;
663 struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
664
665 if (sockdata == NULL) {
666 TRAP_ERROR;
667 return (EINVAL);
668 }
669 if ((sap->sg_len < 4)
670 || (sap->sg_len > (NG_NODELEN + 3))
671 || (sap->sg_data[0] == '\0')
672 || (sap->sg_data[sap->sg_len - 3] != '\0')) {
673 TRAP_ERROR;
674 return (EINVAL);
675 }
676 return (ng_name_node(sockdata->node, sap->sg_data));
677}
678
679/*
680 * Take a message and pass it up to the control socket associated
681 * with the node.
682 */
683static int
684ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr)
685{
686 struct socket *const so = pcbp->ng_socket;
687 struct mbuf *mdata;
688 int msglen;
689
690 /* Copy the message itself into an mbuf chain */
691 msglen = sizeof(struct ng_mesg) + msg->header.arglen;
692 mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL);
693
694 /* Here we free the message, as we are the end of the line.
695 * We need to do that regardless of whether we got mbufs. */
696 FREE(msg, M_NETGRAPH);
697
698 if (mdata == NULL) {
699 TRAP_ERROR;
700 return (ENOBUFS);
701 }
702
703 /* Send it up to the socket */
704 if (sbappendaddr(&so->so_rcv,
705 (struct sockaddr *) addr, mdata, NULL) == 0) {
706 TRAP_ERROR;
707 m_freem(mdata);
708 return (ENOBUFS);
709 }
710 sorwakeup(so);
711 return (0);
712}
713
714/*
715 * You can only create new nodes from the socket end of things.
716 */
717static int
718ngs_constructor(node_p *nodep)
719{
720 return (EINVAL);
721}
722
723/*
724 * We allow any hook to be connected to the node.
725 * There is no per-hook private information though.
726 */
727static int
728ngs_newhook(node_p node, hook_p hook, const char *name)
729{
730 hook->private = node->private;
731 return (0);
732}
733
734/*
735 * Incoming messages get passed up to the control socket.
736 * Unless they are for us specifically (socket_type)
737 */
738static int
739ngs_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
740 struct ng_mesg **resp, hook_p lasthook)
741{
742 struct ngsock *const sockdata = node->private;
743 struct ngpcb *const pcbp = sockdata->ctlsock;
744 struct sockaddr_ng *addr;
745 int addrlen;
746 int error = 0;
747
748 /* Only allow mesgs to be passed if we have the control socket.
749 * Data sockets can only support the generic messages. */
750 if (pcbp == NULL) {
751 TRAP_ERROR;
752 return (EINVAL);
753 }
754
755 if (msg->header.typecookie == NGM_SOCKET_COOKIE) {
756 switch (msg->header.cmd) {
757 case NGM_SOCK_CMD_NOLINGER:
758 sockdata->flags |= NGS_FLAG_NOLINGER;
759 break;
760 case NGM_SOCK_CMD_LINGER:
761 sockdata->flags &= ~NGS_FLAG_NOLINGER;
762 break;
763 default:
764 error = EINVAL; /* unknown command */
765 }
766 /* Free the message and return */
767 FREE(msg, M_NETGRAPH);
768 return(error);
769
770 }
771 /* Get the return address into a sockaddr */
772 if ((retaddr == NULL) || (*retaddr == '\0'))
773 retaddr = "";
774 addrlen = strlen(retaddr);
775 MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH, M_NOWAIT);
776 if (addr == NULL) {
777 TRAP_ERROR;
778 return (ENOMEM);
779 }
780 addr->sg_len = addrlen + 3;
781 addr->sg_family = AF_NETGRAPH;
782 bcopy(retaddr, addr->sg_data, addrlen);
783 addr->sg_data[addrlen] = '\0';
784
785 /* Send it up */
786 error = ship_msg(pcbp, msg, addr);
787 FREE(addr, M_NETGRAPH);
788 return (error);
789}
790
791/*
792 * Receive data on a hook
793 */
794static int
795ngs_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
796 struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp)
797{
798 struct ngsock *const sockdata = hook->node->private;
799 struct ngpcb *const pcbp = sockdata->datasock;
800 struct socket *so;
801 struct sockaddr_ng *addr;
802 char *addrbuf[NG_HOOKLEN + 1 + 4];
803 int addrlen;
804
805 /* If there is no data socket, black-hole it */
806 if (pcbp == NULL) {
807 NG_FREE_DATA(m, meta);
808 return (0);
809 }
810 so = pcbp->ng_socket;
811
812 /* Get the return address into a sockaddr. */
813 addrlen = strlen(hook->name); /* <= NG_HOOKLEN */
814 addr = (struct sockaddr_ng *) addrbuf;
815 addr->sg_len = addrlen + 3;
816 addr->sg_family = AF_NETGRAPH;
817 bcopy(hook->name, addr->sg_data, addrlen);
818 addr->sg_data[addrlen] = '\0';
819
820 /* We have no use for the meta data, free/clear it now. */
821 NG_FREE_META(meta);
822
823 /* Try to tell the socket which hook it came in on */
824 if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) {
825 m_freem(m);
826 TRAP_ERROR;
827 return (ENOBUFS);
828 }
829 sorwakeup(so);
830 return (0);
831}
832
833/*
834 * Hook disconnection
835 *
836 * For this type, removal of the last link destroys the node
837 * if the NOLINGER flag is set.
838 */
839static int
840ngs_disconnect(hook_p hook)
841{
842 struct ngsock *const sockdata = hook->node->private;
843
844 if ((sockdata->flags & NGS_FLAG_NOLINGER )
845 && (hook->node->numhooks == 0)) {
846 ng_rmnode(hook->node);
847 }
848 return (0);
849}
850
851/*
852 * Do local shutdown processing.
853 * In this case, that involves making sure the socket
854 * knows we should be shutting down.
855 */
856static int
857ngs_rmnode(node_p node)
858{
859 struct ngsock *const sockdata = node->private;
860 struct ngpcb *const dpcbp = sockdata->datasock;
861 struct ngpcb *const pcbp = sockdata->ctlsock;
862
863 ng_cutlinks(node);
864 ng_unname(node);
865
866 if (dpcbp != NULL) {
867 soisdisconnected(dpcbp->ng_socket);
868 dpcbp->sockdata = NULL;
869 sockdata->datasock = NULL;
870 sockdata->refs--;
871 }
872 if (pcbp != NULL) {
873 soisdisconnected(pcbp->ng_socket);
874 pcbp->sockdata = NULL;
875 sockdata->ctlsock = NULL;
876 sockdata->refs--;
877 }
878 node->private = NULL;
879 ng_unref(node);
880 FREE(sockdata, M_NETGRAPH);
881 return (0);
882}
883
884/*
885 * Control and data socket type descriptors
886 */
887
888static struct pr_usrreqs ngc_usrreqs = {
889 NULL, /* abort */
890 pru_accept_notsupp,
891 ngc_attach,
892 ngc_bind,
893 ngc_connect,
894 pru_connect2_notsupp,
895 pru_control_notsupp,
896 ngc_detach,
897 NULL, /* disconnect */
898 pru_listen_notsupp,
899 NULL, /* setpeeraddr */
900 pru_rcvd_notsupp,
901 pru_rcvoob_notsupp,
902 ngc_send,
903 pru_sense_null,
904 NULL, /* shutdown */
905 ng_setsockaddr,
906 sosend,
907 soreceive,
908 sopoll
909};
910
911static struct pr_usrreqs ngd_usrreqs = {
912 NULL, /* abort */
913 pru_accept_notsupp,
914 ngd_attach,
915 NULL, /* bind */
916 ngd_connect,
917 pru_connect2_notsupp,
918 pru_control_notsupp,
919 ngd_detach,
920 NULL, /* disconnect */
921 pru_listen_notsupp,
922 NULL, /* setpeeraddr */
923 pru_rcvd_notsupp,
924 pru_rcvoob_notsupp,
925 ngd_send,
926 pru_sense_null,
927 NULL, /* shutdown */
928 ng_setsockaddr,
929 sosend,
930 soreceive,
931 sopoll
932};
933
934/*
935 * Definitions of protocols supported in the NETGRAPH domain.
936 */
937
938extern struct domain ngdomain; /* stop compiler warnings */
939
940static struct protosw ngsw[] = {
941 {
942 SOCK_DGRAM,
943 &ngdomain,
944 NG_CONTROL,
945 PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,
946 0, 0, 0, 0,
947 NULL,
948 0, 0, 0, 0,
949 &ngc_usrreqs
950 },
951 {
952 SOCK_DGRAM,
953 &ngdomain,
954 NG_DATA,
955 PR_ATOMIC | PR_ADDR,
956 0, 0, 0, 0,
957 NULL,
958 0, 0, 0, 0,
959 &ngd_usrreqs
960 }
961};
962
963struct domain ngdomain = {
964 AF_NETGRAPH,
965 "netgraph",
966 0,
967 NULL,
968 NULL,
969 ngsw,
970 &ngsw[sizeof(ngsw) / sizeof(ngsw[0])],
971 0,
972 NULL,
973 0,
974 0
975};
976
977/*
978 * Handle loading and unloading for this node type
979 * This is to handle auxiliary linkages (e.g protocol domain addition).
980 */
981static int
982ngs_mod_event(module_t mod, int event, void *data)
983{
984 int error = 0;
985
986 switch (event) {
987 case MOD_LOAD:
988 /* Register protocol domain */
989 net_add_domain(&ngdomain);
990 break;
991 case MOD_UNLOAD:
992 /* Insure there are no open netgraph sockets */
993 if (!LIST_EMPTY(&ngsocklist)) {
994 error = EBUSY;
995 break;
996 }
997
998#ifdef NOTYET
999 /* Unregister protocol domain XXX can't do this yet.. */
1000 if ((error = net_rm_domain(&ngdomain)) != 0)
1001 break;
1002#else
1003 error = EBUSY;
1004#endif
1005 break;
1006 default:
1007 error = EOPNOTSUPP;
1008 break;
1009 }
1010 return (error);
1011}
1012
1013SYSCTL_NODE(_net, AF_NETGRAPH, graph, CTLFLAG_RW, 0, "netgraph Family");
1014SYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, "");
1015SYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA");
1016SYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, "");
1017SYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL");
1018SYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, "");
1019