ng_socket.c revision 108533
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 108533 2003-01-01 18:49:04Z schweikh $ 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/domain.h> 5352419Sjulian#include <sys/errno.h> 5452419Sjulian#include <sys/kernel.h> 5595759Stanimura#include <sys/lock.h> 5652419Sjulian#include <sys/malloc.h> 5752419Sjulian#include <sys/mbuf.h> 5852419Sjulian#include <sys/protosw.h> 5995759Stanimura#include <sys/queue.h> 6095759Stanimura#include <sys/signalvar.h> 6152419Sjulian#include <sys/socket.h> 6252419Sjulian#include <sys/socketvar.h> 6395759Stanimura#include <sys/sx.h> 6452419Sjulian#include <sys/sysctl.h> 6595759Stanimura#include <sys/systm.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 7470870Sjulian#ifdef NG_SEPARATE_MALLOC 7570870SjulianMALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info "); 7670870SjulianMALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info "); 7770870Sjulian#else 7870870Sjulian#define M_NETGRAPH_PATH M_NETGRAPH 7970870Sjulian#define M_NETGRAPH_SOCK M_NETGRAPH 8070870Sjulian#endif 8170870Sjulian 8252419Sjulian/* 8352419Sjulian * It's Ascii-art time! 8452419Sjulian * +-------------+ +-------------+ 8552419Sjulian * |socket (ctl)| |socket (data)| 8652419Sjulian * +-------------+ +-------------+ 8752419Sjulian * ^ ^ 8852419Sjulian * | | 8952419Sjulian * v v 9052419Sjulian * +-----------+ +-----------+ 9152419Sjulian * |pcb (ctl)| |pcb (data)| 9252419Sjulian * +-----------+ +-----------+ 9352419Sjulian * ^ ^ 9452419Sjulian * | | 9552419Sjulian * v v 9652419Sjulian * +--------------------------+ 9752419Sjulian * | Socket type private | 9852419Sjulian * | data | 9952419Sjulian * +--------------------------+ 10052419Sjulian * ^ 10152419Sjulian * | 10252419Sjulian * v 10352419Sjulian * +----------------+ 10452419Sjulian * | struct ng_node | 10552419Sjulian * +----------------+ 10652419Sjulian */ 10752419Sjulian 10852419Sjulian/* Netgraph node methods */ 10952752Sjulianstatic ng_constructor_t ngs_constructor; 11052752Sjulianstatic ng_rcvmsg_t ngs_rcvmsg; 11170700Sjulianstatic ng_shutdown_t ngs_shutdown; 11252752Sjulianstatic ng_newhook_t ngs_newhook; 11372053Sjulianstatic ng_connect_t ngs_connect; 11452752Sjulianstatic ng_rcvdata_t ngs_rcvdata; 11552885Sjulianstatic ng_disconnect_t ngs_disconnect; 11652419Sjulian 11752419Sjulian/* Internal methods */ 11852419Sjulianstatic int ng_attach_data(struct socket *so); 11952419Sjulianstatic int ng_attach_cntl(struct socket *so); 12052419Sjulianstatic int ng_attach_common(struct socket *so, int type); 12152419Sjulianstatic void ng_detach_common(struct ngpcb *pcbp, int type); 12283366Sjulian/*static int ng_internalize(struct mbuf *m, struct thread *p); */ 12352419Sjulian 12452419Sjulianstatic int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp); 12552419Sjulianstatic int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); 12652419Sjulian 12752419Sjulianstatic int ngs_mod_event(module_t mod, int event, void *data); 12852419Sjulianstatic int ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, 12952419Sjulian struct sockaddr_ng *addr); 13052419Sjulian 13152419Sjulian/* Netgraph type descriptor */ 13252419Sjulianstatic struct ng_type typestruct = { 13370159Sjulian NG_ABI_VERSION, 13452419Sjulian NG_SOCKET_NODE_TYPE, 13552419Sjulian ngs_mod_event, 13652419Sjulian ngs_constructor, 13752419Sjulian ngs_rcvmsg, 13870700Sjulian ngs_shutdown, 13952419Sjulian ngs_newhook, 14052419Sjulian NULL, 14172053Sjulian ngs_connect, 14252419Sjulian ngs_rcvdata, 14353913Sarchie ngs_disconnect, 14453913Sarchie NULL 14552419Sjulian}; 14652419SjulianNETGRAPH_INIT(socket, &typestruct); 14752419Sjulian 14852419Sjulian/* Buffer space */ 14964512Sarchiestatic u_long ngpdg_sendspace = 20 * 1024; /* really max datagram size */ 15052419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024; 15152419Sjulian 15252419Sjulian/* List of all sockets */ 15389066Smsmithstatic LIST_HEAD(, ngpcb) ngsocklist; 15452419Sjulian 15553526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb) 15652419Sjulian 15752419Sjulian/* If getting unexplained errors returned, set this to "Debugger("X"); */ 15852419Sjulian#ifndef TRAP_ERROR 15952419Sjulian#define TRAP_ERROR 16052419Sjulian#endif 16152419Sjulian 16252419Sjulian/*************************************************************** 16352419Sjulian Control sockets 16452419Sjulian***************************************************************/ 16552419Sjulian 16652419Sjulianstatic int 16783366Sjulianngc_attach(struct socket *so, int proto, struct thread *td) 16852419Sjulian{ 16952419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 17052419Sjulian 17193593Sjhb if (suser(td)) 17253530Sjulian return (EPERM); 17352419Sjulian if (pcbp != NULL) 17452419Sjulian return (EISCONN); 17552419Sjulian return (ng_attach_cntl(so)); 17652419Sjulian} 17752419Sjulian 17852419Sjulianstatic int 17952419Sjulianngc_detach(struct socket *so) 18052419Sjulian{ 18152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 18252419Sjulian 18352419Sjulian if (pcbp == NULL) 18452419Sjulian return (EINVAL); 18552419Sjulian ng_detach_common(pcbp, NG_CONTROL); 18652419Sjulian return (0); 18752419Sjulian} 18852419Sjulian 18952419Sjulianstatic int 19052419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 19183366Sjulian struct mbuf *control, struct thread *td) 19252419Sjulian{ 19352419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 19452419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 19570700Sjulian struct ng_mesg *msg; 19652419Sjulian struct mbuf *m0; 19770700Sjulian char *path = NULL; 19852419Sjulian int len, error = 0; 19952419Sjulian 20052419Sjulian if (pcbp == NULL) { 20152419Sjulian error = EINVAL; 20252419Sjulian goto release; 20352419Sjulian } 20452419Sjulian#ifdef NOTYET 20583366Sjulian if (control && (error = ng_internalize(control, td))) { 20652419Sjulian if (pcbp->sockdata == NULL) { 20752419Sjulian error = ENOTCONN; 20852419Sjulian goto release; 20952419Sjulian } 21052419Sjulian } 21152419Sjulian#else /* NOTYET */ 21252419Sjulian if (control) { 21352419Sjulian error = EINVAL; 21452419Sjulian goto release; 21552419Sjulian } 21652419Sjulian#endif /* NOTYET */ 21752419Sjulian 21852419Sjulian /* Require destination as there may be >= 1 hooks on this node */ 21952419Sjulian if (addr == NULL) { 22052419Sjulian error = EDESTADDRREQ; 22152419Sjulian goto release; 22252419Sjulian } 22352419Sjulian 22452419Sjulian /* Allocate an expendable buffer for the path, chop off 22552419Sjulian * the sockaddr header, and make sure it's NUL terminated */ 22652419Sjulian len = sap->sg_len - 2; 22770870Sjulian MALLOC(path, char *, len + 1, M_NETGRAPH_PATH, M_WAITOK); 22852419Sjulian if (path == NULL) { 22952419Sjulian error = ENOMEM; 23052419Sjulian goto release; 23152419Sjulian } 23252419Sjulian bcopy(sap->sg_data, path, len); 23352419Sjulian path[len] = '\0'; 23452419Sjulian 23552419Sjulian /* Move the actual message out of mbufs into a linear buffer. 23652419Sjulian * Start by adding up the size of the data. (could use mh_len?) */ 23752419Sjulian for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next) 23852419Sjulian len += m0->m_len; 23952419Sjulian 24052419Sjulian /* Move the data into a linear buffer as well. Messages are not 24152419Sjulian * delivered in mbufs. */ 24270700Sjulian MALLOC(msg, struct ng_mesg *, len + 1, M_NETGRAPH_MSG, M_WAITOK); 24352419Sjulian if (msg == NULL) { 24452419Sjulian error = ENOMEM; 24552419Sjulian goto release; 24652419Sjulian } 24770700Sjulian m_copydata(m, 0, len, (char *)msg); 24852419Sjulian 24970784Sjulian#ifdef TRACE_MESSAGES 25070784Sjulian do { 25170784Sjulian item_p item; 25270784Sjulian if ((item = ng_package_msg(msg)) == NULL) { 25370784Sjulian (msg) = NULL; 25470784Sjulian (error) = ENOMEM; 25570784Sjulianprintf("err=%d\n",error); 25670784Sjulian break; 25770784Sjulian } 25870784Sjulian if (((error) = ng_address_path((pcbp->sockdata->node), (item), 25970784Sjulian (path), (NULL))) == 0) { 26070784Sjulianprintf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n", 26170784Sjulianitem->el_dest->nd_ID, 26270784Sjulianmsg->header.typecookie, 26370784Sjulianmsg->header.cmd, 26470784Sjulianmsg->header.cmdstr, 26570784Sjulianmsg->header.flags, 26670784Sjulianmsg->header.token, 26770784Sjulianitem->el_dest->nd_type->name); 26870784Sjulian SAVE_LINE(item); 26970784Sjulian (error) = ng_snd_item((item), 0); 27070784Sjulian } 27170784Sjulianelse { 27270784Sjulianprintf("errx=%d\n",error); 27370784Sjulian} 27470784Sjulian (msg) = NULL; 27570784Sjulian } while (0); 27670784Sjulian 27770784Sjulian#else 27870700Sjulian /* The callee will free the msg when done. The path is our business. */ 279102244Sarchie NG_SEND_MSG_PATH(error, pcbp->sockdata->node, msg, path, 0); 28070784Sjulian#endif 28152419Sjulianrelease: 28252419Sjulian if (path != NULL) 28370870Sjulian FREE(path, M_NETGRAPH_PATH); 28452419Sjulian if (control != NULL) 28552419Sjulian m_freem(control); 28652419Sjulian if (m != NULL) 28752419Sjulian m_freem(m); 28852419Sjulian return (error); 28952419Sjulian} 29052419Sjulian 29152419Sjulianstatic int 29283366Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 29352419Sjulian{ 29452419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 29552419Sjulian 29652419Sjulian if (pcbp == 0) 29752419Sjulian return (EINVAL); 29852419Sjulian return (ng_bind(nam, pcbp)); 29952419Sjulian} 30052419Sjulian 30152419Sjulianstatic int 30283366Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 30352419Sjulian{ 30470784Sjulianprintf(" program tried to connect control socket to remote node\n "); 30570700Sjulian /* 30670784Sjulian * At this time refuse to do this.. it used to 30770700Sjulian * do something but it was undocumented and not used. 30870700Sjulian */ 30970700Sjulian return (EINVAL); 31052419Sjulian} 31152419Sjulian 31252419Sjulian/*************************************************************** 31352419Sjulian Data sockets 31452419Sjulian***************************************************************/ 31552419Sjulian 31652419Sjulianstatic int 31783366Sjulianngd_attach(struct socket *so, int proto, struct thread *td) 31852419Sjulian{ 31952419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 32052419Sjulian 32152419Sjulian if (pcbp != NULL) 32252419Sjulian return (EISCONN); 32352419Sjulian return (ng_attach_data(so)); 32452419Sjulian} 32552419Sjulian 32652419Sjulianstatic int 32752419Sjulianngd_detach(struct socket *so) 32852419Sjulian{ 32952419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 33052419Sjulian 33152419Sjulian if (pcbp == NULL) 33252419Sjulian return (EINVAL); 33352419Sjulian ng_detach_common(pcbp, NG_DATA); 33452419Sjulian return (0); 33552419Sjulian} 33652419Sjulian 33752419Sjulianstatic int 33852419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 33983366Sjulian struct mbuf *control, struct thread *td) 34052419Sjulian{ 34152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 34252419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 34352419Sjulian int len, error; 34453498Sjulian hook_p hook = NULL; 34553498Sjulian char hookname[NG_HOOKLEN + 1]; 34652419Sjulian 34752419Sjulian if ((pcbp == NULL) || (control != NULL)) { 34852419Sjulian error = EINVAL; 34952419Sjulian goto release; 35052419Sjulian } 35152419Sjulian if (pcbp->sockdata == NULL) { 35252419Sjulian error = ENOTCONN; 35352419Sjulian goto release; 35452419Sjulian } 35553498Sjulian /* 35653498Sjulian * If the user used any of these ways to not specify an address 35753498Sjulian * then handle specially. 35853498Sjulian */ 35953498Sjulian if ((sap == NULL) 36084777Sarchie || ((len = sap->sg_len - 2) <= 0) 36184777Sarchie || (*sap->sg_data == '\0')) { 36270784Sjulian if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) { 36353498Sjulian error = EDESTADDRREQ; 36453498Sjulian goto release; 36553498Sjulian } 36653498Sjulian /* 36753498Sjulian * if exactly one hook exists, just use it. 36853498Sjulian * Special case to allow write(2) to work on an ng_socket. 36953498Sjulian */ 37070784Sjulian hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks); 37153498Sjulian } else { 37253498Sjulian if (len > NG_HOOKLEN) { 37353498Sjulian error = EINVAL; 37453498Sjulian goto release; 37553498Sjulian } 37652419Sjulian 37753498Sjulian /* 37853498Sjulian * chop off the sockaddr header, and make sure it's NUL 37953498Sjulian * terminated 38053498Sjulian */ 38153498Sjulian bcopy(sap->sg_data, hookname, len); 38253498Sjulian hookname[len] = '\0'; 38352419Sjulian 38453498Sjulian /* Find the correct hook from 'hookname' */ 38570784Sjulian LIST_FOREACH(hook, &pcbp->sockdata->node->nd_hooks, hk_hooks) { 38672053Sjulian if (strcmp(hookname, NG_HOOK_NAME(hook)) == 0) { 38753498Sjulian break; 38872053Sjulian } 38953498Sjulian } 39072053Sjulian if (hook == NULL) { 39153498Sjulian error = EHOSTUNREACH; 39272053Sjulian } 39352419Sjulian } 39452419Sjulian 39552419Sjulian /* Send data (OK if hook is NULL) */ 39669922Sjulian NG_SEND_DATA_ONLY(error, hook, m); /* makes m NULL */ 39752419Sjulian 39852419Sjulianrelease: 39952419Sjulian if (control != NULL) 40052419Sjulian m_freem(control); 40152419Sjulian if (m != NULL) 40252419Sjulian m_freem(m); 40352419Sjulian return (error); 40452419Sjulian} 40552419Sjulian 40652419Sjulianstatic int 40783366Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 40852419Sjulian{ 40952419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 41052419Sjulian 41152419Sjulian if (pcbp == 0) 41252419Sjulian return (EINVAL); 41352419Sjulian return (ng_connect_data(nam, pcbp)); 41452419Sjulian} 41552419Sjulian 41652419Sjulian/* 41752419Sjulian * Used for both data and control sockets 41852419Sjulian */ 41952419Sjulianstatic int 42052419Sjulianng_setsockaddr(struct socket *so, struct sockaddr **addr) 42152419Sjulian{ 42253098Sbrian struct ngpcb *pcbp; 42353098Sbrian struct sockaddr_ng *sg; 42453098Sbrian int sg_len, namelen, s; 42552419Sjulian 42653098Sbrian /* Why isn't sg_data a `char[1]' ? :-( */ 42753098Sbrian sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1; 42853098Sbrian 42953098Sbrian s = splnet(); 43053098Sbrian pcbp = sotongpcb(so); 43169922Sjulian if ((pcbp == NULL) || (pcbp->sockdata == NULL)) { 43253098Sbrian splx(s); 43352419Sjulian return (EINVAL); 43453098Sbrian } 43553098Sbrian 43653098Sbrian namelen = 0; /* silence compiler ! */ 43770784Sjulian if ( NG_NODE_HAS_NAME(pcbp->sockdata->node)) 43870784Sjulian sg_len += namelen = strlen(NG_NODE_NAME(pcbp->sockdata->node)); 43953098Sbrian 44068876Sdwmalone MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK | M_ZERO); 44153098Sbrian 44270784Sjulian if (NG_NODE_HAS_NAME(pcbp->sockdata->node)) 44370784Sjulian bcopy(NG_NODE_NAME(pcbp->sockdata->node), sg->sg_data, namelen); 44453098Sbrian splx(s); 44553098Sbrian 44653098Sbrian sg->sg_len = sg_len; 44753098Sbrian sg->sg_family = AF_NETGRAPH; 44853098Sbrian *addr = (struct sockaddr *)sg; 44953098Sbrian 45052419Sjulian return (0); 45152419Sjulian} 45252419Sjulian 45352419Sjulian/* 45452419Sjulian * Attach a socket to it's protocol specific partner. 45552419Sjulian * For a control socket, actually create a netgraph node and attach 45652419Sjulian * to it as well. 45752419Sjulian */ 45852419Sjulian 45952419Sjulianstatic int 46052419Sjulianng_attach_cntl(struct socket *so) 46152419Sjulian{ 46252419Sjulian struct ngsock *privdata; 46352419Sjulian struct ngpcb *pcbp; 46452419Sjulian int error; 46552419Sjulian 46652419Sjulian /* Setup protocol control block */ 46752419Sjulian if ((error = ng_attach_common(so, NG_CONTROL)) != 0) 46852419Sjulian return (error); 46953526Sjulian pcbp = sotongpcb(so); 47052419Sjulian 47152419Sjulian /* Allocate node private info */ 47252419Sjulian MALLOC(privdata, struct ngsock *, 47370870Sjulian sizeof(*privdata), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO); 47452419Sjulian if (privdata == NULL) { 47552419Sjulian ng_detach_common(pcbp, NG_CONTROL); 47652419Sjulian return (ENOMEM); 47752419Sjulian } 47852419Sjulian 47952419Sjulian /* Make the generic node components */ 48052419Sjulian if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) { 48170870Sjulian FREE(privdata, M_NETGRAPH_SOCK); 48252419Sjulian ng_detach_common(pcbp, NG_CONTROL); 48352419Sjulian return (error); 48452419Sjulian } 48570784Sjulian NG_NODE_SET_PRIVATE(privdata->node, privdata); 48652419Sjulian 48752419Sjulian /* Link the pcb and the node private data */ 48852419Sjulian privdata->ctlsock = pcbp; 48952419Sjulian pcbp->sockdata = privdata; 49052419Sjulian privdata->refs++; 49152419Sjulian return (0); 49252419Sjulian} 49352419Sjulian 49452419Sjulianstatic int 49552419Sjulianng_attach_data(struct socket *so) 49652419Sjulian{ 49752419Sjulian return(ng_attach_common(so, NG_DATA)); 49852419Sjulian} 49952419Sjulian 50052419Sjulian/* 50152419Sjulian * Set up a socket protocol control block. 50252419Sjulian * This code is shared between control and data sockets. 50352419Sjulian */ 50452419Sjulianstatic int 50552419Sjulianng_attach_common(struct socket *so, int type) 50652419Sjulian{ 50752419Sjulian struct ngpcb *pcbp; 50852419Sjulian int error; 50952419Sjulian 51052419Sjulian /* Standard socket setup stuff */ 51152419Sjulian error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace); 51252419Sjulian if (error) 51352419Sjulian return (error); 51452419Sjulian 51552419Sjulian /* Allocate the pcb */ 51668876Sdwmalone MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK | M_ZERO); 51752419Sjulian if (pcbp == NULL) 51852419Sjulian return (ENOMEM); 51952419Sjulian pcbp->type = type; 52052419Sjulian 52152419Sjulian /* Link the pcb and the socket */ 52252419Sjulian so->so_pcb = (caddr_t) pcbp; 52352419Sjulian pcbp->ng_socket = so; 52452419Sjulian 52552419Sjulian /* Add the socket to linked list */ 52652419Sjulian LIST_INSERT_HEAD(&ngsocklist, pcbp, socks); 52752419Sjulian return (0); 52852419Sjulian} 52952419Sjulian 53052419Sjulian/* 53152419Sjulian * Disassociate the socket from it's protocol specific 53252419Sjulian * partner. If it's attached to a node's private data structure, 53352419Sjulian * then unlink from that too. If we were the last socket attached to it, 53452419Sjulian * then shut down the entire node. Shared code for control and data sockets. 53552419Sjulian */ 53652419Sjulianstatic void 53752419Sjulianng_detach_common(struct ngpcb *pcbp, int which) 53852419Sjulian{ 53972053Sjulian struct ngsock *priv; 54052419Sjulian 54152419Sjulian if (pcbp->sockdata) { 54272053Sjulian priv = pcbp->sockdata; 54352419Sjulian pcbp->sockdata = NULL; 54452419Sjulian switch (which) { 54552419Sjulian case NG_CONTROL: 54672053Sjulian priv->ctlsock = NULL; 54752419Sjulian break; 54852419Sjulian case NG_DATA: 54972053Sjulian priv->datasock = NULL; 55052419Sjulian break; 55152419Sjulian default: 55287599Sobrien panic(__func__); 55352419Sjulian } 55472053Sjulian if ((--priv->refs == 0) && (priv->node != NULL)) 55572053Sjulian ng_rmnode_self(priv->node); 55652419Sjulian } 55752419Sjulian pcbp->ng_socket->so_pcb = NULL; 55852419Sjulian pcbp->ng_socket = NULL; 55952419Sjulian LIST_REMOVE(pcbp, socks); 56052419Sjulian FREE(pcbp, M_PCB); 56152419Sjulian} 56252419Sjulian 56352419Sjulian#ifdef NOTYET 56452419Sjulian/* 565108533Sschweikh * File descriptors can be passed into an AF_NETGRAPH socket. 56652419Sjulian * Note, that file descriptors cannot be passed OUT. 56752419Sjulian * Only character device descriptors are accepted. 56852419Sjulian * Character devices are useful to connect a graph to a device, 56952419Sjulian * which after all is the purpose of this whole system. 57052419Sjulian */ 57152419Sjulianstatic int 57283366Sjulianng_internalize(struct mbuf *control, struct thread *td) 57352419Sjulian{ 57497897Sarchie const struct cmsghdr *cm = mtod(control, const struct cmsghdr *); 57552419Sjulian struct file *fp; 57652419Sjulian struct vnode *vn; 57752419Sjulian int oldfds; 57852419Sjulian int fd; 57952419Sjulian 58052419Sjulian if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 58152419Sjulian cm->cmsg_len != control->m_len) { 58252419Sjulian TRAP_ERROR; 58352419Sjulian return (EINVAL); 58452419Sjulian } 58552419Sjulian 58652419Sjulian /* Check there is only one FD. XXX what would more than one signify? */ 58784472Sdwmalone oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int); 58852419Sjulian if (oldfds != 1) { 58952419Sjulian TRAP_ERROR; 59052419Sjulian return (EINVAL); 59152419Sjulian } 59252419Sjulian 59352419Sjulian /* Check that the FD given is legit. and change it to a pointer to a 59452419Sjulian * struct file. */ 59584472Sdwmalone fd = CMSG_DATA(cm); 59689319Salfred if ((error = fget(td, fd, &fp)) != 0) 59789319Salfred return (error); 59852419Sjulian 59952419Sjulian /* Depending on what kind of resource it is, act differently. For 600108533Sschweikh * devices, we treat it as a file. For an AF_NETGRAPH socket, 60152419Sjulian * shortcut straight to the node. */ 60252419Sjulian switch (fp->f_type) { 60352419Sjulian case DTYPE_VNODE: 60452419Sjulian vn = (struct vnode *) fp->f_data; 60552419Sjulian if (vn && (vn->v_type == VCHR)) { 60652419Sjulian /* for a VCHR, actually reference the FILE */ 60752419Sjulian fp->f_count++; 60852419Sjulian /* XXX then what :) */ 60952419Sjulian /* how to pass on to other modules? */ 61052419Sjulian } else { 61189306Salfred fdrop(fp, td); 61252419Sjulian TRAP_ERROR; 61352419Sjulian return (EINVAL); 61452419Sjulian } 61552419Sjulian break; 61652419Sjulian default: 61789306Salfred fdrop(fp, td); 61852419Sjulian TRAP_ERROR; 61952419Sjulian return (EINVAL); 62052419Sjulian } 62189306Salfred fdrop(fp, td); 62252419Sjulian return (0); 62352419Sjulian} 62452419Sjulian#endif /* NOTYET */ 62552419Sjulian 62652419Sjulian/* 62752419Sjulian * Connect the data socket to a named control socket node. 62852419Sjulian */ 62952419Sjulianstatic int 63052419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) 63152419Sjulian{ 63252419Sjulian struct sockaddr_ng *sap; 63352419Sjulian node_p farnode; 63472053Sjulian struct ngsock *priv; 63552419Sjulian int error; 63670700Sjulian item_p item; 63752419Sjulian 63852419Sjulian /* If we are already connected, don't do it again */ 63952419Sjulian if (pcbp->sockdata != NULL) 64052419Sjulian return (EISCONN); 64152419Sjulian 64252419Sjulian /* Find the target (victim) and check it doesn't already have a data 64370700Sjulian * socket. Also check it is a 'socket' type node. 64470700Sjulian * Use ng_package_data() and address_path() to do this. 64570700Sjulian */ 64670700Sjulian 64752419Sjulian sap = (struct sockaddr_ng *) nam; 64870700Sjulian /* The item will hold the node reference */ 64970700Sjulian item = ng_package_data(NULL, NULL); 65070700Sjulian if (item == NULL) { 65170700Sjulian return (ENOMEM); 65270700Sjulian } 653102244Sarchie if ((error = ng_address_path(NULL, item, sap->sg_data, 0))) 65470700Sjulian return (error); /* item is freed on failure */ 65552419Sjulian 65670700Sjulian /* 65770784Sjulian * Extract node from item and free item. Remember we now have 65870700Sjulian * a reference on the node. The item holds it for us. 65970700Sjulian * when we free the item we release the reference. 66070700Sjulian */ 66170700Sjulian farnode = item->el_dest; /* shortcut */ 66270784Sjulian if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) { 66370700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 66452419Sjulian return (EINVAL); 66570700Sjulian } 66672053Sjulian priv = NG_NODE_PRIVATE(farnode); 66772053Sjulian if (priv->datasock != NULL) { 66870700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 66952419Sjulian return (EADDRINUSE); 67070700Sjulian } 67152419Sjulian 67270700Sjulian /* 67370700Sjulian * Link the PCB and the private data struct. and note the extra 67470700Sjulian * reference. Drop the extra reference on the node. 67570700Sjulian */ 67672053Sjulian priv->datasock = pcbp; 67772053Sjulian pcbp->sockdata = priv; 67872053Sjulian priv->refs++; /* XXX possible race if it's being freed */ 67970700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 68052419Sjulian return (0); 68152419Sjulian} 68252419Sjulian 68352419Sjulian/* 68452419Sjulian * Binding a socket means giving the corresponding node a name 68552419Sjulian */ 68652419Sjulianstatic int 68752419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp) 68852419Sjulian{ 68972053Sjulian struct ngsock *const priv = pcbp->sockdata; 69052419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; 69152419Sjulian 69272053Sjulian if (priv == NULL) { 69352419Sjulian TRAP_ERROR; 69452419Sjulian return (EINVAL); 69552419Sjulian } 69669922Sjulian if ((sap->sg_len < 4) 69769922Sjulian || (sap->sg_len > (NG_NODELEN + 3)) 69869922Sjulian || (sap->sg_data[0] == '\0') 69969922Sjulian || (sap->sg_data[sap->sg_len - 3] != '\0')) { 70052419Sjulian TRAP_ERROR; 70152419Sjulian return (EINVAL); 70252419Sjulian } 70372053Sjulian return (ng_name_node(priv->node, sap->sg_data)); 70452419Sjulian} 70552419Sjulian 70652419Sjulian/* 70752419Sjulian * Take a message and pass it up to the control socket associated 70852419Sjulian * with the node. 70952419Sjulian */ 71052419Sjulianstatic int 71152419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr) 71252419Sjulian{ 71352419Sjulian struct socket *const so = pcbp->ng_socket; 71452419Sjulian struct mbuf *mdata; 71552419Sjulian int msglen; 71652419Sjulian 71752419Sjulian /* Copy the message itself into an mbuf chain */ 71852419Sjulian msglen = sizeof(struct ng_mesg) + msg->header.arglen; 71952419Sjulian mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL); 72052419Sjulian 72152419Sjulian /* Here we free the message, as we are the end of the line. 72252419Sjulian * We need to do that regardless of whether we got mbufs. */ 72370700Sjulian NG_FREE_MSG(msg); 72452419Sjulian 72552419Sjulian if (mdata == NULL) { 72652419Sjulian TRAP_ERROR; 72752419Sjulian return (ENOBUFS); 72852419Sjulian } 72952419Sjulian 73052419Sjulian /* Send it up to the socket */ 73152419Sjulian if (sbappendaddr(&so->so_rcv, 73252419Sjulian (struct sockaddr *) addr, mdata, NULL) == 0) { 73352419Sjulian TRAP_ERROR; 73452419Sjulian m_freem(mdata); 73552419Sjulian return (ENOBUFS); 73652419Sjulian } 73752419Sjulian sorwakeup(so); 73852419Sjulian return (0); 73952419Sjulian} 74052419Sjulian 74152419Sjulian/* 74252419Sjulian * You can only create new nodes from the socket end of things. 74352419Sjulian */ 74452419Sjulianstatic int 74570700Sjulianngs_constructor(node_p nodep) 74652419Sjulian{ 74752419Sjulian return (EINVAL); 74852419Sjulian} 74952419Sjulian 75052419Sjulian/* 75152419Sjulian * We allow any hook to be connected to the node. 75252419Sjulian * There is no per-hook private information though. 75352419Sjulian */ 75452419Sjulianstatic int 75552419Sjulianngs_newhook(node_p node, hook_p hook, const char *name) 75652419Sjulian{ 75770784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 75852419Sjulian return (0); 75952419Sjulian} 76052419Sjulian 76172053Sjulian/* 76272053Sjulian * if only one hook, allow read(2) and write(2) to work. 76372053Sjulian */ 76472053Sjulianstatic int 76572053Sjulianngs_connect(hook_p hook) 76672053Sjulian{ 76772053Sjulian node_p node = NG_HOOK_NODE(hook); 76872053Sjulian struct ngsock *priv = NG_NODE_PRIVATE(node); 76972053Sjulian 77072053Sjulian if ((priv->datasock) 77172053Sjulian && (priv->datasock->ng_socket)) { 77272053Sjulian if (NG_NODE_NUMHOOKS(node) == 1) { 77372053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 77472053Sjulian } else { 77572053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 77672053Sjulian } 77772053Sjulian } 77872053Sjulian return (0); 77972053Sjulian} 78072053Sjulian 78152419Sjulian/* 78252419Sjulian * Incoming messages get passed up to the control socket. 78352885Sjulian * Unless they are for us specifically (socket_type) 78452419Sjulian */ 78552419Sjulianstatic int 78670700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook) 78752419Sjulian{ 78872053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 78972053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 79052419Sjulian struct sockaddr_ng *addr; 79152419Sjulian int addrlen; 79252419Sjulian int error = 0; 79370700Sjulian struct ng_mesg *msg; 79470700Sjulian ng_ID_t retaddr = NGI_RETADDR(item); 79570700Sjulian char retabuf[32]; 79652419Sjulian 79770700Sjulian NGI_GET_MSG(item, msg); 79870700Sjulian NG_FREE_ITEM(item); /* we have all we need */ 79970700Sjulian 80052419Sjulian /* Only allow mesgs to be passed if we have the control socket. 80152419Sjulian * Data sockets can only support the generic messages. */ 80252419Sjulian if (pcbp == NULL) { 80352419Sjulian TRAP_ERROR; 80452419Sjulian return (EINVAL); 80552419Sjulian } 80670784Sjulian#ifdef TRACE_MESSAGES 80770784Sjulianprintf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n", 80870784Sjulianretaddr, 80970784Sjulianmsg->header.typecookie, 81070784Sjulianmsg->header.cmd, 81170784Sjulianmsg->header.cmdstr, 81270784Sjulianmsg->header.flags, 81370784Sjulianmsg->header.token); 81452419Sjulian 81570784Sjulian#endif 81670784Sjulian 81752885Sjulian if (msg->header.typecookie == NGM_SOCKET_COOKIE) { 81852885Sjulian switch (msg->header.cmd) { 81952885Sjulian case NGM_SOCK_CMD_NOLINGER: 82072053Sjulian priv->flags |= NGS_FLAG_NOLINGER; 82152885Sjulian break; 82252885Sjulian case NGM_SOCK_CMD_LINGER: 82372053Sjulian priv->flags &= ~NGS_FLAG_NOLINGER; 82452885Sjulian break; 82552885Sjulian default: 82652885Sjulian error = EINVAL; /* unknown command */ 82752885Sjulian } 82852885Sjulian /* Free the message and return */ 82970700Sjulian NG_FREE_MSG(msg); 83052885Sjulian return(error); 83152885Sjulian 83252885Sjulian } 83352419Sjulian /* Get the return address into a sockaddr */ 83470700Sjulian sprintf(retabuf,"[%x]:", retaddr); 83570700Sjulian addrlen = strlen(retabuf); 83670870Sjulian MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH_PATH, M_NOWAIT); 83752419Sjulian if (addr == NULL) { 83852419Sjulian TRAP_ERROR; 83952419Sjulian return (ENOMEM); 84052419Sjulian } 84152419Sjulian addr->sg_len = addrlen + 3; 84252419Sjulian addr->sg_family = AF_NETGRAPH; 84370700Sjulian bcopy(retabuf, addr->sg_data, addrlen); 84452419Sjulian addr->sg_data[addrlen] = '\0'; 84552419Sjulian 84652419Sjulian /* Send it up */ 84752419Sjulian error = ship_msg(pcbp, msg, addr); 84870870Sjulian FREE(addr, M_NETGRAPH_PATH); 84952419Sjulian return (error); 85052419Sjulian} 85152419Sjulian 85252419Sjulian/* 85352419Sjulian * Receive data on a hook 85452419Sjulian */ 85552419Sjulianstatic int 85670700Sjulianngs_rcvdata(hook_p hook, item_p item) 85752419Sjulian{ 85872053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 85972053Sjulian struct ngpcb *const pcbp = priv->datasock; 86052419Sjulian struct socket *so; 86152419Sjulian struct sockaddr_ng *addr; 86252419Sjulian char *addrbuf[NG_HOOKLEN + 1 + 4]; 86352419Sjulian int addrlen; 86470700Sjulian struct mbuf *m; 86552419Sjulian 86670700Sjulian NGI_GET_M(item, m); 86770700Sjulian NG_FREE_ITEM(item); 86852419Sjulian /* If there is no data socket, black-hole it */ 86952419Sjulian if (pcbp == NULL) { 87070700Sjulian NG_FREE_M(m); 87152419Sjulian return (0); 87252419Sjulian } 87352419Sjulian so = pcbp->ng_socket; 87452419Sjulian 87552419Sjulian /* Get the return address into a sockaddr. */ 87670784Sjulian addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKLEN */ 87752419Sjulian addr = (struct sockaddr_ng *) addrbuf; 87852419Sjulian addr->sg_len = addrlen + 3; 87952419Sjulian addr->sg_family = AF_NETGRAPH; 88070784Sjulian bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); 88152419Sjulian addr->sg_data[addrlen] = '\0'; 88252419Sjulian 88352419Sjulian /* Try to tell the socket which hook it came in on */ 88452419Sjulian if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) { 88552419Sjulian m_freem(m); 88652419Sjulian TRAP_ERROR; 88752419Sjulian return (ENOBUFS); 88852419Sjulian } 88952419Sjulian sorwakeup(so); 89052419Sjulian return (0); 89152419Sjulian} 89252419Sjulian 89352419Sjulian/* 89453498Sjulian * Hook disconnection 89552885Sjulian * 89652885Sjulian * For this type, removal of the last link destroys the node 89752885Sjulian * if the NOLINGER flag is set. 89852885Sjulian */ 89952885Sjulianstatic int 90052885Sjulianngs_disconnect(hook_p hook) 90152885Sjulian{ 90272053Sjulian node_p node = NG_HOOK_NODE(hook); 90372053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 90452885Sjulian 90572053Sjulian if ((priv->datasock) 90672053Sjulian && (priv->datasock->ng_socket)) { 90772053Sjulian if (NG_NODE_NUMHOOKS(node) == 1) { 90872053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 90972053Sjulian } else { 91072053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 91172053Sjulian } 91252885Sjulian } 91372053Sjulian 91472053Sjulian if ((priv->flags & NGS_FLAG_NOLINGER ) 91572053Sjulian && (NG_NODE_NUMHOOKS(node) == 0) 91672053Sjulian && (NG_NODE_IS_VALID(node))) { 91772053Sjulian ng_rmnode_self(node); 91872053Sjulian } 91952885Sjulian return (0); 92052885Sjulian} 92152885Sjulian 92252885Sjulian/* 92352419Sjulian * Do local shutdown processing. 92452419Sjulian * In this case, that involves making sure the socket 92552419Sjulian * knows we should be shutting down. 92652419Sjulian */ 92752419Sjulianstatic int 92870700Sjulianngs_shutdown(node_p node) 92952419Sjulian{ 93072053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 93172053Sjulian struct ngpcb *const dpcbp = priv->datasock; 93272053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 93352419Sjulian 93452419Sjulian if (dpcbp != NULL) { 93552419Sjulian soisdisconnected(dpcbp->ng_socket); 93652419Sjulian dpcbp->sockdata = NULL; 93772053Sjulian priv->datasock = NULL; 93872053Sjulian priv->refs--; 93952419Sjulian } 94052419Sjulian if (pcbp != NULL) { 94152419Sjulian soisdisconnected(pcbp->ng_socket); 94252419Sjulian pcbp->sockdata = NULL; 94372053Sjulian priv->ctlsock = NULL; 94472053Sjulian priv->refs--; 94552419Sjulian } 94670784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 94770784Sjulian NG_NODE_UNREF(node); 94872053Sjulian FREE(priv, M_NETGRAPH_SOCK); 94952419Sjulian return (0); 95052419Sjulian} 95152419Sjulian 95272055Sjulianstatic int 95372055Sjuliandummy_disconnect(struct socket *so) 95472055Sjulian{ 95572055Sjulian return (0); 95672055Sjulian} 95752419Sjulian/* 95852419Sjulian * Control and data socket type descriptors 95952419Sjulian */ 96052419Sjulian 96152419Sjulianstatic struct pr_usrreqs ngc_usrreqs = { 96252419Sjulian NULL, /* abort */ 96352419Sjulian pru_accept_notsupp, 96452419Sjulian ngc_attach, 96552419Sjulian ngc_bind, 96652419Sjulian ngc_connect, 96752419Sjulian pru_connect2_notsupp, 96852419Sjulian pru_control_notsupp, 96952419Sjulian ngc_detach, 97072055Sjulian dummy_disconnect, /* disconnect */ 97152419Sjulian pru_listen_notsupp, 97252419Sjulian NULL, /* setpeeraddr */ 97352419Sjulian pru_rcvd_notsupp, 97452419Sjulian pru_rcvoob_notsupp, 97552419Sjulian ngc_send, 97652419Sjulian pru_sense_null, 97752419Sjulian NULL, /* shutdown */ 97852419Sjulian ng_setsockaddr, 97952419Sjulian sosend, 98052419Sjulian soreceive, 98152419Sjulian sopoll 98252419Sjulian}; 98352419Sjulian 98452419Sjulianstatic struct pr_usrreqs ngd_usrreqs = { 98552419Sjulian NULL, /* abort */ 98652419Sjulian pru_accept_notsupp, 98752419Sjulian ngd_attach, 98852419Sjulian NULL, /* bind */ 98952419Sjulian ngd_connect, 99052419Sjulian pru_connect2_notsupp, 99152419Sjulian pru_control_notsupp, 99252419Sjulian ngd_detach, 99372055Sjulian dummy_disconnect, /* disconnect */ 99452419Sjulian pru_listen_notsupp, 99552419Sjulian NULL, /* setpeeraddr */ 99652419Sjulian pru_rcvd_notsupp, 99752419Sjulian pru_rcvoob_notsupp, 99852419Sjulian ngd_send, 99952419Sjulian pru_sense_null, 100052419Sjulian NULL, /* shutdown */ 100152419Sjulian ng_setsockaddr, 100252419Sjulian sosend, 100352419Sjulian soreceive, 100452419Sjulian sopoll 100552419Sjulian}; 100652419Sjulian 100752419Sjulian/* 100852419Sjulian * Definitions of protocols supported in the NETGRAPH domain. 100952419Sjulian */ 101052419Sjulian 101152419Sjulianextern struct domain ngdomain; /* stop compiler warnings */ 101252419Sjulian 101352419Sjulianstatic struct protosw ngsw[] = { 101452419Sjulian { 101570700Sjulian SOCK_DGRAM, /* protocol type */ 101670700Sjulian &ngdomain, /* backpointer to domain */ 101752419Sjulian NG_CONTROL, 101870700Sjulian PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, /* flags */ 101970700Sjulian 0, 0, 0, 0, /* input, output, ctlinput, ctloutput */ 102070700Sjulian NULL, /* ousrreq */ 102170700Sjulian 0, 0, 0, 0, /* init, fasttimeo, slowtimo, drain */ 102270700Sjulian &ngc_usrreqs, /* usrreq table (above) */ 102370700Sjulian /*{NULL}*/ /* pffh (protocol filter head?) */ 102452419Sjulian }, 102552419Sjulian { 102670700Sjulian SOCK_DGRAM, /* protocol type */ 102770700Sjulian &ngdomain, /* backpointer to domain */ 102852419Sjulian NG_DATA, 102970700Sjulian PR_ATOMIC | PR_ADDR, /* flags */ 103070700Sjulian 0, 0, 0, 0, /* input, output, ctlinput, ctloutput */ 103170700Sjulian NULL, /* ousrreq() */ 103270700Sjulian 0, 0, 0, 0, /* init, fasttimeo, slowtimo, drain */ 103370700Sjulian &ngd_usrreqs, /* usrreq table (above) */ 103470700Sjulian /*{NULL}*/ /* pffh (protocol filter head?) */ 103552419Sjulian } 103652419Sjulian}; 103752419Sjulian 103852419Sjulianstruct domain ngdomain = { 103952419Sjulian AF_NETGRAPH, 104052419Sjulian "netgraph", 104170700Sjulian NULL, /* init() */ 104270700Sjulian NULL, /* externalise() */ 104370700Sjulian NULL, /* dispose() */ 104470700Sjulian ngsw, /* protosw entry */ 104570700Sjulian &ngsw[sizeof(ngsw) / sizeof(ngsw[0])], /* Number of protosw entries */ 104670700Sjulian NULL, /* next domain in list */ 104770700Sjulian NULL, /* rtattach() */ 104870700Sjulian 0, /* arg to rtattach in bits */ 104970700Sjulian 0 /* maxrtkey */ 105052419Sjulian}; 105152419Sjulian 105252419Sjulian/* 105352419Sjulian * Handle loading and unloading for this node type 105452419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition). 105552419Sjulian */ 105652419Sjulianstatic int 105752419Sjulianngs_mod_event(module_t mod, int event, void *data) 105852419Sjulian{ 105952419Sjulian int error = 0; 106052419Sjulian 106152419Sjulian switch (event) { 106252419Sjulian case MOD_LOAD: 106352419Sjulian /* Register protocol domain */ 106452419Sjulian net_add_domain(&ngdomain); 106552419Sjulian break; 106652419Sjulian case MOD_UNLOAD: 106752419Sjulian /* Insure there are no open netgraph sockets */ 106852419Sjulian if (!LIST_EMPTY(&ngsocklist)) { 106952419Sjulian error = EBUSY; 107052419Sjulian break; 107152419Sjulian } 107252419Sjulian 107352419Sjulian#ifdef NOTYET 107470700Sjulian if ((LIST_EMPTY(&ngsocklist)) && (typestruct.refs == 0)) { 107552419Sjulian /* Unregister protocol domain XXX can't do this yet.. */ 107670700Sjulian if ((error = net_rm_domain(&ngdomain)) != 0) 107770700Sjulian break; 107870700Sjulian } else 107952419Sjulian#endif 108070700Sjulian error = EBUSY; 108152419Sjulian break; 108252419Sjulian default: 108352419Sjulian error = EOPNOTSUPP; 108452419Sjulian break; 108552419Sjulian } 108652419Sjulian return (error); 108752419Sjulian} 108852419Sjulian 108952419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, ""); 109052419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); 109152419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, ""); 109252419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); 109352419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, ""); 109452419Sjulian 1095