ng_socket.c revision 89306
152419Sjulian 252419Sjulian/* 352419Sjulian * ng_socket.c 452419Sjulian * 552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 652419Sjulian * All rights reserved. 770784Sjulian * 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. 1870784Sjulian * 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 * 3767506Sjulian * Author: Julian Elischer <julian@freebsd.org> 3852419Sjulian * 3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_socket.c 89306 2002-01-13 11:58:06Z alfred $ 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/domain.h> 5452419Sjulian#include <sys/errno.h> 5552419Sjulian#include <sys/kernel.h> 5652419Sjulian#include <sys/filedesc.h> 5752419Sjulian#include <sys/malloc.h> 5852419Sjulian#include <sys/queue.h> 5952419Sjulian#include <sys/mbuf.h> 6052419Sjulian#include <sys/protosw.h> 6152419Sjulian#include <sys/socket.h> 6252419Sjulian#include <sys/socketvar.h> 6352419Sjulian#include <sys/sysctl.h> 6452419Sjulian#ifdef NOTYET 6552419Sjulian#include <sys/vnode.h> 6652419Sjulian#endif 6752419Sjulian#include <netgraph/ng_message.h> 6852419Sjulian#include <netgraph/netgraph.h> 6952919Sjulian#include <netgraph/ng_socketvar.h> 7052419Sjulian#include <netgraph/ng_socket.h> 7152419Sjulian 7270870Sjulian#ifdef NG_SEPARATE_MALLOC 7370870SjulianMALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info "); 7470870SjulianMALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info "); 7570870Sjulian#else 7670870Sjulian#define M_NETGRAPH_PATH M_NETGRAPH 7770870Sjulian#define M_NETGRAPH_SOCK M_NETGRAPH 7870870Sjulian#endif 7970870Sjulian 8052419Sjulian/* 8152419Sjulian * It's Ascii-art time! 8252419Sjulian * +-------------+ +-------------+ 8352419Sjulian * |socket (ctl)| |socket (data)| 8452419Sjulian * +-------------+ +-------------+ 8552419Sjulian * ^ ^ 8652419Sjulian * | | 8752419Sjulian * v v 8852419Sjulian * +-----------+ +-----------+ 8952419Sjulian * |pcb (ctl)| |pcb (data)| 9052419Sjulian * +-----------+ +-----------+ 9152419Sjulian * ^ ^ 9252419Sjulian * | | 9352419Sjulian * v v 9452419Sjulian * +--------------------------+ 9552419Sjulian * | Socket type private | 9652419Sjulian * | data | 9752419Sjulian * +--------------------------+ 9852419Sjulian * ^ 9952419Sjulian * | 10052419Sjulian * v 10152419Sjulian * +----------------+ 10252419Sjulian * | struct ng_node | 10352419Sjulian * +----------------+ 10452419Sjulian */ 10552419Sjulian 10652419Sjulian/* Netgraph node methods */ 10752752Sjulianstatic ng_constructor_t ngs_constructor; 10852752Sjulianstatic ng_rcvmsg_t ngs_rcvmsg; 10970700Sjulianstatic ng_shutdown_t ngs_shutdown; 11052752Sjulianstatic ng_newhook_t ngs_newhook; 11172053Sjulianstatic ng_connect_t ngs_connect; 11252752Sjulianstatic ng_rcvdata_t ngs_rcvdata; 11352885Sjulianstatic ng_disconnect_t ngs_disconnect; 11452419Sjulian 11552419Sjulian/* Internal methods */ 11652419Sjulianstatic int ng_attach_data(struct socket *so); 11752419Sjulianstatic int ng_attach_cntl(struct socket *so); 11852419Sjulianstatic int ng_attach_common(struct socket *so, int type); 11952419Sjulianstatic void ng_detach_common(struct ngpcb *pcbp, int type); 12083366Sjulian/*static int ng_internalize(struct mbuf *m, struct thread *p); */ 12152419Sjulian 12252419Sjulianstatic int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp); 12352419Sjulianstatic int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); 12452419Sjulian 12552419Sjulianstatic int ngs_mod_event(module_t mod, int event, void *data); 12652419Sjulianstatic int ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, 12752419Sjulian struct sockaddr_ng *addr); 12852419Sjulian 12952419Sjulian/* Netgraph type descriptor */ 13052419Sjulianstatic struct ng_type typestruct = { 13170159Sjulian NG_ABI_VERSION, 13252419Sjulian NG_SOCKET_NODE_TYPE, 13352419Sjulian ngs_mod_event, 13452419Sjulian ngs_constructor, 13552419Sjulian ngs_rcvmsg, 13670700Sjulian ngs_shutdown, 13752419Sjulian ngs_newhook, 13852419Sjulian NULL, 13972053Sjulian ngs_connect, 14052419Sjulian ngs_rcvdata, 14153913Sarchie ngs_disconnect, 14253913Sarchie NULL 14352419Sjulian}; 14452419SjulianNETGRAPH_INIT(socket, &typestruct); 14552419Sjulian 14652419Sjulian/* Buffer space */ 14764512Sarchiestatic u_long ngpdg_sendspace = 20 * 1024; /* really max datagram size */ 14852419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024; 14952419Sjulian 15052419Sjulian/* List of all sockets */ 15189066Smsmithstatic LIST_HEAD(, ngpcb) ngsocklist; 15252419Sjulian 15353526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb) 15452419Sjulian 15552419Sjulian/* If getting unexplained errors returned, set this to "Debugger("X"); */ 15652419Sjulian#ifndef TRAP_ERROR 15752419Sjulian#define TRAP_ERROR 15852419Sjulian#endif 15952419Sjulian 16052419Sjulian/*************************************************************** 16152419Sjulian Control sockets 16252419Sjulian***************************************************************/ 16352419Sjulian 16452419Sjulianstatic int 16583366Sjulianngc_attach(struct socket *so, int proto, struct thread *td) 16652419Sjulian{ 16752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 16852419Sjulian 16983366Sjulian if (suser_td(td)) 17053530Sjulian return (EPERM); 17152419Sjulian if (pcbp != NULL) 17252419Sjulian return (EISCONN); 17352419Sjulian return (ng_attach_cntl(so)); 17452419Sjulian} 17552419Sjulian 17652419Sjulianstatic int 17752419Sjulianngc_detach(struct socket *so) 17852419Sjulian{ 17952419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 18052419Sjulian 18152419Sjulian if (pcbp == NULL) 18252419Sjulian return (EINVAL); 18352419Sjulian ng_detach_common(pcbp, NG_CONTROL); 18452419Sjulian return (0); 18552419Sjulian} 18652419Sjulian 18752419Sjulianstatic int 18852419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 18983366Sjulian struct mbuf *control, struct thread *td) 19052419Sjulian{ 19152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 19252419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 19370700Sjulian struct ng_mesg *msg; 19452419Sjulian struct mbuf *m0; 19570700Sjulian char *path = NULL; 19652419Sjulian int len, error = 0; 19752419Sjulian 19852419Sjulian if (pcbp == NULL) { 19952419Sjulian error = EINVAL; 20052419Sjulian goto release; 20152419Sjulian } 20252419Sjulian#ifdef NOTYET 20383366Sjulian if (control && (error = ng_internalize(control, td))) { 20452419Sjulian if (pcbp->sockdata == NULL) { 20552419Sjulian error = ENOTCONN; 20652419Sjulian goto release; 20752419Sjulian } 20852419Sjulian } 20952419Sjulian#else /* NOTYET */ 21052419Sjulian if (control) { 21152419Sjulian error = EINVAL; 21252419Sjulian goto release; 21352419Sjulian } 21452419Sjulian#endif /* NOTYET */ 21552419Sjulian 21652419Sjulian /* Require destination as there may be >= 1 hooks on this node */ 21752419Sjulian if (addr == NULL) { 21852419Sjulian error = EDESTADDRREQ; 21952419Sjulian goto release; 22052419Sjulian } 22152419Sjulian 22252419Sjulian /* Allocate an expendable buffer for the path, chop off 22352419Sjulian * the sockaddr header, and make sure it's NUL terminated */ 22452419Sjulian len = sap->sg_len - 2; 22570870Sjulian MALLOC(path, char *, len + 1, M_NETGRAPH_PATH, M_WAITOK); 22652419Sjulian if (path == NULL) { 22752419Sjulian error = ENOMEM; 22852419Sjulian goto release; 22952419Sjulian } 23052419Sjulian bcopy(sap->sg_data, path, len); 23152419Sjulian path[len] = '\0'; 23252419Sjulian 23352419Sjulian /* Move the actual message out of mbufs into a linear buffer. 23452419Sjulian * Start by adding up the size of the data. (could use mh_len?) */ 23552419Sjulian for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next) 23652419Sjulian len += m0->m_len; 23752419Sjulian 23852419Sjulian /* Move the data into a linear buffer as well. Messages are not 23952419Sjulian * delivered in mbufs. */ 24070700Sjulian MALLOC(msg, struct ng_mesg *, len + 1, M_NETGRAPH_MSG, M_WAITOK); 24152419Sjulian if (msg == NULL) { 24252419Sjulian error = ENOMEM; 24352419Sjulian goto release; 24452419Sjulian } 24570700Sjulian m_copydata(m, 0, len, (char *)msg); 24652419Sjulian 24770784Sjulian#ifdef TRACE_MESSAGES 24870784Sjulian do { 24970784Sjulian item_p item; 25070784Sjulian if ((item = ng_package_msg(msg)) == NULL) { 25170784Sjulian (msg) = NULL; 25270784Sjulian (error) = ENOMEM; 25370784Sjulianprintf("err=%d\n",error); 25470784Sjulian break; 25570784Sjulian } 25670784Sjulian if (((error) = ng_address_path((pcbp->sockdata->node), (item), 25770784Sjulian (path), (NULL))) == 0) { 25870784Sjulianprintf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n", 25970784Sjulianitem->el_dest->nd_ID, 26070784Sjulianmsg->header.typecookie, 26170784Sjulianmsg->header.cmd, 26270784Sjulianmsg->header.cmdstr, 26370784Sjulianmsg->header.flags, 26470784Sjulianmsg->header.token, 26570784Sjulianitem->el_dest->nd_type->name); 26670784Sjulian SAVE_LINE(item); 26770784Sjulian (error) = ng_snd_item((item), 0); 26870784Sjulian } 26970784Sjulianelse { 27070784Sjulianprintf("errx=%d\n",error); 27170784Sjulian} 27270784Sjulian (msg) = NULL; 27370784Sjulian } while (0); 27470784Sjulian 27570784Sjulian#else 27670700Sjulian /* The callee will free the msg when done. The path is our business. */ 27770700Sjulian NG_SEND_MSG_PATH(error, pcbp->sockdata->node, msg, path, NULL); 27870784Sjulian#endif 27952419Sjulianrelease: 28052419Sjulian if (path != NULL) 28170870Sjulian FREE(path, M_NETGRAPH_PATH); 28252419Sjulian if (control != NULL) 28352419Sjulian m_freem(control); 28452419Sjulian if (m != NULL) 28552419Sjulian m_freem(m); 28652419Sjulian return (error); 28752419Sjulian} 28852419Sjulian 28952419Sjulianstatic int 29083366Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 29152419Sjulian{ 29252419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 29352419Sjulian 29452419Sjulian if (pcbp == 0) 29552419Sjulian return (EINVAL); 29652419Sjulian return (ng_bind(nam, pcbp)); 29752419Sjulian} 29852419Sjulian 29952419Sjulianstatic int 30083366Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 30152419Sjulian{ 30270784Sjulianprintf(" program tried to connect control socket to remote node\n "); 30370700Sjulian /* 30470784Sjulian * At this time refuse to do this.. it used to 30570700Sjulian * do something but it was undocumented and not used. 30670700Sjulian */ 30770700Sjulian return (EINVAL); 30852419Sjulian} 30952419Sjulian 31052419Sjulian/*************************************************************** 31152419Sjulian Data sockets 31252419Sjulian***************************************************************/ 31352419Sjulian 31452419Sjulianstatic int 31583366Sjulianngd_attach(struct socket *so, int proto, struct thread *td) 31652419Sjulian{ 31752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 31852419Sjulian 31952419Sjulian if (pcbp != NULL) 32052419Sjulian return (EISCONN); 32152419Sjulian return (ng_attach_data(so)); 32252419Sjulian} 32352419Sjulian 32452419Sjulianstatic int 32552419Sjulianngd_detach(struct socket *so) 32652419Sjulian{ 32752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 32852419Sjulian 32952419Sjulian if (pcbp == NULL) 33052419Sjulian return (EINVAL); 33152419Sjulian ng_detach_common(pcbp, NG_DATA); 33252419Sjulian return (0); 33352419Sjulian} 33452419Sjulian 33552419Sjulianstatic int 33652419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 33783366Sjulian struct mbuf *control, struct thread *td) 33852419Sjulian{ 33952419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 34052419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 34152419Sjulian int len, error; 34253498Sjulian hook_p hook = NULL; 34353498Sjulian char hookname[NG_HOOKLEN + 1]; 34452419Sjulian 34552419Sjulian if ((pcbp == NULL) || (control != NULL)) { 34652419Sjulian error = EINVAL; 34752419Sjulian goto release; 34852419Sjulian } 34952419Sjulian if (pcbp->sockdata == NULL) { 35052419Sjulian error = ENOTCONN; 35152419Sjulian goto release; 35252419Sjulian } 35353498Sjulian /* 35453498Sjulian * If the user used any of these ways to not specify an address 35553498Sjulian * then handle specially. 35653498Sjulian */ 35753498Sjulian if ((sap == NULL) 35884777Sarchie || ((len = sap->sg_len - 2) <= 0) 35984777Sarchie || (*sap->sg_data == '\0')) { 36070784Sjulian if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) { 36153498Sjulian error = EDESTADDRREQ; 36253498Sjulian goto release; 36353498Sjulian } 36453498Sjulian /* 36553498Sjulian * if exactly one hook exists, just use it. 36653498Sjulian * Special case to allow write(2) to work on an ng_socket. 36753498Sjulian */ 36870784Sjulian hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks); 36953498Sjulian } else { 37053498Sjulian if (len > NG_HOOKLEN) { 37153498Sjulian error = EINVAL; 37253498Sjulian goto release; 37353498Sjulian } 37452419Sjulian 37553498Sjulian /* 37653498Sjulian * chop off the sockaddr header, and make sure it's NUL 37753498Sjulian * terminated 37853498Sjulian */ 37953498Sjulian bcopy(sap->sg_data, hookname, len); 38053498Sjulian hookname[len] = '\0'; 38152419Sjulian 38253498Sjulian /* Find the correct hook from 'hookname' */ 38370784Sjulian LIST_FOREACH(hook, &pcbp->sockdata->node->nd_hooks, hk_hooks) { 38472053Sjulian if (strcmp(hookname, NG_HOOK_NAME(hook)) == 0) { 38553498Sjulian break; 38672053Sjulian } 38753498Sjulian } 38872053Sjulian if (hook == NULL) { 38953498Sjulian error = EHOSTUNREACH; 39072053Sjulian } 39152419Sjulian } 39252419Sjulian 39352419Sjulian /* Send data (OK if hook is NULL) */ 39469922Sjulian NG_SEND_DATA_ONLY(error, hook, m); /* makes m NULL */ 39552419Sjulian 39652419Sjulianrelease: 39752419Sjulian if (control != NULL) 39852419Sjulian m_freem(control); 39952419Sjulian if (m != NULL) 40052419Sjulian m_freem(m); 40152419Sjulian return (error); 40252419Sjulian} 40352419Sjulian 40452419Sjulianstatic int 40583366Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 40652419Sjulian{ 40752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 40852419Sjulian 40952419Sjulian if (pcbp == 0) 41052419Sjulian return (EINVAL); 41152419Sjulian return (ng_connect_data(nam, pcbp)); 41252419Sjulian} 41352419Sjulian 41452419Sjulian/* 41552419Sjulian * Used for both data and control sockets 41652419Sjulian */ 41752419Sjulianstatic int 41852419Sjulianng_setsockaddr(struct socket *so, struct sockaddr **addr) 41952419Sjulian{ 42053098Sbrian struct ngpcb *pcbp; 42153098Sbrian struct sockaddr_ng *sg; 42253098Sbrian int sg_len, namelen, s; 42352419Sjulian 42453098Sbrian /* Why isn't sg_data a `char[1]' ? :-( */ 42553098Sbrian sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1; 42653098Sbrian 42753098Sbrian s = splnet(); 42853098Sbrian pcbp = sotongpcb(so); 42969922Sjulian if ((pcbp == NULL) || (pcbp->sockdata == NULL)) { 43053098Sbrian splx(s); 43152419Sjulian return (EINVAL); 43253098Sbrian } 43353098Sbrian 43453098Sbrian namelen = 0; /* silence compiler ! */ 43570784Sjulian if ( NG_NODE_HAS_NAME(pcbp->sockdata->node)) 43670784Sjulian sg_len += namelen = strlen(NG_NODE_NAME(pcbp->sockdata->node)); 43753098Sbrian 43868876Sdwmalone MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK | M_ZERO); 43953098Sbrian 44070784Sjulian if (NG_NODE_HAS_NAME(pcbp->sockdata->node)) 44170784Sjulian bcopy(NG_NODE_NAME(pcbp->sockdata->node), sg->sg_data, namelen); 44253098Sbrian splx(s); 44353098Sbrian 44453098Sbrian sg->sg_len = sg_len; 44553098Sbrian sg->sg_family = AF_NETGRAPH; 44653098Sbrian *addr = (struct sockaddr *)sg; 44753098Sbrian 44852419Sjulian return (0); 44952419Sjulian} 45052419Sjulian 45152419Sjulian/* 45252419Sjulian * Attach a socket to it's protocol specific partner. 45352419Sjulian * For a control socket, actually create a netgraph node and attach 45452419Sjulian * to it as well. 45552419Sjulian */ 45652419Sjulian 45752419Sjulianstatic int 45852419Sjulianng_attach_cntl(struct socket *so) 45952419Sjulian{ 46052419Sjulian struct ngsock *privdata; 46152419Sjulian struct ngpcb *pcbp; 46252419Sjulian int error; 46352419Sjulian 46452419Sjulian /* Setup protocol control block */ 46552419Sjulian if ((error = ng_attach_common(so, NG_CONTROL)) != 0) 46652419Sjulian return (error); 46753526Sjulian pcbp = sotongpcb(so); 46852419Sjulian 46952419Sjulian /* Allocate node private info */ 47052419Sjulian MALLOC(privdata, struct ngsock *, 47170870Sjulian sizeof(*privdata), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO); 47252419Sjulian if (privdata == NULL) { 47352419Sjulian ng_detach_common(pcbp, NG_CONTROL); 47452419Sjulian return (ENOMEM); 47552419Sjulian } 47652419Sjulian 47752419Sjulian /* Make the generic node components */ 47852419Sjulian if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) { 47970870Sjulian FREE(privdata, M_NETGRAPH_SOCK); 48052419Sjulian ng_detach_common(pcbp, NG_CONTROL); 48152419Sjulian return (error); 48252419Sjulian } 48370784Sjulian NG_NODE_SET_PRIVATE(privdata->node, privdata); 48452419Sjulian 48552419Sjulian /* Link the pcb and the node private data */ 48652419Sjulian privdata->ctlsock = pcbp; 48752419Sjulian pcbp->sockdata = privdata; 48852419Sjulian privdata->refs++; 48952419Sjulian return (0); 49052419Sjulian} 49152419Sjulian 49252419Sjulianstatic int 49352419Sjulianng_attach_data(struct socket *so) 49452419Sjulian{ 49552419Sjulian return(ng_attach_common(so, NG_DATA)); 49652419Sjulian} 49752419Sjulian 49852419Sjulian/* 49952419Sjulian * Set up a socket protocol control block. 50052419Sjulian * This code is shared between control and data sockets. 50152419Sjulian */ 50252419Sjulianstatic int 50352419Sjulianng_attach_common(struct socket *so, int type) 50452419Sjulian{ 50552419Sjulian struct ngpcb *pcbp; 50652419Sjulian int error; 50752419Sjulian 50852419Sjulian /* Standard socket setup stuff */ 50952419Sjulian error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace); 51052419Sjulian if (error) 51152419Sjulian return (error); 51252419Sjulian 51352419Sjulian /* Allocate the pcb */ 51468876Sdwmalone MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK | M_ZERO); 51552419Sjulian if (pcbp == NULL) 51652419Sjulian return (ENOMEM); 51752419Sjulian pcbp->type = type; 51852419Sjulian 51952419Sjulian /* Link the pcb and the socket */ 52052419Sjulian so->so_pcb = (caddr_t) pcbp; 52152419Sjulian pcbp->ng_socket = so; 52252419Sjulian 52352419Sjulian /* Add the socket to linked list */ 52452419Sjulian LIST_INSERT_HEAD(&ngsocklist, pcbp, socks); 52552419Sjulian return (0); 52652419Sjulian} 52752419Sjulian 52852419Sjulian/* 52952419Sjulian * Disassociate the socket from it's protocol specific 53052419Sjulian * partner. If it's attached to a node's private data structure, 53152419Sjulian * then unlink from that too. If we were the last socket attached to it, 53252419Sjulian * then shut down the entire node. Shared code for control and data sockets. 53352419Sjulian */ 53452419Sjulianstatic void 53552419Sjulianng_detach_common(struct ngpcb *pcbp, int which) 53652419Sjulian{ 53772053Sjulian struct ngsock *priv; 53852419Sjulian 53952419Sjulian if (pcbp->sockdata) { 54072053Sjulian priv = pcbp->sockdata; 54152419Sjulian pcbp->sockdata = NULL; 54252419Sjulian switch (which) { 54352419Sjulian case NG_CONTROL: 54472053Sjulian priv->ctlsock = NULL; 54552419Sjulian break; 54652419Sjulian case NG_DATA: 54772053Sjulian priv->datasock = NULL; 54852419Sjulian break; 54952419Sjulian default: 55087599Sobrien panic(__func__); 55152419Sjulian } 55272053Sjulian if ((--priv->refs == 0) && (priv->node != NULL)) 55372053Sjulian ng_rmnode_self(priv->node); 55452419Sjulian } 55552419Sjulian pcbp->ng_socket->so_pcb = NULL; 55652419Sjulian pcbp->ng_socket = NULL; 55752419Sjulian LIST_REMOVE(pcbp, socks); 55852419Sjulian FREE(pcbp, M_PCB); 55952419Sjulian} 56052419Sjulian 56152419Sjulian#ifdef NOTYET 56252419Sjulian/* 56352419Sjulian * File descriptors can be passed into a AF_NETGRAPH socket. 56452419Sjulian * Note, that file descriptors cannot be passed OUT. 56552419Sjulian * Only character device descriptors are accepted. 56652419Sjulian * Character devices are useful to connect a graph to a device, 56752419Sjulian * which after all is the purpose of this whole system. 56852419Sjulian */ 56952419Sjulianstatic int 57083366Sjulianng_internalize(struct mbuf *control, struct thread *td) 57152419Sjulian{ 57252419Sjulian struct cmsghdr *cm = mtod(control, struct cmsghdr *); 57352419Sjulian struct file *fp; 57452419Sjulian struct vnode *vn; 57552419Sjulian int oldfds; 57652419Sjulian int fd; 57752419Sjulian 57852419Sjulian if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 57952419Sjulian cm->cmsg_len != control->m_len) { 58052419Sjulian TRAP_ERROR; 58152419Sjulian return (EINVAL); 58252419Sjulian } 58352419Sjulian 58452419Sjulian /* Check there is only one FD. XXX what would more than one signify? */ 58584472Sdwmalone oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int); 58652419Sjulian if (oldfds != 1) { 58752419Sjulian TRAP_ERROR; 58852419Sjulian return (EINVAL); 58952419Sjulian } 59052419Sjulian 59152419Sjulian /* Check that the FD given is legit. and change it to a pointer to a 59252419Sjulian * struct file. */ 59384472Sdwmalone fd = CMSG_DATA(cm); 59489306Salfred fp = ffind_hold(td, fd); 59589306Salfred if (fp == NULL) 59652419Sjulian return (EBADF); 59752419Sjulian 59852419Sjulian /* Depending on what kind of resource it is, act differently. For 59952419Sjulian * devices, we treat it as a file. For a AF_NETGRAPH socket, 60052419Sjulian * shortcut straight to the node. */ 60152419Sjulian switch (fp->f_type) { 60252419Sjulian case DTYPE_VNODE: 60352419Sjulian vn = (struct vnode *) fp->f_data; 60452419Sjulian if (vn && (vn->v_type == VCHR)) { 60552419Sjulian /* for a VCHR, actually reference the FILE */ 60652419Sjulian fp->f_count++; 60752419Sjulian /* XXX then what :) */ 60852419Sjulian /* how to pass on to other modules? */ 60952419Sjulian } else { 61089306Salfred fdrop(fp, td); 61152419Sjulian TRAP_ERROR; 61252419Sjulian return (EINVAL); 61352419Sjulian } 61452419Sjulian break; 61552419Sjulian default: 61689306Salfred fdrop(fp, td); 61752419Sjulian TRAP_ERROR; 61852419Sjulian return (EINVAL); 61952419Sjulian } 62089306Salfred fdrop(fp, td); 62152419Sjulian return (0); 62252419Sjulian} 62352419Sjulian#endif /* NOTYET */ 62452419Sjulian 62552419Sjulian/* 62652419Sjulian * Connect the data socket to a named control socket node. 62752419Sjulian */ 62852419Sjulianstatic int 62952419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) 63052419Sjulian{ 63152419Sjulian struct sockaddr_ng *sap; 63252419Sjulian node_p farnode; 63372053Sjulian struct ngsock *priv; 63452419Sjulian int error; 63570700Sjulian item_p item; 63652419Sjulian 63752419Sjulian /* If we are already connected, don't do it again */ 63852419Sjulian if (pcbp->sockdata != NULL) 63952419Sjulian return (EISCONN); 64052419Sjulian 64152419Sjulian /* Find the target (victim) and check it doesn't already have a data 64270700Sjulian * socket. Also check it is a 'socket' type node. 64370700Sjulian * Use ng_package_data() and address_path() to do this. 64470700Sjulian */ 64570700Sjulian 64652419Sjulian sap = (struct sockaddr_ng *) nam; 64770700Sjulian /* The item will hold the node reference */ 64870700Sjulian item = ng_package_data(NULL, NULL); 64970700Sjulian if (item == NULL) { 65070700Sjulian return (ENOMEM); 65170700Sjulian } 65270700Sjulian if ((error = ng_address_path(NULL, item, sap->sg_data, NULL))) 65370700Sjulian return (error); /* item is freed on failure */ 65452419Sjulian 65570700Sjulian /* 65670784Sjulian * Extract node from item and free item. Remember we now have 65770700Sjulian * a reference on the node. The item holds it for us. 65870700Sjulian * when we free the item we release the reference. 65970700Sjulian */ 66070700Sjulian farnode = item->el_dest; /* shortcut */ 66170784Sjulian if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) { 66270700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 66352419Sjulian return (EINVAL); 66470700Sjulian } 66572053Sjulian priv = NG_NODE_PRIVATE(farnode); 66672053Sjulian if (priv->datasock != NULL) { 66770700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 66852419Sjulian return (EADDRINUSE); 66970700Sjulian } 67052419Sjulian 67170700Sjulian /* 67270700Sjulian * Link the PCB and the private data struct. and note the extra 67370700Sjulian * reference. Drop the extra reference on the node. 67470700Sjulian */ 67572053Sjulian priv->datasock = pcbp; 67672053Sjulian pcbp->sockdata = priv; 67772053Sjulian priv->refs++; /* XXX possible race if it's being freed */ 67870700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 67952419Sjulian return (0); 68052419Sjulian} 68152419Sjulian 68252419Sjulian/* 68352419Sjulian * Binding a socket means giving the corresponding node a name 68452419Sjulian */ 68552419Sjulianstatic int 68652419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp) 68752419Sjulian{ 68872053Sjulian struct ngsock *const priv = pcbp->sockdata; 68952419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; 69052419Sjulian 69172053Sjulian if (priv == NULL) { 69252419Sjulian TRAP_ERROR; 69352419Sjulian return (EINVAL); 69452419Sjulian } 69569922Sjulian if ((sap->sg_len < 4) 69669922Sjulian || (sap->sg_len > (NG_NODELEN + 3)) 69769922Sjulian || (sap->sg_data[0] == '\0') 69869922Sjulian || (sap->sg_data[sap->sg_len - 3] != '\0')) { 69952419Sjulian TRAP_ERROR; 70052419Sjulian return (EINVAL); 70152419Sjulian } 70272053Sjulian return (ng_name_node(priv->node, sap->sg_data)); 70352419Sjulian} 70452419Sjulian 70552419Sjulian/* 70652419Sjulian * Take a message and pass it up to the control socket associated 70752419Sjulian * with the node. 70852419Sjulian */ 70952419Sjulianstatic int 71052419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr) 71152419Sjulian{ 71252419Sjulian struct socket *const so = pcbp->ng_socket; 71352419Sjulian struct mbuf *mdata; 71452419Sjulian int msglen; 71552419Sjulian 71652419Sjulian /* Copy the message itself into an mbuf chain */ 71752419Sjulian msglen = sizeof(struct ng_mesg) + msg->header.arglen; 71852419Sjulian mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL); 71952419Sjulian 72052419Sjulian /* Here we free the message, as we are the end of the line. 72152419Sjulian * We need to do that regardless of whether we got mbufs. */ 72270700Sjulian NG_FREE_MSG(msg); 72352419Sjulian 72452419Sjulian if (mdata == NULL) { 72552419Sjulian TRAP_ERROR; 72652419Sjulian return (ENOBUFS); 72752419Sjulian } 72852419Sjulian 72952419Sjulian /* Send it up to the socket */ 73052419Sjulian if (sbappendaddr(&so->so_rcv, 73152419Sjulian (struct sockaddr *) addr, mdata, NULL) == 0) { 73252419Sjulian TRAP_ERROR; 73352419Sjulian m_freem(mdata); 73452419Sjulian return (ENOBUFS); 73552419Sjulian } 73652419Sjulian sorwakeup(so); 73752419Sjulian return (0); 73852419Sjulian} 73952419Sjulian 74052419Sjulian/* 74152419Sjulian * You can only create new nodes from the socket end of things. 74252419Sjulian */ 74352419Sjulianstatic int 74470700Sjulianngs_constructor(node_p nodep) 74552419Sjulian{ 74652419Sjulian return (EINVAL); 74752419Sjulian} 74852419Sjulian 74952419Sjulian/* 75052419Sjulian * We allow any hook to be connected to the node. 75152419Sjulian * There is no per-hook private information though. 75252419Sjulian */ 75352419Sjulianstatic int 75452419Sjulianngs_newhook(node_p node, hook_p hook, const char *name) 75552419Sjulian{ 75670784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 75752419Sjulian return (0); 75852419Sjulian} 75952419Sjulian 76072053Sjulian/* 76172053Sjulian * if only one hook, allow read(2) and write(2) to work. 76272053Sjulian */ 76372053Sjulianstatic int 76472053Sjulianngs_connect(hook_p hook) 76572053Sjulian{ 76672053Sjulian node_p node = NG_HOOK_NODE(hook); 76772053Sjulian struct ngsock *priv = NG_NODE_PRIVATE(node); 76872053Sjulian 76972053Sjulian if ((priv->datasock) 77072053Sjulian && (priv->datasock->ng_socket)) { 77172053Sjulian if (NG_NODE_NUMHOOKS(node) == 1) { 77272053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 77372053Sjulian } else { 77472053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 77572053Sjulian } 77672053Sjulian } 77772053Sjulian return (0); 77872053Sjulian} 77972053Sjulian 78052419Sjulian/* 78152419Sjulian * Incoming messages get passed up to the control socket. 78252885Sjulian * Unless they are for us specifically (socket_type) 78352419Sjulian */ 78452419Sjulianstatic int 78570700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook) 78652419Sjulian{ 78772053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 78872053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 78952419Sjulian struct sockaddr_ng *addr; 79052419Sjulian int addrlen; 79152419Sjulian int error = 0; 79270700Sjulian struct ng_mesg *msg; 79370700Sjulian ng_ID_t retaddr = NGI_RETADDR(item); 79470700Sjulian char retabuf[32]; 79552419Sjulian 79670700Sjulian NGI_GET_MSG(item, msg); 79770700Sjulian NG_FREE_ITEM(item); /* we have all we need */ 79870700Sjulian 79952419Sjulian /* Only allow mesgs to be passed if we have the control socket. 80052419Sjulian * Data sockets can only support the generic messages. */ 80152419Sjulian if (pcbp == NULL) { 80252419Sjulian TRAP_ERROR; 80352419Sjulian return (EINVAL); 80452419Sjulian } 80570784Sjulian#ifdef TRACE_MESSAGES 80670784Sjulianprintf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n", 80770784Sjulianretaddr, 80870784Sjulianmsg->header.typecookie, 80970784Sjulianmsg->header.cmd, 81070784Sjulianmsg->header.cmdstr, 81170784Sjulianmsg->header.flags, 81270784Sjulianmsg->header.token); 81352419Sjulian 81470784Sjulian#endif 81570784Sjulian 81652885Sjulian if (msg->header.typecookie == NGM_SOCKET_COOKIE) { 81752885Sjulian switch (msg->header.cmd) { 81852885Sjulian case NGM_SOCK_CMD_NOLINGER: 81972053Sjulian priv->flags |= NGS_FLAG_NOLINGER; 82052885Sjulian break; 82152885Sjulian case NGM_SOCK_CMD_LINGER: 82272053Sjulian priv->flags &= ~NGS_FLAG_NOLINGER; 82352885Sjulian break; 82452885Sjulian default: 82552885Sjulian error = EINVAL; /* unknown command */ 82652885Sjulian } 82752885Sjulian /* Free the message and return */ 82870700Sjulian NG_FREE_MSG(msg); 82952885Sjulian return(error); 83052885Sjulian 83152885Sjulian } 83252419Sjulian /* Get the return address into a sockaddr */ 83370700Sjulian sprintf(retabuf,"[%x]:", retaddr); 83470700Sjulian addrlen = strlen(retabuf); 83570870Sjulian MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH_PATH, M_NOWAIT); 83652419Sjulian if (addr == NULL) { 83752419Sjulian TRAP_ERROR; 83852419Sjulian return (ENOMEM); 83952419Sjulian } 84052419Sjulian addr->sg_len = addrlen + 3; 84152419Sjulian addr->sg_family = AF_NETGRAPH; 84270700Sjulian bcopy(retabuf, addr->sg_data, addrlen); 84352419Sjulian addr->sg_data[addrlen] = '\0'; 84452419Sjulian 84552419Sjulian /* Send it up */ 84652419Sjulian error = ship_msg(pcbp, msg, addr); 84770870Sjulian FREE(addr, M_NETGRAPH_PATH); 84852419Sjulian return (error); 84952419Sjulian} 85052419Sjulian 85152419Sjulian/* 85252419Sjulian * Receive data on a hook 85352419Sjulian */ 85452419Sjulianstatic int 85570700Sjulianngs_rcvdata(hook_p hook, item_p item) 85652419Sjulian{ 85772053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 85872053Sjulian struct ngpcb *const pcbp = priv->datasock; 85952419Sjulian struct socket *so; 86052419Sjulian struct sockaddr_ng *addr; 86152419Sjulian char *addrbuf[NG_HOOKLEN + 1 + 4]; 86252419Sjulian int addrlen; 86370700Sjulian struct mbuf *m; 86452419Sjulian 86570700Sjulian NGI_GET_M(item, m); 86670700Sjulian NG_FREE_ITEM(item); 86752419Sjulian /* If there is no data socket, black-hole it */ 86852419Sjulian if (pcbp == NULL) { 86970700Sjulian NG_FREE_M(m); 87052419Sjulian return (0); 87152419Sjulian } 87252419Sjulian so = pcbp->ng_socket; 87352419Sjulian 87452419Sjulian /* Get the return address into a sockaddr. */ 87570784Sjulian addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKLEN */ 87652419Sjulian addr = (struct sockaddr_ng *) addrbuf; 87752419Sjulian addr->sg_len = addrlen + 3; 87852419Sjulian addr->sg_family = AF_NETGRAPH; 87970784Sjulian bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); 88052419Sjulian addr->sg_data[addrlen] = '\0'; 88152419Sjulian 88252419Sjulian /* Try to tell the socket which hook it came in on */ 88352419Sjulian if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) { 88452419Sjulian m_freem(m); 88552419Sjulian TRAP_ERROR; 88652419Sjulian return (ENOBUFS); 88752419Sjulian } 88852419Sjulian sorwakeup(so); 88952419Sjulian return (0); 89052419Sjulian} 89152419Sjulian 89252419Sjulian/* 89353498Sjulian * Hook disconnection 89452885Sjulian * 89552885Sjulian * For this type, removal of the last link destroys the node 89652885Sjulian * if the NOLINGER flag is set. 89752885Sjulian */ 89852885Sjulianstatic int 89952885Sjulianngs_disconnect(hook_p hook) 90052885Sjulian{ 90172053Sjulian node_p node = NG_HOOK_NODE(hook); 90272053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 90352885Sjulian 90472053Sjulian if ((priv->datasock) 90572053Sjulian && (priv->datasock->ng_socket)) { 90672053Sjulian if (NG_NODE_NUMHOOKS(node) == 1) { 90772053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 90872053Sjulian } else { 90972053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 91072053Sjulian } 91152885Sjulian } 91272053Sjulian 91372053Sjulian if ((priv->flags & NGS_FLAG_NOLINGER ) 91472053Sjulian && (NG_NODE_NUMHOOKS(node) == 0) 91572053Sjulian && (NG_NODE_IS_VALID(node))) { 91672053Sjulian ng_rmnode_self(node); 91772053Sjulian } 91852885Sjulian return (0); 91952885Sjulian} 92052885Sjulian 92152885Sjulian/* 92252419Sjulian * Do local shutdown processing. 92352419Sjulian * In this case, that involves making sure the socket 92452419Sjulian * knows we should be shutting down. 92552419Sjulian */ 92652419Sjulianstatic int 92770700Sjulianngs_shutdown(node_p node) 92852419Sjulian{ 92972053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 93072053Sjulian struct ngpcb *const dpcbp = priv->datasock; 93172053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 93252419Sjulian 93352419Sjulian if (dpcbp != NULL) { 93452419Sjulian soisdisconnected(dpcbp->ng_socket); 93552419Sjulian dpcbp->sockdata = NULL; 93672053Sjulian priv->datasock = NULL; 93772053Sjulian priv->refs--; 93852419Sjulian } 93952419Sjulian if (pcbp != NULL) { 94052419Sjulian soisdisconnected(pcbp->ng_socket); 94152419Sjulian pcbp->sockdata = NULL; 94272053Sjulian priv->ctlsock = NULL; 94372053Sjulian priv->refs--; 94452419Sjulian } 94570784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 94670784Sjulian NG_NODE_UNREF(node); 94772053Sjulian FREE(priv, M_NETGRAPH_SOCK); 94852419Sjulian return (0); 94952419Sjulian} 95052419Sjulian 95172055Sjulianstatic int 95272055Sjuliandummy_disconnect(struct socket *so) 95372055Sjulian{ 95472055Sjulian return (0); 95572055Sjulian} 95652419Sjulian/* 95752419Sjulian * Control and data socket type descriptors 95852419Sjulian */ 95952419Sjulian 96052419Sjulianstatic struct pr_usrreqs ngc_usrreqs = { 96152419Sjulian NULL, /* abort */ 96252419Sjulian pru_accept_notsupp, 96352419Sjulian ngc_attach, 96452419Sjulian ngc_bind, 96552419Sjulian ngc_connect, 96652419Sjulian pru_connect2_notsupp, 96752419Sjulian pru_control_notsupp, 96852419Sjulian ngc_detach, 96972055Sjulian dummy_disconnect, /* disconnect */ 97052419Sjulian pru_listen_notsupp, 97152419Sjulian NULL, /* setpeeraddr */ 97252419Sjulian pru_rcvd_notsupp, 97352419Sjulian pru_rcvoob_notsupp, 97452419Sjulian ngc_send, 97552419Sjulian pru_sense_null, 97652419Sjulian NULL, /* shutdown */ 97752419Sjulian ng_setsockaddr, 97852419Sjulian sosend, 97952419Sjulian soreceive, 98052419Sjulian sopoll 98152419Sjulian}; 98252419Sjulian 98352419Sjulianstatic struct pr_usrreqs ngd_usrreqs = { 98452419Sjulian NULL, /* abort */ 98552419Sjulian pru_accept_notsupp, 98652419Sjulian ngd_attach, 98752419Sjulian NULL, /* bind */ 98852419Sjulian ngd_connect, 98952419Sjulian pru_connect2_notsupp, 99052419Sjulian pru_control_notsupp, 99152419Sjulian ngd_detach, 99272055Sjulian dummy_disconnect, /* disconnect */ 99352419Sjulian pru_listen_notsupp, 99452419Sjulian NULL, /* setpeeraddr */ 99552419Sjulian pru_rcvd_notsupp, 99652419Sjulian pru_rcvoob_notsupp, 99752419Sjulian ngd_send, 99852419Sjulian pru_sense_null, 99952419Sjulian NULL, /* shutdown */ 100052419Sjulian ng_setsockaddr, 100152419Sjulian sosend, 100252419Sjulian soreceive, 100352419Sjulian sopoll 100452419Sjulian}; 100552419Sjulian 100652419Sjulian/* 100752419Sjulian * Definitions of protocols supported in the NETGRAPH domain. 100852419Sjulian */ 100952419Sjulian 101052419Sjulianextern struct domain ngdomain; /* stop compiler warnings */ 101152419Sjulian 101252419Sjulianstatic struct protosw ngsw[] = { 101352419Sjulian { 101470700Sjulian SOCK_DGRAM, /* protocol type */ 101570700Sjulian &ngdomain, /* backpointer to domain */ 101652419Sjulian NG_CONTROL, 101770700Sjulian PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, /* flags */ 101870700Sjulian 0, 0, 0, 0, /* input, output, ctlinput, ctloutput */ 101970700Sjulian NULL, /* ousrreq */ 102070700Sjulian 0, 0, 0, 0, /* init, fasttimeo, slowtimo, drain */ 102170700Sjulian &ngc_usrreqs, /* usrreq table (above) */ 102270700Sjulian /*{NULL}*/ /* pffh (protocol filter head?) */ 102352419Sjulian }, 102452419Sjulian { 102570700Sjulian SOCK_DGRAM, /* protocol type */ 102670700Sjulian &ngdomain, /* backpointer to domain */ 102752419Sjulian NG_DATA, 102870700Sjulian PR_ATOMIC | PR_ADDR, /* flags */ 102970700Sjulian 0, 0, 0, 0, /* input, output, ctlinput, ctloutput */ 103070700Sjulian NULL, /* ousrreq() */ 103170700Sjulian 0, 0, 0, 0, /* init, fasttimeo, slowtimo, drain */ 103270700Sjulian &ngd_usrreqs, /* usrreq table (above) */ 103370700Sjulian /*{NULL}*/ /* pffh (protocol filter head?) */ 103452419Sjulian } 103552419Sjulian}; 103652419Sjulian 103752419Sjulianstruct domain ngdomain = { 103852419Sjulian AF_NETGRAPH, 103952419Sjulian "netgraph", 104070700Sjulian NULL, /* init() */ 104170700Sjulian NULL, /* externalise() */ 104270700Sjulian NULL, /* dispose() */ 104370700Sjulian ngsw, /* protosw entry */ 104470700Sjulian &ngsw[sizeof(ngsw) / sizeof(ngsw[0])], /* Number of protosw entries */ 104570700Sjulian NULL, /* next domain in list */ 104670700Sjulian NULL, /* rtattach() */ 104770700Sjulian 0, /* arg to rtattach in bits */ 104870700Sjulian 0 /* maxrtkey */ 104952419Sjulian}; 105052419Sjulian 105152419Sjulian/* 105252419Sjulian * Handle loading and unloading for this node type 105352419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition). 105452419Sjulian */ 105552419Sjulianstatic int 105652419Sjulianngs_mod_event(module_t mod, int event, void *data) 105752419Sjulian{ 105852419Sjulian int error = 0; 105952419Sjulian 106052419Sjulian switch (event) { 106152419Sjulian case MOD_LOAD: 106252419Sjulian /* Register protocol domain */ 106352419Sjulian net_add_domain(&ngdomain); 106452419Sjulian break; 106552419Sjulian case MOD_UNLOAD: 106652419Sjulian /* Insure there are no open netgraph sockets */ 106752419Sjulian if (!LIST_EMPTY(&ngsocklist)) { 106852419Sjulian error = EBUSY; 106952419Sjulian break; 107052419Sjulian } 107152419Sjulian 107252419Sjulian#ifdef NOTYET 107370700Sjulian if ((LIST_EMPTY(&ngsocklist)) && (typestruct.refs == 0)) { 107452419Sjulian /* Unregister protocol domain XXX can't do this yet.. */ 107570700Sjulian if ((error = net_rm_domain(&ngdomain)) != 0) 107670700Sjulian break; 107770700Sjulian } else 107852419Sjulian#endif 107970700Sjulian error = EBUSY; 108052419Sjulian break; 108152419Sjulian default: 108252419Sjulian error = EOPNOTSUPP; 108352419Sjulian break; 108452419Sjulian } 108552419Sjulian return (error); 108652419Sjulian} 108752419Sjulian 108852419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, ""); 108952419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); 109052419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, ""); 109152419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); 109252419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, ""); 109352419Sjulian 1094