ng_socket.c revision 53498
152419Sjulian 252419Sjulian/* 352419Sjulian * ng_socket.c 452419Sjulian * 552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 652419Sjulian * All rights reserved. 752419Sjulian * 852419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 952419Sjulian * redistribution of this software, in source or object code forms, with or 1052419Sjulian * without modifications are expressly permitted by Whistle Communications; 1152419Sjulian * provided, however, that: 1252419Sjulian * 1. Any and all reproductions of the source or object code must include the 1352419Sjulian * copyright notice above and the following disclaimer of warranties; and 1452419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1552419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1652419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1752419Sjulian * such appears in the above copyright notice or in the software. 1852419Sjulian * 1952419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2052419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2152419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2252419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2352419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2452419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2552419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2652419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2752419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2852419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2952419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3052419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3152419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3252419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3352419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3452419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3552419Sjulian * OF SUCH DAMAGE. 3652419Sjulian * 3752419Sjulian * Author: Julian Elischer <julian@whistle.com> 3852419Sjulian * 3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_socket.c 53498 1999-11-21 10:43:05Z julian $ 4052752Sjulian * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $ 4152419Sjulian */ 4252419Sjulian 4352419Sjulian/* 4452419Sjulian * Netgraph socket nodes 4552419Sjulian * 4652419Sjulian * There are two types of netgraph sockets, control and data. 4752419Sjulian * Control sockets have a netgraph node, but data sockets are 4852419Sjulian * parasitic on control sockets, and have no node of their own. 4952419Sjulian */ 5052419Sjulian 5152419Sjulian#include <sys/param.h> 5252419Sjulian#include <sys/systm.h> 5352419Sjulian#include <sys/proc.h> 5452419Sjulian#include <sys/domain.h> 5552419Sjulian#include <sys/errno.h> 5652419Sjulian#include <sys/kernel.h> 5752419Sjulian#include <sys/file.h> 5852419Sjulian#include <sys/filedesc.h> 5952419Sjulian#include <sys/malloc.h> 6052419Sjulian#include <sys/queue.h> 6152419Sjulian#include <sys/mbuf.h> 6252419Sjulian#include <sys/protosw.h> 6352419Sjulian#include <sys/socket.h> 6452419Sjulian#include <sys/socketvar.h> 6552419Sjulian#include <sys/sysctl.h> 6652419Sjulian#ifdef NOTYET 6752419Sjulian#include <sys/vnode.h> 6852419Sjulian#endif 6952419Sjulian#include <netgraph/ng_message.h> 7052419Sjulian#include <netgraph/netgraph.h> 7152919Sjulian#include <netgraph/ng_socketvar.h> 7252419Sjulian#include <netgraph/ng_socket.h> 7352419Sjulian 7452419Sjulian/* 7552419Sjulian * It's Ascii-art time! 7652419Sjulian * +-------------+ +-------------+ 7752419Sjulian * |socket (ctl)| |socket (data)| 7852419Sjulian * +-------------+ +-------------+ 7952419Sjulian * ^ ^ 8052419Sjulian * | | 8152419Sjulian * v v 8252419Sjulian * +-----------+ +-----------+ 8352419Sjulian * |pcb (ctl)| |pcb (data)| 8452419Sjulian * +-----------+ +-----------+ 8552419Sjulian * ^ ^ 8652419Sjulian * | | 8752419Sjulian * v v 8852419Sjulian * +--------------------------+ 8952419Sjulian * | Socket type private | 9052419Sjulian * | data | 9152419Sjulian * +--------------------------+ 9252419Sjulian * ^ 9352419Sjulian * | 9452419Sjulian * v 9552419Sjulian * +----------------+ 9652419Sjulian * | struct ng_node | 9752419Sjulian * +----------------+ 9852419Sjulian */ 9952419Sjulian 10052419Sjulian/* Netgraph node methods */ 10152752Sjulianstatic ng_constructor_t ngs_constructor; 10252752Sjulianstatic ng_rcvmsg_t ngs_rcvmsg; 10352752Sjulianstatic ng_shutdown_t ngs_rmnode; 10452752Sjulianstatic ng_newhook_t ngs_newhook; 10552752Sjulianstatic ng_rcvdata_t ngs_rcvdata; 10652885Sjulianstatic ng_disconnect_t ngs_disconnect; 10752419Sjulian 10852419Sjulian/* Internal methods */ 10952419Sjulianstatic int ng_attach_data(struct socket *so); 11052419Sjulianstatic int ng_attach_cntl(struct socket *so); 11152419Sjulianstatic int ng_attach_common(struct socket *so, int type); 11252419Sjulianstatic void ng_detach_common(struct ngpcb *pcbp, int type); 11352419Sjulian/*static int ng_internalize(struct mbuf *m, struct proc *p); */ 11452419Sjulian 11552419Sjulianstatic int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp); 11652419Sjulianstatic int ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp); 11752419Sjulianstatic int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); 11852419Sjulian 11952419Sjulianstatic int ngs_mod_event(module_t mod, int event, void *data); 12052419Sjulianstatic int ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, 12152419Sjulian struct sockaddr_ng *addr); 12252419Sjulian 12352419Sjulian/* Netgraph type descriptor */ 12452419Sjulianstatic struct ng_type typestruct = { 12552419Sjulian NG_VERSION, 12652419Sjulian NG_SOCKET_NODE_TYPE, 12752419Sjulian ngs_mod_event, 12852419Sjulian ngs_constructor, 12952419Sjulian ngs_rcvmsg, 13052419Sjulian ngs_rmnode, 13152419Sjulian ngs_newhook, 13252419Sjulian NULL, 13352419Sjulian NULL, 13452419Sjulian ngs_rcvdata, 13552419Sjulian ngs_rcvdata, 13652885Sjulian ngs_disconnect 13752419Sjulian}; 13852419SjulianNETGRAPH_INIT(socket, &typestruct); 13952419Sjulian 14052419Sjulian/* Buffer space */ 14152419Sjulianstatic u_long ngpdg_sendspace = 2 * 1024; /* really max datagram size */ 14252419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024; 14352419Sjulian 14452419Sjulian/* List of all sockets */ 14552419SjulianLIST_HEAD(, ngpcb) ngsocklist; 14652419Sjulian 14752419Sjulian#define sotongpcb(so) ((struct ngpcb *)so->so_pcb) 14852419Sjulian 14952419Sjulian/* If getting unexplained errors returned, set this to "Debugger("X"); */ 15052419Sjulian#ifndef TRAP_ERROR 15152419Sjulian#define TRAP_ERROR 15252419Sjulian#endif 15352419Sjulian 15452419Sjulian/*************************************************************** 15552419Sjulian Control sockets 15652419Sjulian***************************************************************/ 15752419Sjulian 15852419Sjulianstatic int 15952419Sjulianngc_attach(struct socket *so, int proto, struct proc *p) 16052419Sjulian{ 16152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 16252419Sjulian 16352419Sjulian if (pcbp != NULL) 16452419Sjulian return (EISCONN); 16552419Sjulian return (ng_attach_cntl(so)); 16652419Sjulian} 16752419Sjulian 16852419Sjulianstatic int 16952419Sjulianngc_detach(struct socket *so) 17052419Sjulian{ 17152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 17252419Sjulian 17352419Sjulian if (pcbp == NULL) 17452419Sjulian return (EINVAL); 17552419Sjulian ng_detach_common(pcbp, NG_CONTROL); 17652419Sjulian return (0); 17752419Sjulian} 17852419Sjulian 17952419Sjulianstatic int 18052419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 18152419Sjulian struct mbuf *control, struct proc *p) 18252419Sjulian{ 18352419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 18452419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 18552419Sjulian struct ng_mesg *resp; 18652419Sjulian struct mbuf *m0; 18752419Sjulian char *msg, *path = NULL; 18852419Sjulian int len, error = 0; 18952419Sjulian 19052419Sjulian if (pcbp == NULL) { 19152419Sjulian error = EINVAL; 19252419Sjulian goto release; 19352419Sjulian } 19452419Sjulian#ifdef NOTYET 19552419Sjulian if (control && (error = ng_internalize(control, p))) { 19652419Sjulian if (pcbp->sockdata == NULL) { 19752419Sjulian error = ENOTCONN; 19852419Sjulian goto release; 19952419Sjulian } 20052419Sjulian } 20152419Sjulian#else /* NOTYET */ 20252419Sjulian if (control) { 20352419Sjulian error = EINVAL; 20452419Sjulian goto release; 20552419Sjulian } 20652419Sjulian#endif /* NOTYET */ 20752419Sjulian 20852419Sjulian /* Require destination as there may be >= 1 hooks on this node */ 20952419Sjulian if (addr == NULL) { 21052419Sjulian error = EDESTADDRREQ; 21152419Sjulian goto release; 21252419Sjulian } 21352419Sjulian 21452419Sjulian /* Allocate an expendable buffer for the path, chop off 21552419Sjulian * the sockaddr header, and make sure it's NUL terminated */ 21652419Sjulian len = sap->sg_len - 2; 21752419Sjulian MALLOC(path, char *, len + 1, M_NETGRAPH, M_WAITOK); 21852419Sjulian if (path == NULL) { 21952419Sjulian error = ENOMEM; 22052419Sjulian goto release; 22152419Sjulian } 22252419Sjulian bcopy(sap->sg_data, path, len); 22352419Sjulian path[len] = '\0'; 22452419Sjulian 22552419Sjulian /* Move the actual message out of mbufs into a linear buffer. 22652419Sjulian * Start by adding up the size of the data. (could use mh_len?) */ 22752419Sjulian for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next) 22852419Sjulian len += m0->m_len; 22952419Sjulian 23052419Sjulian /* Move the data into a linear buffer as well. Messages are not 23152419Sjulian * delivered in mbufs. */ 23252419Sjulian MALLOC(msg, char *, len + 1, M_NETGRAPH, M_WAITOK); 23352419Sjulian if (msg == NULL) { 23452419Sjulian error = ENOMEM; 23552419Sjulian goto release; 23652419Sjulian } 23752419Sjulian m_copydata(m, 0, len, msg); 23852419Sjulian 23952419Sjulian /* The callee will free the msg when done. The addr is our business. */ 24052419Sjulian error = ng_send_msg(pcbp->sockdata->node, 24152419Sjulian (struct ng_mesg *) msg, path, &resp); 24252419Sjulian 24352419Sjulian /* If the callee responded with a synchronous response, then put it 24452419Sjulian * back on the receive side of the socket; sap is source address. */ 24552419Sjulian if (error == 0 && resp != NULL) 24652419Sjulian error = ship_msg(pcbp, resp, sap); 24752419Sjulian 24852419Sjulianrelease: 24952419Sjulian if (path != NULL) 25052419Sjulian FREE(path, M_NETGRAPH); 25152419Sjulian if (control != NULL) 25252419Sjulian m_freem(control); 25352419Sjulian if (m != NULL) 25452419Sjulian m_freem(m); 25552419Sjulian return (error); 25652419Sjulian} 25752419Sjulian 25852419Sjulianstatic int 25952419Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 26052419Sjulian{ 26152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 26252419Sjulian 26352419Sjulian if (pcbp == 0) 26452419Sjulian return (EINVAL); 26552419Sjulian return (ng_bind(nam, pcbp)); 26652419Sjulian} 26752419Sjulian 26852419Sjulianstatic int 26952419Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 27052419Sjulian{ 27152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 27252419Sjulian 27352419Sjulian if (pcbp == 0) 27452419Sjulian return (EINVAL); 27552419Sjulian return (ng_connect_cntl(nam, pcbp)); 27652419Sjulian} 27752419Sjulian 27852419Sjulian/*************************************************************** 27952419Sjulian Data sockets 28052419Sjulian***************************************************************/ 28152419Sjulian 28252419Sjulianstatic int 28352419Sjulianngd_attach(struct socket *so, int proto, struct proc *p) 28452419Sjulian{ 28552419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 28652419Sjulian 28752419Sjulian if (pcbp != NULL) 28852419Sjulian return (EISCONN); 28952419Sjulian return (ng_attach_data(so)); 29052419Sjulian} 29152419Sjulian 29252419Sjulianstatic int 29352419Sjulianngd_detach(struct socket *so) 29452419Sjulian{ 29552419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 29652419Sjulian 29752419Sjulian if (pcbp == NULL) 29852419Sjulian return (EINVAL); 29952419Sjulian ng_detach_common(pcbp, NG_DATA); 30052419Sjulian return (0); 30152419Sjulian} 30252419Sjulian 30352419Sjulianstatic int 30452419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 30552419Sjulian struct mbuf *control, struct proc *p) 30652419Sjulian{ 30752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 30852419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 30952419Sjulian meta_p mp = NULL; 31052419Sjulian int len, error; 31153498Sjulian hook_p hook = NULL; 31253498Sjulian char hookname[NG_HOOKLEN + 1]; 31352419Sjulian 31452419Sjulian if ((pcbp == NULL) || (control != NULL)) { 31552419Sjulian error = EINVAL; 31652419Sjulian goto release; 31752419Sjulian } 31852419Sjulian if (pcbp->sockdata == NULL) { 31952419Sjulian error = ENOTCONN; 32052419Sjulian goto release; 32152419Sjulian } 32253498Sjulian /* 32353498Sjulian * If the user used any of these ways to not specify an address 32453498Sjulian * then handle specially. 32553498Sjulian */ 32653498Sjulian if ((sap == NULL) 32753498Sjulian || ((len = sap->sg_len) <= 2) 32853498Sjulian || (*sap->sg_data == '\0')) { 32953498Sjulian if (pcbp->sockdata->node->numhooks != 1) { 33053498Sjulian error = EDESTADDRREQ; 33153498Sjulian goto release; 33253498Sjulian } 33353498Sjulian /* 33453498Sjulian * if exactly one hook exists, just use it. 33553498Sjulian * Special case to allow write(2) to work on an ng_socket. 33653498Sjulian */ 33753498Sjulian hook = LIST_FIRST(&pcbp->sockdata->node->hooks); 33853498Sjulian } else { 33953498Sjulian if (len > NG_HOOKLEN) { 34053498Sjulian error = EINVAL; 34153498Sjulian goto release; 34253498Sjulian } 34352419Sjulian 34453498Sjulian /* 34553498Sjulian * chop off the sockaddr header, and make sure it's NUL 34653498Sjulian * terminated 34753498Sjulian */ 34853498Sjulian bcopy(sap->sg_data, hookname, len); 34953498Sjulian hookname[len] = '\0'; 35052419Sjulian 35153498Sjulian /* Find the correct hook from 'hookname' */ 35253498Sjulian LIST_FOREACH(hook, &pcbp->sockdata->node->hooks, hooks) { 35353498Sjulian if (strcmp(hookname, hook->name) == 0) 35453498Sjulian break; 35553498Sjulian } 35653498Sjulian if (hook == NULL) 35753498Sjulian error = EHOSTUNREACH; 35852419Sjulian } 35952419Sjulian 36052419Sjulian /* Send data (OK if hook is NULL) */ 36152419Sjulian NG_SEND_DATA(error, hook, m, mp); /* makes m NULL */ 36252419Sjulian 36352419Sjulianrelease: 36452419Sjulian if (hookname != NULL) 36552419Sjulian FREE(hookname, M_NETGRAPH); 36652419Sjulian if (control != NULL) 36752419Sjulian m_freem(control); 36852419Sjulian if (m != NULL) 36952419Sjulian m_freem(m); 37052419Sjulian return (error); 37152419Sjulian} 37252419Sjulian 37352419Sjulianstatic int 37452419Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 37552419Sjulian{ 37652419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 37752419Sjulian 37852419Sjulian if (pcbp == 0) 37952419Sjulian return (EINVAL); 38052419Sjulian return (ng_connect_data(nam, pcbp)); 38152419Sjulian} 38252419Sjulian 38352419Sjulian/* 38452419Sjulian * Used for both data and control sockets 38552419Sjulian */ 38652419Sjulianstatic int 38752419Sjulianng_setsockaddr(struct socket *so, struct sockaddr **addr) 38852419Sjulian{ 38953098Sbrian struct ngpcb *pcbp; 39053098Sbrian struct sockaddr_ng *sg; 39153098Sbrian int sg_len, namelen, s; 39252419Sjulian 39353098Sbrian /* Why isn't sg_data a `char[1]' ? :-( */ 39453098Sbrian sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1; 39553098Sbrian 39653098Sbrian s = splnet(); 39753098Sbrian pcbp = sotongpcb(so); 39853098Sbrian if (pcbp == 0) { 39953098Sbrian splx(s); 40052419Sjulian return (EINVAL); 40153098Sbrian } 40253098Sbrian 40353098Sbrian namelen = 0; /* silence compiler ! */ 40453098Sbrian 40553098Sbrian if (pcbp->sockdata->node->name != NULL) 40653098Sbrian sg_len += namelen = strlen(pcbp->sockdata->node->name); 40753098Sbrian 40853098Sbrian MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK); 40953098Sbrian bzero(sg, sg_len); 41053098Sbrian 41153098Sbrian if (pcbp->sockdata->node->name != NULL) 41253098Sbrian bcopy(pcbp->sockdata->node->name, sg->sg_data, namelen); 41353098Sbrian splx(s); 41453098Sbrian 41553098Sbrian sg->sg_len = sg_len; 41653098Sbrian sg->sg_family = AF_NETGRAPH; 41753098Sbrian *addr = (struct sockaddr *)sg; 41853098Sbrian 41952419Sjulian return (0); 42052419Sjulian} 42152419Sjulian 42252419Sjulian/* 42352419Sjulian * Attach a socket to it's protocol specific partner. 42452419Sjulian * For a control socket, actually create a netgraph node and attach 42552419Sjulian * to it as well. 42652419Sjulian */ 42752419Sjulian 42852419Sjulianstatic int 42952419Sjulianng_attach_cntl(struct socket *so) 43052419Sjulian{ 43152419Sjulian struct ngsock *privdata; 43252419Sjulian struct ngpcb *pcbp; 43352419Sjulian int error; 43452419Sjulian 43552419Sjulian /* Setup protocol control block */ 43652419Sjulian if ((error = ng_attach_common(so, NG_CONTROL)) != 0) 43752419Sjulian return (error); 43852419Sjulian pcbp = (struct ngpcb *) so->so_pcb; 43952419Sjulian 44052419Sjulian /* Allocate node private info */ 44152419Sjulian MALLOC(privdata, struct ngsock *, 44252419Sjulian sizeof(*privdata), M_NETGRAPH, M_WAITOK); 44352419Sjulian if (privdata == NULL) { 44452419Sjulian ng_detach_common(pcbp, NG_CONTROL); 44552419Sjulian return (ENOMEM); 44652419Sjulian } 44752419Sjulian bzero(privdata, sizeof(*privdata)); 44852419Sjulian 44952419Sjulian /* Make the generic node components */ 45052419Sjulian if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) { 45152419Sjulian FREE(privdata, M_NETGRAPH); 45252419Sjulian ng_detach_common(pcbp, NG_CONTROL); 45352419Sjulian return (error); 45452419Sjulian } 45552419Sjulian privdata->node->private = privdata; 45652419Sjulian 45752419Sjulian /* Link the pcb and the node private data */ 45852419Sjulian privdata->ctlsock = pcbp; 45952419Sjulian pcbp->sockdata = privdata; 46052419Sjulian privdata->refs++; 46152419Sjulian return (0); 46252419Sjulian} 46352419Sjulian 46452419Sjulianstatic int 46552419Sjulianng_attach_data(struct socket *so) 46652419Sjulian{ 46752419Sjulian return(ng_attach_common(so, NG_DATA)); 46852419Sjulian} 46952419Sjulian 47052419Sjulian/* 47152419Sjulian * Set up a socket protocol control block. 47252419Sjulian * This code is shared between control and data sockets. 47352419Sjulian */ 47452419Sjulianstatic int 47552419Sjulianng_attach_common(struct socket *so, int type) 47652419Sjulian{ 47752419Sjulian struct ngpcb *pcbp; 47852419Sjulian int error; 47952419Sjulian 48052419Sjulian /* Standard socket setup stuff */ 48152419Sjulian error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace); 48252419Sjulian if (error) 48352419Sjulian return (error); 48452419Sjulian 48552419Sjulian /* Allocate the pcb */ 48652419Sjulian MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK); 48752419Sjulian if (pcbp == NULL) 48852419Sjulian return (ENOMEM); 48952419Sjulian bzero(pcbp, sizeof(*pcbp)); 49052419Sjulian pcbp->type = type; 49152419Sjulian 49252419Sjulian /* Link the pcb and the socket */ 49352419Sjulian so->so_pcb = (caddr_t) pcbp; 49452419Sjulian pcbp->ng_socket = so; 49552419Sjulian 49652419Sjulian /* Add the socket to linked list */ 49752419Sjulian LIST_INSERT_HEAD(&ngsocklist, pcbp, socks); 49852419Sjulian return (0); 49952419Sjulian} 50052419Sjulian 50152419Sjulian/* 50252419Sjulian * Disassociate the socket from it's protocol specific 50352419Sjulian * partner. If it's attached to a node's private data structure, 50452419Sjulian * then unlink from that too. If we were the last socket attached to it, 50552419Sjulian * then shut down the entire node. Shared code for control and data sockets. 50652419Sjulian */ 50752419Sjulianstatic void 50852419Sjulianng_detach_common(struct ngpcb *pcbp, int which) 50952419Sjulian{ 51052419Sjulian struct ngsock *sockdata; 51152419Sjulian 51252419Sjulian if (pcbp->sockdata) { 51352419Sjulian sockdata = pcbp->sockdata; 51452419Sjulian pcbp->sockdata = NULL; 51552419Sjulian switch (which) { 51652419Sjulian case NG_CONTROL: 51752419Sjulian sockdata->ctlsock = NULL; 51852419Sjulian break; 51952419Sjulian case NG_DATA: 52052419Sjulian sockdata->datasock = NULL; 52152419Sjulian break; 52252419Sjulian default: 52352419Sjulian panic(__FUNCTION__); 52452419Sjulian } 52552419Sjulian if ((--sockdata->refs == 0) && (sockdata->node != NULL)) 52652419Sjulian ng_rmnode(sockdata->node); 52752419Sjulian } 52852419Sjulian pcbp->ng_socket->so_pcb = NULL; 52952419Sjulian pcbp->ng_socket = NULL; 53052419Sjulian LIST_REMOVE(pcbp, socks); 53152419Sjulian FREE(pcbp, M_PCB); 53252419Sjulian} 53352419Sjulian 53452419Sjulian#ifdef NOTYET 53552419Sjulian/* 53652419Sjulian * File descriptors can be passed into a AF_NETGRAPH socket. 53752419Sjulian * Note, that file descriptors cannot be passed OUT. 53852419Sjulian * Only character device descriptors are accepted. 53952419Sjulian * Character devices are useful to connect a graph to a device, 54052419Sjulian * which after all is the purpose of this whole system. 54152419Sjulian */ 54252419Sjulianstatic int 54352419Sjulianng_internalize(struct mbuf *control, struct proc *p) 54452419Sjulian{ 54552419Sjulian struct filedesc *fdp = p->p_fd; 54652419Sjulian struct cmsghdr *cm = mtod(control, struct cmsghdr *); 54752419Sjulian struct file *fp; 54852419Sjulian struct vnode *vn; 54952419Sjulian int oldfds; 55052419Sjulian int fd; 55152419Sjulian 55252419Sjulian if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 55352419Sjulian cm->cmsg_len != control->m_len) { 55452419Sjulian TRAP_ERROR; 55552419Sjulian return (EINVAL); 55652419Sjulian } 55752419Sjulian 55852419Sjulian /* Check there is only one FD. XXX what would more than one signify? */ 55952419Sjulian oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int); 56052419Sjulian if (oldfds != 1) { 56152419Sjulian TRAP_ERROR; 56252419Sjulian return (EINVAL); 56352419Sjulian } 56452419Sjulian 56552419Sjulian /* Check that the FD given is legit. and change it to a pointer to a 56652419Sjulian * struct file. */ 56752419Sjulian fd = *(int *) (cm + 1); 56852419Sjulian if ((unsigned) fd >= fdp->fd_nfiles 56952419Sjulian || (fp = fdp->fd_ofiles[fd]) == NULL) { 57052419Sjulian return (EBADF); 57152419Sjulian } 57252419Sjulian 57352419Sjulian /* Depending on what kind of resource it is, act differently. For 57452419Sjulian * devices, we treat it as a file. For a AF_NETGRAPH socket, 57552419Sjulian * shortcut straight to the node. */ 57652419Sjulian switch (fp->f_type) { 57752419Sjulian case DTYPE_VNODE: 57852419Sjulian vn = (struct vnode *) fp->f_data; 57952419Sjulian if (vn && (vn->v_type == VCHR)) { 58052419Sjulian /* for a VCHR, actually reference the FILE */ 58152419Sjulian fp->f_count++; 58252419Sjulian /* XXX then what :) */ 58352419Sjulian /* how to pass on to other modules? */ 58452419Sjulian } else { 58552419Sjulian TRAP_ERROR; 58652419Sjulian return (EINVAL); 58752419Sjulian } 58852419Sjulian break; 58952419Sjulian default: 59052419Sjulian TRAP_ERROR; 59152419Sjulian return (EINVAL); 59252419Sjulian } 59352419Sjulian return (0); 59452419Sjulian} 59552419Sjulian#endif /* NOTYET */ 59652419Sjulian 59752419Sjulian/* 59852419Sjulian * Connect the data socket to a named control socket node. 59952419Sjulian */ 60052419Sjulianstatic int 60152419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) 60252419Sjulian{ 60352419Sjulian struct sockaddr_ng *sap; 60452419Sjulian node_p farnode; 60552419Sjulian struct ngsock *sockdata; 60652419Sjulian int error; 60752419Sjulian 60852419Sjulian /* If we are already connected, don't do it again */ 60952419Sjulian if (pcbp->sockdata != NULL) 61052419Sjulian return (EISCONN); 61152419Sjulian 61252419Sjulian /* Find the target (victim) and check it doesn't already have a data 61352419Sjulian * socket. Also check it is a 'socket' type node. */ 61452419Sjulian sap = (struct sockaddr_ng *) nam; 61552419Sjulian if ((error = ng_path2node(NULL, sap->sg_data, &farnode, NULL))) 61652419Sjulian return (error); 61752419Sjulian 61852419Sjulian if (strcmp(farnode->type->name, NG_SOCKET_NODE_TYPE) != 0) 61952419Sjulian return (EINVAL); 62052419Sjulian sockdata = farnode->private; 62152419Sjulian if (sockdata->datasock != NULL) 62252419Sjulian return (EADDRINUSE); 62352419Sjulian 62452419Sjulian /* Link the PCB and the private data struct. and note the extra 62552419Sjulian * reference */ 62652419Sjulian sockdata->datasock = pcbp; 62752419Sjulian pcbp->sockdata = sockdata; 62852419Sjulian sockdata->refs++; 62952419Sjulian return (0); 63052419Sjulian} 63152419Sjulian 63252419Sjulian/* 63352419Sjulian * Connect the existing control socket node to a named node:hook. 63452419Sjulian * The hook we use on this end is the same name as the remote node name. 63552419Sjulian */ 63652419Sjulianstatic int 63752419Sjulianng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp) 63852419Sjulian{ 63952419Sjulian struct ngsock *const sockdata = pcbp->sockdata; 64052419Sjulian struct sockaddr_ng *sap; 64152419Sjulian char *node, *hook; 64252419Sjulian node_p farnode; 64352419Sjulian int rtn, error; 64452419Sjulian 64552419Sjulian sap = (struct sockaddr_ng *) nam; 64652419Sjulian rtn = ng_path_parse(sap->sg_data, &node, NULL, &hook); 64752419Sjulian if (rtn < 0 || node == NULL || hook == NULL) { 64852419Sjulian TRAP_ERROR; 64952419Sjulian return (EINVAL); 65052419Sjulian } 65152419Sjulian farnode = ng_findname(sockdata->node, node); 65252419Sjulian if (farnode == NULL) { 65352419Sjulian TRAP_ERROR; 65452419Sjulian return (EADDRNOTAVAIL); 65552419Sjulian } 65652419Sjulian 65752419Sjulian /* Connect, using a hook name the same as the far node name. */ 65852419Sjulian error = ng_con_nodes(sockdata->node, node, farnode, hook); 65952419Sjulian return error; 66052419Sjulian} 66152419Sjulian 66252419Sjulian/* 66352419Sjulian * Binding a socket means giving the corresponding node a name 66452419Sjulian */ 66552419Sjulianstatic int 66652419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp) 66752419Sjulian{ 66852419Sjulian struct ngsock *const sockdata = pcbp->sockdata; 66952419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; 67052419Sjulian 67152419Sjulian if (sockdata == NULL) { 67252419Sjulian TRAP_ERROR; 67352419Sjulian return (EINVAL); 67452419Sjulian } 67552419Sjulian if (sap->sg_len < 3 || sap->sg_data[sap->sg_len - 3] != '\0') { 67652419Sjulian TRAP_ERROR; 67752419Sjulian return (EINVAL); 67852419Sjulian } 67952419Sjulian return (ng_name_node(sockdata->node, sap->sg_data)); 68052419Sjulian} 68152419Sjulian 68252419Sjulian/* 68352419Sjulian * Take a message and pass it up to the control socket associated 68452419Sjulian * with the node. 68552419Sjulian */ 68652419Sjulianstatic int 68752419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr) 68852419Sjulian{ 68952419Sjulian struct socket *const so = pcbp->ng_socket; 69052419Sjulian struct mbuf *mdata; 69152419Sjulian int msglen; 69252419Sjulian 69352419Sjulian /* Copy the message itself into an mbuf chain */ 69452419Sjulian msglen = sizeof(struct ng_mesg) + msg->header.arglen; 69552419Sjulian mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL); 69652419Sjulian 69752419Sjulian /* Here we free the message, as we are the end of the line. 69852419Sjulian * We need to do that regardless of whether we got mbufs. */ 69952419Sjulian FREE(msg, M_NETGRAPH); 70052419Sjulian 70152419Sjulian if (mdata == NULL) { 70252419Sjulian TRAP_ERROR; 70352419Sjulian return (ENOBUFS); 70452419Sjulian } 70552419Sjulian 70652419Sjulian /* Send it up to the socket */ 70752419Sjulian if (sbappendaddr(&so->so_rcv, 70852419Sjulian (struct sockaddr *) addr, mdata, NULL) == 0) { 70952419Sjulian TRAP_ERROR; 71052419Sjulian m_freem(mdata); 71152419Sjulian return (ENOBUFS); 71252419Sjulian } 71352419Sjulian sorwakeup(so); 71452419Sjulian return (0); 71552419Sjulian} 71652419Sjulian 71752419Sjulian/* 71852419Sjulian * You can only create new nodes from the socket end of things. 71952419Sjulian */ 72052419Sjulianstatic int 72152419Sjulianngs_constructor(node_p *nodep) 72252419Sjulian{ 72352419Sjulian return (EINVAL); 72452419Sjulian} 72552419Sjulian 72652419Sjulian/* 72752419Sjulian * We allow any hook to be connected to the node. 72852419Sjulian * There is no per-hook private information though. 72952419Sjulian */ 73052419Sjulianstatic int 73152419Sjulianngs_newhook(node_p node, hook_p hook, const char *name) 73252419Sjulian{ 73352419Sjulian hook->private = node->private; 73452419Sjulian return (0); 73552419Sjulian} 73652419Sjulian 73752419Sjulian/* 73852419Sjulian * Incoming messages get passed up to the control socket. 73952885Sjulian * Unless they are for us specifically (socket_type) 74052419Sjulian */ 74152419Sjulianstatic int 74252419Sjulianngs_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 74352419Sjulian struct ng_mesg **resp) 74452419Sjulian{ 74552419Sjulian struct ngsock *const sockdata = node->private; 74652419Sjulian struct ngpcb *const pcbp = sockdata->ctlsock; 74752419Sjulian struct sockaddr_ng *addr; 74852419Sjulian int addrlen; 74952419Sjulian int error = 0; 75052419Sjulian 75152419Sjulian /* Only allow mesgs to be passed if we have the control socket. 75252419Sjulian * Data sockets can only support the generic messages. */ 75352419Sjulian if (pcbp == NULL) { 75452419Sjulian TRAP_ERROR; 75552419Sjulian return (EINVAL); 75652419Sjulian } 75752419Sjulian 75852885Sjulian if (msg->header.typecookie == NGM_SOCKET_COOKIE) { 75952885Sjulian switch (msg->header.cmd) { 76052885Sjulian case NGM_SOCK_CMD_NOLINGER: 76152885Sjulian sockdata->flags |= NGS_FLAG_NOLINGER; 76252885Sjulian break; 76352885Sjulian case NGM_SOCK_CMD_LINGER: 76452885Sjulian sockdata->flags &= ~NGS_FLAG_NOLINGER; 76552885Sjulian break; 76652885Sjulian default: 76752885Sjulian error = EINVAL; /* unknown command */ 76852885Sjulian } 76952885Sjulian /* Free the message and return */ 77052885Sjulian FREE(msg, M_NETGRAPH); 77152885Sjulian return(error); 77252885Sjulian 77352885Sjulian } 77452419Sjulian /* Get the return address into a sockaddr */ 77552419Sjulian if ((retaddr == NULL) || (*retaddr == '\0')) 77652419Sjulian retaddr = ""; 77752419Sjulian addrlen = strlen(retaddr); 77852419Sjulian MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH, M_NOWAIT); 77952419Sjulian if (addr == NULL) { 78052419Sjulian TRAP_ERROR; 78152419Sjulian return (ENOMEM); 78252419Sjulian } 78352419Sjulian addr->sg_len = addrlen + 3; 78452419Sjulian addr->sg_family = AF_NETGRAPH; 78552419Sjulian bcopy(retaddr, addr->sg_data, addrlen); 78652419Sjulian addr->sg_data[addrlen] = '\0'; 78752419Sjulian 78852419Sjulian /* Send it up */ 78952419Sjulian error = ship_msg(pcbp, msg, addr); 79052419Sjulian FREE(addr, M_NETGRAPH); 79152419Sjulian return (error); 79252419Sjulian} 79352419Sjulian 79452419Sjulian/* 79552419Sjulian * Receive data on a hook 79652419Sjulian */ 79752419Sjulianstatic int 79852419Sjulianngs_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 79952419Sjulian{ 80052419Sjulian struct ngsock *const sockdata = hook->node->private; 80152419Sjulian struct ngpcb *const pcbp = sockdata->datasock; 80252419Sjulian struct socket *so; 80352419Sjulian struct sockaddr_ng *addr; 80452419Sjulian char *addrbuf[NG_HOOKLEN + 1 + 4]; 80552419Sjulian int addrlen; 80652419Sjulian 80752419Sjulian /* If there is no data socket, black-hole it */ 80852419Sjulian if (pcbp == NULL) { 80952419Sjulian NG_FREE_DATA(m, meta); 81052419Sjulian return (0); 81152419Sjulian } 81252419Sjulian so = pcbp->ng_socket; 81352419Sjulian 81452419Sjulian /* Get the return address into a sockaddr. */ 81552419Sjulian addrlen = strlen(hook->name); /* <= NG_HOOKLEN */ 81652419Sjulian addr = (struct sockaddr_ng *) addrbuf; 81752419Sjulian addr->sg_len = addrlen + 3; 81852419Sjulian addr->sg_family = AF_NETGRAPH; 81952419Sjulian bcopy(hook->name, addr->sg_data, addrlen); 82052419Sjulian addr->sg_data[addrlen] = '\0'; 82152419Sjulian 82252419Sjulian /* We have no use for the meta data, free/clear it now. */ 82352419Sjulian NG_FREE_META(meta); 82452419Sjulian 82552419Sjulian /* Try to tell the socket which hook it came in on */ 82652419Sjulian if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) { 82752419Sjulian m_freem(m); 82852419Sjulian TRAP_ERROR; 82952419Sjulian return (ENOBUFS); 83052419Sjulian } 83152419Sjulian sorwakeup(so); 83252419Sjulian return (0); 83352419Sjulian} 83452419Sjulian 83552419Sjulian/* 83653498Sjulian * Hook disconnection 83752885Sjulian * 83852885Sjulian * For this type, removal of the last link destroys the node 83952885Sjulian * if the NOLINGER flag is set. 84052885Sjulian */ 84152885Sjulianstatic int 84252885Sjulianngs_disconnect(hook_p hook) 84352885Sjulian{ 84452885Sjulian struct ngsock *const sockdata = hook->node->private; 84552885Sjulian 84652885Sjulian if ((sockdata->flags & NGS_FLAG_NOLINGER ) 84752885Sjulian && (hook->node->numhooks == 0)) { 84852885Sjulian ng_rmnode(hook->node); 84952885Sjulian } 85052885Sjulian return (0); 85152885Sjulian} 85252885Sjulian 85352885Sjulian/* 85452419Sjulian * Do local shutdown processing. 85552419Sjulian * In this case, that involves making sure the socket 85652419Sjulian * knows we should be shutting down. 85752419Sjulian */ 85852419Sjulianstatic int 85952419Sjulianngs_rmnode(node_p node) 86052419Sjulian{ 86152419Sjulian struct ngsock *const sockdata = node->private; 86252419Sjulian struct ngpcb *const dpcbp = sockdata->datasock; 86352419Sjulian struct ngpcb *const pcbp = sockdata->ctlsock; 86452419Sjulian 86552419Sjulian ng_cutlinks(node); 86652419Sjulian ng_unname(node); 86752419Sjulian 86852419Sjulian if (dpcbp != NULL) { 86952419Sjulian soisdisconnected(dpcbp->ng_socket); 87052419Sjulian dpcbp->sockdata = NULL; 87152419Sjulian sockdata->datasock = NULL; 87252419Sjulian sockdata->refs--; 87352419Sjulian } 87452419Sjulian if (pcbp != NULL) { 87552419Sjulian soisdisconnected(pcbp->ng_socket); 87652419Sjulian pcbp->sockdata = NULL; 87752419Sjulian sockdata->ctlsock = NULL; 87852419Sjulian sockdata->refs--; 87952419Sjulian } 88052419Sjulian node->private = NULL; 88152419Sjulian ng_unref(node); 88252419Sjulian FREE(sockdata, M_NETGRAPH); 88352419Sjulian return (0); 88452419Sjulian} 88552419Sjulian 88652419Sjulian/* 88752419Sjulian * Control and data socket type descriptors 88852419Sjulian */ 88952419Sjulian 89052419Sjulianstatic struct pr_usrreqs ngc_usrreqs = { 89152419Sjulian NULL, /* abort */ 89252419Sjulian pru_accept_notsupp, 89352419Sjulian ngc_attach, 89452419Sjulian ngc_bind, 89552419Sjulian ngc_connect, 89652419Sjulian pru_connect2_notsupp, 89752419Sjulian pru_control_notsupp, 89852419Sjulian ngc_detach, 89952419Sjulian NULL, /* disconnect */ 90052419Sjulian pru_listen_notsupp, 90152419Sjulian NULL, /* setpeeraddr */ 90252419Sjulian pru_rcvd_notsupp, 90352419Sjulian pru_rcvoob_notsupp, 90452419Sjulian ngc_send, 90552419Sjulian pru_sense_null, 90652419Sjulian NULL, /* shutdown */ 90752419Sjulian ng_setsockaddr, 90852419Sjulian sosend, 90952419Sjulian soreceive, 91052419Sjulian sopoll 91152419Sjulian}; 91252419Sjulian 91352419Sjulianstatic struct pr_usrreqs ngd_usrreqs = { 91452419Sjulian NULL, /* abort */ 91552419Sjulian pru_accept_notsupp, 91652419Sjulian ngd_attach, 91752419Sjulian NULL, /* bind */ 91852419Sjulian ngd_connect, 91952419Sjulian pru_connect2_notsupp, 92052419Sjulian pru_control_notsupp, 92152419Sjulian ngd_detach, 92252419Sjulian NULL, /* disconnect */ 92352419Sjulian pru_listen_notsupp, 92452419Sjulian NULL, /* setpeeraddr */ 92552419Sjulian pru_rcvd_notsupp, 92652419Sjulian pru_rcvoob_notsupp, 92752419Sjulian ngd_send, 92852419Sjulian pru_sense_null, 92952419Sjulian NULL, /* shutdown */ 93052419Sjulian ng_setsockaddr, 93152419Sjulian sosend, 93252419Sjulian soreceive, 93352419Sjulian sopoll 93452419Sjulian}; 93552419Sjulian 93652419Sjulian/* 93752419Sjulian * Definitions of protocols supported in the NETGRAPH domain. 93852419Sjulian */ 93952419Sjulian 94052419Sjulianextern struct domain ngdomain; /* stop compiler warnings */ 94152419Sjulian 94252419Sjulianstatic struct protosw ngsw[] = { 94352419Sjulian { 94452419Sjulian SOCK_DGRAM, 94552419Sjulian &ngdomain, 94652419Sjulian NG_CONTROL, 94752419Sjulian PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, 94852419Sjulian 0, 0, 0, 0, 94952419Sjulian NULL, 95052419Sjulian 0, 0, 0, 0, 95152419Sjulian &ngc_usrreqs 95252419Sjulian }, 95352419Sjulian { 95452419Sjulian SOCK_DGRAM, 95552419Sjulian &ngdomain, 95652419Sjulian NG_DATA, 95752419Sjulian PR_ATOMIC | PR_ADDR, 95852419Sjulian 0, 0, 0, 0, 95952419Sjulian NULL, 96052419Sjulian 0, 0, 0, 0, 96152419Sjulian &ngd_usrreqs 96252419Sjulian } 96352419Sjulian}; 96452419Sjulian 96552419Sjulianstruct domain ngdomain = { 96652419Sjulian AF_NETGRAPH, 96752419Sjulian "netgraph", 96852419Sjulian 0, 96952419Sjulian NULL, 97052419Sjulian NULL, 97152419Sjulian ngsw, 97252419Sjulian &ngsw[sizeof(ngsw) / sizeof(ngsw[0])], 97352419Sjulian 0, 97452419Sjulian NULL, 97552419Sjulian 0, 97652419Sjulian 0 97752419Sjulian}; 97852419Sjulian 97952419Sjulian/* 98052419Sjulian * Handle loading and unloading for this node type 98152419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition). 98252419Sjulian */ 98352419Sjulianstatic int 98452419Sjulianngs_mod_event(module_t mod, int event, void *data) 98552419Sjulian{ 98652419Sjulian int error = 0; 98752419Sjulian 98852419Sjulian switch (event) { 98952419Sjulian case MOD_LOAD: 99052419Sjulian /* Register protocol domain */ 99152419Sjulian net_add_domain(&ngdomain); 99252419Sjulian break; 99352419Sjulian case MOD_UNLOAD: 99452419Sjulian /* Insure there are no open netgraph sockets */ 99552419Sjulian if (!LIST_EMPTY(&ngsocklist)) { 99652419Sjulian error = EBUSY; 99752419Sjulian break; 99852419Sjulian } 99952419Sjulian 100052419Sjulian#ifdef NOTYET 100152419Sjulian /* Unregister protocol domain XXX can't do this yet.. */ 100252419Sjulian if ((error = net_rm_domain(&ngdomain)) != 0) 100352419Sjulian break; 100452419Sjulian#else 100552419Sjulian error = EBUSY; 100652419Sjulian#endif 100752419Sjulian break; 100852419Sjulian default: 100952419Sjulian error = EOPNOTSUPP; 101052419Sjulian break; 101152419Sjulian } 101252419Sjulian return (error); 101352419Sjulian} 101452419Sjulian 101552419SjulianSYSCTL_NODE(_net, AF_NETGRAPH, graph, CTLFLAG_RW, 0, "netgraph Family"); 101652419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, ""); 101752419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); 101852419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, ""); 101952419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); 102052419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, ""); 102152419Sjulian 1022