ng_socket.c revision 83366
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 83366 2001-09-12 08:38:13Z 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/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 */ 15160938SjakeLIST_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) 35853498Sjulian || ((len = sap->sg_len) <= 2) 35953498Sjulian || (*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: 55052419Sjulian panic(__FUNCTION__); 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{ 57283366Sjulian struct filedesc *fdp = td->td_proc->p_fd; 57352419Sjulian struct cmsghdr *cm = mtod(control, struct cmsghdr *); 57452419Sjulian struct file *fp; 57552419Sjulian struct vnode *vn; 57652419Sjulian int oldfds; 57752419Sjulian int fd; 57852419Sjulian 57952419Sjulian if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 58052419Sjulian cm->cmsg_len != control->m_len) { 58152419Sjulian TRAP_ERROR; 58252419Sjulian return (EINVAL); 58352419Sjulian } 58452419Sjulian 58552419Sjulian /* Check there is only one FD. XXX what would more than one signify? */ 58652419Sjulian oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int); 58752419Sjulian if (oldfds != 1) { 58852419Sjulian TRAP_ERROR; 58952419Sjulian return (EINVAL); 59052419Sjulian } 59152419Sjulian 59252419Sjulian /* Check that the FD given is legit. and change it to a pointer to a 59352419Sjulian * struct file. */ 59452419Sjulian fd = *(int *) (cm + 1); 59552419Sjulian if ((unsigned) fd >= fdp->fd_nfiles 59652419Sjulian || (fp = fdp->fd_ofiles[fd]) == NULL) { 59752419Sjulian return (EBADF); 59852419Sjulian } 59952419Sjulian 60052419Sjulian /* Depending on what kind of resource it is, act differently. For 60152419Sjulian * devices, we treat it as a file. For a AF_NETGRAPH socket, 60252419Sjulian * shortcut straight to the node. */ 60352419Sjulian switch (fp->f_type) { 60452419Sjulian case DTYPE_VNODE: 60552419Sjulian vn = (struct vnode *) fp->f_data; 60652419Sjulian if (vn && (vn->v_type == VCHR)) { 60752419Sjulian /* for a VCHR, actually reference the FILE */ 60852419Sjulian fp->f_count++; 60952419Sjulian /* XXX then what :) */ 61052419Sjulian /* how to pass on to other modules? */ 61152419Sjulian } else { 61252419Sjulian TRAP_ERROR; 61352419Sjulian return (EINVAL); 61452419Sjulian } 61552419Sjulian break; 61652419Sjulian default: 61752419Sjulian TRAP_ERROR; 61852419Sjulian return (EINVAL); 61952419Sjulian } 62052419Sjulian return (0); 62152419Sjulian} 62252419Sjulian#endif /* NOTYET */ 62352419Sjulian 62452419Sjulian/* 62552419Sjulian * Connect the data socket to a named control socket node. 62652419Sjulian */ 62752419Sjulianstatic int 62852419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) 62952419Sjulian{ 63052419Sjulian struct sockaddr_ng *sap; 63152419Sjulian node_p farnode; 63272053Sjulian struct ngsock *priv; 63352419Sjulian int error; 63470700Sjulian item_p item; 63552419Sjulian 63652419Sjulian /* If we are already connected, don't do it again */ 63752419Sjulian if (pcbp->sockdata != NULL) 63852419Sjulian return (EISCONN); 63952419Sjulian 64052419Sjulian /* Find the target (victim) and check it doesn't already have a data 64170700Sjulian * socket. Also check it is a 'socket' type node. 64270700Sjulian * Use ng_package_data() and address_path() to do this. 64370700Sjulian */ 64470700Sjulian 64552419Sjulian sap = (struct sockaddr_ng *) nam; 64670700Sjulian /* The item will hold the node reference */ 64770700Sjulian item = ng_package_data(NULL, NULL); 64870700Sjulian if (item == NULL) { 64970700Sjulian return (ENOMEM); 65070700Sjulian } 65170700Sjulian if ((error = ng_address_path(NULL, item, sap->sg_data, NULL))) 65270700Sjulian return (error); /* item is freed on failure */ 65352419Sjulian 65470700Sjulian /* 65570784Sjulian * Extract node from item and free item. Remember we now have 65670700Sjulian * a reference on the node. The item holds it for us. 65770700Sjulian * when we free the item we release the reference. 65870700Sjulian */ 65970700Sjulian farnode = item->el_dest; /* shortcut */ 66070784Sjulian if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) { 66170700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 66252419Sjulian return (EINVAL); 66370700Sjulian } 66472053Sjulian priv = NG_NODE_PRIVATE(farnode); 66572053Sjulian if (priv->datasock != NULL) { 66670700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 66752419Sjulian return (EADDRINUSE); 66870700Sjulian } 66952419Sjulian 67070700Sjulian /* 67170700Sjulian * Link the PCB and the private data struct. and note the extra 67270700Sjulian * reference. Drop the extra reference on the node. 67370700Sjulian */ 67472053Sjulian priv->datasock = pcbp; 67572053Sjulian pcbp->sockdata = priv; 67672053Sjulian priv->refs++; /* XXX possible race if it's being freed */ 67770700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 67852419Sjulian return (0); 67952419Sjulian} 68052419Sjulian 68152419Sjulian/* 68252419Sjulian * Binding a socket means giving the corresponding node a name 68352419Sjulian */ 68452419Sjulianstatic int 68552419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp) 68652419Sjulian{ 68772053Sjulian struct ngsock *const priv = pcbp->sockdata; 68852419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; 68952419Sjulian 69072053Sjulian if (priv == NULL) { 69152419Sjulian TRAP_ERROR; 69252419Sjulian return (EINVAL); 69352419Sjulian } 69469922Sjulian if ((sap->sg_len < 4) 69569922Sjulian || (sap->sg_len > (NG_NODELEN + 3)) 69669922Sjulian || (sap->sg_data[0] == '\0') 69769922Sjulian || (sap->sg_data[sap->sg_len - 3] != '\0')) { 69852419Sjulian TRAP_ERROR; 69952419Sjulian return (EINVAL); 70052419Sjulian } 70172053Sjulian return (ng_name_node(priv->node, sap->sg_data)); 70252419Sjulian} 70352419Sjulian 70452419Sjulian/* 70552419Sjulian * Take a message and pass it up to the control socket associated 70652419Sjulian * with the node. 70752419Sjulian */ 70852419Sjulianstatic int 70952419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr) 71052419Sjulian{ 71152419Sjulian struct socket *const so = pcbp->ng_socket; 71252419Sjulian struct mbuf *mdata; 71352419Sjulian int msglen; 71452419Sjulian 71552419Sjulian /* Copy the message itself into an mbuf chain */ 71652419Sjulian msglen = sizeof(struct ng_mesg) + msg->header.arglen; 71752419Sjulian mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL); 71852419Sjulian 71952419Sjulian /* Here we free the message, as we are the end of the line. 72052419Sjulian * We need to do that regardless of whether we got mbufs. */ 72170700Sjulian NG_FREE_MSG(msg); 72252419Sjulian 72352419Sjulian if (mdata == NULL) { 72452419Sjulian TRAP_ERROR; 72552419Sjulian return (ENOBUFS); 72652419Sjulian } 72752419Sjulian 72852419Sjulian /* Send it up to the socket */ 72952419Sjulian if (sbappendaddr(&so->so_rcv, 73052419Sjulian (struct sockaddr *) addr, mdata, NULL) == 0) { 73152419Sjulian TRAP_ERROR; 73252419Sjulian m_freem(mdata); 73352419Sjulian return (ENOBUFS); 73452419Sjulian } 73552419Sjulian sorwakeup(so); 73652419Sjulian return (0); 73752419Sjulian} 73852419Sjulian 73952419Sjulian/* 74052419Sjulian * You can only create new nodes from the socket end of things. 74152419Sjulian */ 74252419Sjulianstatic int 74370700Sjulianngs_constructor(node_p nodep) 74452419Sjulian{ 74552419Sjulian return (EINVAL); 74652419Sjulian} 74752419Sjulian 74852419Sjulian/* 74952419Sjulian * We allow any hook to be connected to the node. 75052419Sjulian * There is no per-hook private information though. 75152419Sjulian */ 75252419Sjulianstatic int 75352419Sjulianngs_newhook(node_p node, hook_p hook, const char *name) 75452419Sjulian{ 75570784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 75652419Sjulian return (0); 75752419Sjulian} 75852419Sjulian 75972053Sjulian/* 76072053Sjulian * if only one hook, allow read(2) and write(2) to work. 76172053Sjulian */ 76272053Sjulianstatic int 76372053Sjulianngs_connect(hook_p hook) 76472053Sjulian{ 76572053Sjulian node_p node = NG_HOOK_NODE(hook); 76672053Sjulian struct ngsock *priv = NG_NODE_PRIVATE(node); 76772053Sjulian 76872053Sjulian if ((priv->datasock) 76972053Sjulian && (priv->datasock->ng_socket)) { 77072053Sjulian if (NG_NODE_NUMHOOKS(node) == 1) { 77172053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 77272053Sjulian } else { 77372053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 77472053Sjulian } 77572053Sjulian } 77672053Sjulian return (0); 77772053Sjulian} 77872053Sjulian 77952419Sjulian/* 78052419Sjulian * Incoming messages get passed up to the control socket. 78152885Sjulian * Unless they are for us specifically (socket_type) 78252419Sjulian */ 78352419Sjulianstatic int 78470700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook) 78552419Sjulian{ 78672053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 78772053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 78852419Sjulian struct sockaddr_ng *addr; 78952419Sjulian int addrlen; 79052419Sjulian int error = 0; 79170700Sjulian struct ng_mesg *msg; 79270700Sjulian ng_ID_t retaddr = NGI_RETADDR(item); 79370700Sjulian char retabuf[32]; 79452419Sjulian 79570700Sjulian NGI_GET_MSG(item, msg); 79670700Sjulian NG_FREE_ITEM(item); /* we have all we need */ 79770700Sjulian 79852419Sjulian /* Only allow mesgs to be passed if we have the control socket. 79952419Sjulian * Data sockets can only support the generic messages. */ 80052419Sjulian if (pcbp == NULL) { 80152419Sjulian TRAP_ERROR; 80252419Sjulian return (EINVAL); 80352419Sjulian } 80470784Sjulian#ifdef TRACE_MESSAGES 80570784Sjulianprintf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n", 80670784Sjulianretaddr, 80770784Sjulianmsg->header.typecookie, 80870784Sjulianmsg->header.cmd, 80970784Sjulianmsg->header.cmdstr, 81070784Sjulianmsg->header.flags, 81170784Sjulianmsg->header.token); 81252419Sjulian 81370784Sjulian#endif 81470784Sjulian 81552885Sjulian if (msg->header.typecookie == NGM_SOCKET_COOKIE) { 81652885Sjulian switch (msg->header.cmd) { 81752885Sjulian case NGM_SOCK_CMD_NOLINGER: 81872053Sjulian priv->flags |= NGS_FLAG_NOLINGER; 81952885Sjulian break; 82052885Sjulian case NGM_SOCK_CMD_LINGER: 82172053Sjulian priv->flags &= ~NGS_FLAG_NOLINGER; 82252885Sjulian break; 82352885Sjulian default: 82452885Sjulian error = EINVAL; /* unknown command */ 82552885Sjulian } 82652885Sjulian /* Free the message and return */ 82770700Sjulian NG_FREE_MSG(msg); 82852885Sjulian return(error); 82952885Sjulian 83052885Sjulian } 83152419Sjulian /* Get the return address into a sockaddr */ 83270700Sjulian sprintf(retabuf,"[%x]:", retaddr); 83370700Sjulian addrlen = strlen(retabuf); 83470870Sjulian MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH_PATH, M_NOWAIT); 83552419Sjulian if (addr == NULL) { 83652419Sjulian TRAP_ERROR; 83752419Sjulian return (ENOMEM); 83852419Sjulian } 83952419Sjulian addr->sg_len = addrlen + 3; 84052419Sjulian addr->sg_family = AF_NETGRAPH; 84170700Sjulian bcopy(retabuf, addr->sg_data, addrlen); 84252419Sjulian addr->sg_data[addrlen] = '\0'; 84352419Sjulian 84452419Sjulian /* Send it up */ 84552419Sjulian error = ship_msg(pcbp, msg, addr); 84670870Sjulian FREE(addr, M_NETGRAPH_PATH); 84752419Sjulian return (error); 84852419Sjulian} 84952419Sjulian 85052419Sjulian/* 85152419Sjulian * Receive data on a hook 85252419Sjulian */ 85352419Sjulianstatic int 85470700Sjulianngs_rcvdata(hook_p hook, item_p item) 85552419Sjulian{ 85672053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 85772053Sjulian struct ngpcb *const pcbp = priv->datasock; 85852419Sjulian struct socket *so; 85952419Sjulian struct sockaddr_ng *addr; 86052419Sjulian char *addrbuf[NG_HOOKLEN + 1 + 4]; 86152419Sjulian int addrlen; 86270700Sjulian struct mbuf *m; 86352419Sjulian 86470700Sjulian NGI_GET_M(item, m); 86570700Sjulian NG_FREE_ITEM(item); 86652419Sjulian /* If there is no data socket, black-hole it */ 86752419Sjulian if (pcbp == NULL) { 86870700Sjulian NG_FREE_M(m); 86952419Sjulian return (0); 87052419Sjulian } 87152419Sjulian so = pcbp->ng_socket; 87252419Sjulian 87352419Sjulian /* Get the return address into a sockaddr. */ 87470784Sjulian addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKLEN */ 87552419Sjulian addr = (struct sockaddr_ng *) addrbuf; 87652419Sjulian addr->sg_len = addrlen + 3; 87752419Sjulian addr->sg_family = AF_NETGRAPH; 87870784Sjulian bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); 87952419Sjulian addr->sg_data[addrlen] = '\0'; 88052419Sjulian 88152419Sjulian /* Try to tell the socket which hook it came in on */ 88252419Sjulian if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) { 88352419Sjulian m_freem(m); 88452419Sjulian TRAP_ERROR; 88552419Sjulian return (ENOBUFS); 88652419Sjulian } 88752419Sjulian sorwakeup(so); 88852419Sjulian return (0); 88952419Sjulian} 89052419Sjulian 89152419Sjulian/* 89253498Sjulian * Hook disconnection 89352885Sjulian * 89452885Sjulian * For this type, removal of the last link destroys the node 89552885Sjulian * if the NOLINGER flag is set. 89652885Sjulian */ 89752885Sjulianstatic int 89852885Sjulianngs_disconnect(hook_p hook) 89952885Sjulian{ 90072053Sjulian node_p node = NG_HOOK_NODE(hook); 90172053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 90252885Sjulian 90372053Sjulian if ((priv->datasock) 90472053Sjulian && (priv->datasock->ng_socket)) { 90572053Sjulian if (NG_NODE_NUMHOOKS(node) == 1) { 90672053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 90772053Sjulian } else { 90872053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 90972053Sjulian } 91052885Sjulian } 91172053Sjulian 91272053Sjulian if ((priv->flags & NGS_FLAG_NOLINGER ) 91372053Sjulian && (NG_NODE_NUMHOOKS(node) == 0) 91472053Sjulian && (NG_NODE_IS_VALID(node))) { 91572053Sjulian ng_rmnode_self(node); 91672053Sjulian } 91752885Sjulian return (0); 91852885Sjulian} 91952885Sjulian 92052885Sjulian/* 92152419Sjulian * Do local shutdown processing. 92252419Sjulian * In this case, that involves making sure the socket 92352419Sjulian * knows we should be shutting down. 92452419Sjulian */ 92552419Sjulianstatic int 92670700Sjulianngs_shutdown(node_p node) 92752419Sjulian{ 92872053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 92972053Sjulian struct ngpcb *const dpcbp = priv->datasock; 93072053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 93152419Sjulian 93252419Sjulian if (dpcbp != NULL) { 93352419Sjulian soisdisconnected(dpcbp->ng_socket); 93452419Sjulian dpcbp->sockdata = NULL; 93572053Sjulian priv->datasock = NULL; 93672053Sjulian priv->refs--; 93752419Sjulian } 93852419Sjulian if (pcbp != NULL) { 93952419Sjulian soisdisconnected(pcbp->ng_socket); 94052419Sjulian pcbp->sockdata = NULL; 94172053Sjulian priv->ctlsock = NULL; 94272053Sjulian priv->refs--; 94352419Sjulian } 94470784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 94570784Sjulian NG_NODE_UNREF(node); 94672053Sjulian FREE(priv, M_NETGRAPH_SOCK); 94752419Sjulian return (0); 94852419Sjulian} 94952419Sjulian 95072055Sjulianstatic int 95172055Sjuliandummy_disconnect(struct socket *so) 95272055Sjulian{ 95372055Sjulian return (0); 95472055Sjulian} 95552419Sjulian/* 95652419Sjulian * Control and data socket type descriptors 95752419Sjulian */ 95852419Sjulian 95952419Sjulianstatic struct pr_usrreqs ngc_usrreqs = { 96052419Sjulian NULL, /* abort */ 96152419Sjulian pru_accept_notsupp, 96252419Sjulian ngc_attach, 96352419Sjulian ngc_bind, 96452419Sjulian ngc_connect, 96552419Sjulian pru_connect2_notsupp, 96652419Sjulian pru_control_notsupp, 96752419Sjulian ngc_detach, 96872055Sjulian dummy_disconnect, /* disconnect */ 96952419Sjulian pru_listen_notsupp, 97052419Sjulian NULL, /* setpeeraddr */ 97152419Sjulian pru_rcvd_notsupp, 97252419Sjulian pru_rcvoob_notsupp, 97352419Sjulian ngc_send, 97452419Sjulian pru_sense_null, 97552419Sjulian NULL, /* shutdown */ 97652419Sjulian ng_setsockaddr, 97752419Sjulian sosend, 97852419Sjulian soreceive, 97952419Sjulian sopoll 98052419Sjulian}; 98152419Sjulian 98252419Sjulianstatic struct pr_usrreqs ngd_usrreqs = { 98352419Sjulian NULL, /* abort */ 98452419Sjulian pru_accept_notsupp, 98552419Sjulian ngd_attach, 98652419Sjulian NULL, /* bind */ 98752419Sjulian ngd_connect, 98852419Sjulian pru_connect2_notsupp, 98952419Sjulian pru_control_notsupp, 99052419Sjulian ngd_detach, 99172055Sjulian dummy_disconnect, /* disconnect */ 99252419Sjulian pru_listen_notsupp, 99352419Sjulian NULL, /* setpeeraddr */ 99452419Sjulian pru_rcvd_notsupp, 99552419Sjulian pru_rcvoob_notsupp, 99652419Sjulian ngd_send, 99752419Sjulian pru_sense_null, 99852419Sjulian NULL, /* shutdown */ 99952419Sjulian ng_setsockaddr, 100052419Sjulian sosend, 100152419Sjulian soreceive, 100252419Sjulian sopoll 100352419Sjulian}; 100452419Sjulian 100552419Sjulian/* 100652419Sjulian * Definitions of protocols supported in the NETGRAPH domain. 100752419Sjulian */ 100852419Sjulian 100952419Sjulianextern struct domain ngdomain; /* stop compiler warnings */ 101052419Sjulian 101152419Sjulianstatic struct protosw ngsw[] = { 101252419Sjulian { 101370700Sjulian SOCK_DGRAM, /* protocol type */ 101470700Sjulian &ngdomain, /* backpointer to domain */ 101552419Sjulian NG_CONTROL, 101670700Sjulian PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, /* flags */ 101770700Sjulian 0, 0, 0, 0, /* input, output, ctlinput, ctloutput */ 101870700Sjulian NULL, /* ousrreq */ 101970700Sjulian 0, 0, 0, 0, /* init, fasttimeo, slowtimo, drain */ 102070700Sjulian &ngc_usrreqs, /* usrreq table (above) */ 102170700Sjulian /*{NULL}*/ /* pffh (protocol filter head?) */ 102252419Sjulian }, 102352419Sjulian { 102470700Sjulian SOCK_DGRAM, /* protocol type */ 102570700Sjulian &ngdomain, /* backpointer to domain */ 102652419Sjulian NG_DATA, 102770700Sjulian PR_ATOMIC | PR_ADDR, /* flags */ 102870700Sjulian 0, 0, 0, 0, /* input, output, ctlinput, ctloutput */ 102970700Sjulian NULL, /* ousrreq() */ 103070700Sjulian 0, 0, 0, 0, /* init, fasttimeo, slowtimo, drain */ 103170700Sjulian &ngd_usrreqs, /* usrreq table (above) */ 103270700Sjulian /*{NULL}*/ /* pffh (protocol filter head?) */ 103352419Sjulian } 103452419Sjulian}; 103552419Sjulian 103652419Sjulianstruct domain ngdomain = { 103752419Sjulian AF_NETGRAPH, 103852419Sjulian "netgraph", 103970700Sjulian NULL, /* init() */ 104070700Sjulian NULL, /* externalise() */ 104170700Sjulian NULL, /* dispose() */ 104270700Sjulian ngsw, /* protosw entry */ 104370700Sjulian &ngsw[sizeof(ngsw) / sizeof(ngsw[0])], /* Number of protosw entries */ 104470700Sjulian NULL, /* next domain in list */ 104570700Sjulian NULL, /* rtattach() */ 104670700Sjulian 0, /* arg to rtattach in bits */ 104770700Sjulian 0 /* maxrtkey */ 104852419Sjulian}; 104952419Sjulian 105052419Sjulian/* 105152419Sjulian * Handle loading and unloading for this node type 105252419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition). 105352419Sjulian */ 105452419Sjulianstatic int 105552419Sjulianngs_mod_event(module_t mod, int event, void *data) 105652419Sjulian{ 105752419Sjulian int error = 0; 105852419Sjulian 105952419Sjulian switch (event) { 106052419Sjulian case MOD_LOAD: 106152419Sjulian /* Register protocol domain */ 106252419Sjulian net_add_domain(&ngdomain); 106352419Sjulian break; 106452419Sjulian case MOD_UNLOAD: 106552419Sjulian /* Insure there are no open netgraph sockets */ 106652419Sjulian if (!LIST_EMPTY(&ngsocklist)) { 106752419Sjulian error = EBUSY; 106852419Sjulian break; 106952419Sjulian } 107052419Sjulian 107152419Sjulian#ifdef NOTYET 107270700Sjulian if ((LIST_EMPTY(&ngsocklist)) && (typestruct.refs == 0)) { 107352419Sjulian /* Unregister protocol domain XXX can't do this yet.. */ 107470700Sjulian if ((error = net_rm_domain(&ngdomain)) != 0) 107570700Sjulian break; 107670700Sjulian } else 107752419Sjulian#endif 107870700Sjulian error = EBUSY; 107952419Sjulian break; 108052419Sjulian default: 108152419Sjulian error = EOPNOTSUPP; 108252419Sjulian break; 108352419Sjulian } 108452419Sjulian return (error); 108552419Sjulian} 108652419Sjulian 108752419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, ""); 108852419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); 108952419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, ""); 109052419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); 109152419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, ""); 109252419Sjulian 1093