ng_socket.c revision 205082
152419Sjulian/* 252419Sjulian * ng_socket.c 3139823Simp */ 4139823Simp 5139823Simp/*- 652419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 752419Sjulian * All rights reserved. 870784Sjulian * 952419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 1052419Sjulian * redistribution of this software, in source or object code forms, with or 1152419Sjulian * without modifications are expressly permitted by Whistle Communications; 1252419Sjulian * provided, however, that: 1352419Sjulian * 1. Any and all reproductions of the source or object code must include the 1452419Sjulian * copyright notice above and the following disclaimer of warranties; and 1552419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1652419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1752419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1852419Sjulian * such appears in the above copyright notice or in the software. 1970784Sjulian * 2052419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2152419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2252419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2352419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2452419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2552419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2652419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2752419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2852419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2952419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3052419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3152419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3252419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3352419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3452419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3552419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3652419Sjulian * OF SUCH DAMAGE. 3752419Sjulian * 3867506Sjulian * Author: Julian Elischer <julian@freebsd.org> 3952419Sjulian * 4052419Sjulian * $FreeBSD: head/sys/netgraph/ng_socket.c 205082 2010-03-12 14:51:42Z glebius $ 4152752Sjulian * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $ 4252419Sjulian */ 4352419Sjulian 4452419Sjulian/* 4552419Sjulian * Netgraph socket nodes 4652419Sjulian * 4752419Sjulian * There are two types of netgraph sockets, control and data. 4852419Sjulian * Control sockets have a netgraph node, but data sockets are 4952419Sjulian * parasitic on control sockets, and have no node of their own. 5052419Sjulian */ 5152419Sjulian 5252419Sjulian#include <sys/param.h> 5352419Sjulian#include <sys/domain.h> 5452419Sjulian#include <sys/kernel.h> 55132705Sglebius#include <sys/linker.h> 5695759Stanimura#include <sys/lock.h> 5752419Sjulian#include <sys/malloc.h> 5852419Sjulian#include <sys/mbuf.h> 59132013Srwatson#include <sys/mutex.h> 60164033Srwatson#include <sys/priv.h> 6152419Sjulian#include <sys/protosw.h> 6295759Stanimura#include <sys/queue.h> 6352419Sjulian#include <sys/socket.h> 6452419Sjulian#include <sys/socketvar.h> 65159590Sjhb#include <sys/syscallsubr.h> 6652419Sjulian#include <sys/sysctl.h> 6752419Sjulian#ifdef NOTYET 6852419Sjulian#include <sys/vnode.h> 6952419Sjulian#endif 70195837Srwatson 71195837Srwatson#include <net/vnet.h> 72195837Srwatson 7352419Sjulian#include <netgraph/ng_message.h> 7452419Sjulian#include <netgraph/netgraph.h> 7552919Sjulian#include <netgraph/ng_socketvar.h> 7652419Sjulian#include <netgraph/ng_socket.h> 7752419Sjulian 7870870Sjulian#ifdef NG_SEPARATE_MALLOC 7970870SjulianMALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info "); 8070870SjulianMALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info "); 8170870Sjulian#else 8270870Sjulian#define M_NETGRAPH_PATH M_NETGRAPH 8370870Sjulian#define M_NETGRAPH_SOCK M_NETGRAPH 8470870Sjulian#endif 8570870Sjulian 8652419Sjulian/* 8752419Sjulian * It's Ascii-art time! 8852419Sjulian * +-------------+ +-------------+ 8952419Sjulian * |socket (ctl)| |socket (data)| 9052419Sjulian * +-------------+ +-------------+ 9152419Sjulian * ^ ^ 9252419Sjulian * | | 9352419Sjulian * v v 9452419Sjulian * +-----------+ +-----------+ 9552419Sjulian * |pcb (ctl)| |pcb (data)| 9652419Sjulian * +-----------+ +-----------+ 9752419Sjulian * ^ ^ 9852419Sjulian * | | 9952419Sjulian * v v 10052419Sjulian * +--------------------------+ 10152419Sjulian * | Socket type private | 10252419Sjulian * | data | 10352419Sjulian * +--------------------------+ 10452419Sjulian * ^ 10552419Sjulian * | 10652419Sjulian * v 10752419Sjulian * +----------------+ 10852419Sjulian * | struct ng_node | 10952419Sjulian * +----------------+ 11052419Sjulian */ 11152419Sjulian 11252419Sjulian/* Netgraph node methods */ 11352752Sjulianstatic ng_constructor_t ngs_constructor; 11452752Sjulianstatic ng_rcvmsg_t ngs_rcvmsg; 11570700Sjulianstatic ng_shutdown_t ngs_shutdown; 11652752Sjulianstatic ng_newhook_t ngs_newhook; 11772053Sjulianstatic ng_connect_t ngs_connect; 11852752Sjulianstatic ng_rcvdata_t ngs_rcvdata; 11952885Sjulianstatic ng_disconnect_t ngs_disconnect; 12052419Sjulian 12152419Sjulian/* Internal methods */ 12252419Sjulianstatic int ng_attach_data(struct socket *so); 12352419Sjulianstatic int ng_attach_cntl(struct socket *so); 12452419Sjulianstatic int ng_attach_common(struct socket *so, int type); 125151975Sglebiusstatic void ng_detach_common(struct ngpcb *pcbp, int type); 126151975Sglebiusstatic void ng_socket_free_priv(struct ngsock *priv); 127163463Sglebius#ifdef NOTYET 128163463Sglebiusstatic int ng_internalize(struct mbuf *m, struct thread *p); 129163463Sglebius#endif 13052419Sjulianstatic int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp); 13152419Sjulianstatic int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); 13252419Sjulian 13352419Sjulianstatic int ngs_mod_event(module_t mod, int event, void *data); 134147774Sglebiusstatic void ng_socket_item_applied(void *context, int error); 13552419Sjulian 13652419Sjulian/* Netgraph type descriptor */ 13752419Sjulianstatic struct ng_type typestruct = { 138129823Sjulian .version = NG_ABI_VERSION, 139129823Sjulian .name = NG_SOCKET_NODE_TYPE, 140129823Sjulian .mod_event = ngs_mod_event, 141129823Sjulian .constructor = ngs_constructor, 142129823Sjulian .rcvmsg = ngs_rcvmsg, 143129823Sjulian .shutdown = ngs_shutdown, 144129823Sjulian .newhook = ngs_newhook, 145129823Sjulian .connect = ngs_connect, 146129823Sjulian .rcvdata = ngs_rcvdata, 147129823Sjulian .disconnect = ngs_disconnect, 14852419Sjulian}; 149138238SmlaierNETGRAPH_INIT_ORDERED(socket, &typestruct, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 15052419Sjulian 15152419Sjulian/* Buffer space */ 15264512Sarchiestatic u_long ngpdg_sendspace = 20 * 1024; /* really max datagram size */ 153124871SruSYSCTL_INT(_net_graph, OID_AUTO, maxdgram, CTLFLAG_RW, 154124871Sru &ngpdg_sendspace , 0, "Maximum outgoing Netgraph datagram size"); 15552419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024; 156124871SruSYSCTL_INT(_net_graph, OID_AUTO, recvspace, CTLFLAG_RW, 157125116Sru &ngpdg_recvspace , 0, "Maximum space for incoming Netgraph datagrams"); 15852419Sjulian 159205082Sglebius/* List of all sockets (for netstat -f netgraph) */ 160205082Sglebiusstatic LIST_HEAD(, ngpcb) ngsocklist; 161205082Sglebius 162205082Sglebiusstatic struct mtx ngsocketlist_mtx; 163205082Sglebius 16453526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb) 16552419Sjulian 166131933Smarcel/* If getting unexplained errors returned, set this to "kdb_enter("X"); */ 16752419Sjulian#ifndef TRAP_ERROR 16852419Sjulian#define TRAP_ERROR 16952419Sjulian#endif 17052419Sjulian 17152419Sjulian/*************************************************************** 17252419Sjulian Control sockets 17352419Sjulian***************************************************************/ 17452419Sjulian 17552419Sjulianstatic int 17683366Sjulianngc_attach(struct socket *so, int proto, struct thread *td) 17752419Sjulian{ 17852419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 179164033Srwatson int error; 18052419Sjulian 181164033Srwatson error = priv_check(td, PRIV_NETGRAPH_CONTROL); 182164033Srwatson if (error) 183164033Srwatson return (error); 18452419Sjulian if (pcbp != NULL) 18552419Sjulian return (EISCONN); 18652419Sjulian return (ng_attach_cntl(so)); 18752419Sjulian} 18852419Sjulian 189157370Srwatsonstatic void 19052419Sjulianngc_detach(struct socket *so) 19152419Sjulian{ 19252419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 19352419Sjulian 194157370Srwatson KASSERT(pcbp != NULL, ("ngc_detach: pcbp == NULL")); 195151975Sglebius ng_detach_common(pcbp, NG_CONTROL); 19652419Sjulian} 19752419Sjulian 19852419Sjulianstatic int 19952419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 20083366Sjulian struct mbuf *control, struct thread *td) 20152419Sjulian{ 20252419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 203147774Sglebius struct ngsock *const priv = NG_NODE_PRIVATE(pcbp->sockdata->node); 20452419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 20570700Sjulian struct ng_mesg *msg; 20652419Sjulian struct mbuf *m0; 207146317Sglebius item_p item; 20870700Sjulian char *path = NULL; 20952419Sjulian int len, error = 0; 210172806Smav struct ng_apply_info apply; 21152419Sjulian 21252419Sjulian#ifdef NOTYET 21383366Sjulian if (control && (error = ng_internalize(control, td))) { 21452419Sjulian if (pcbp->sockdata == NULL) { 21552419Sjulian error = ENOTCONN; 21652419Sjulian goto release; 21752419Sjulian } 21852419Sjulian } 21952419Sjulian#else /* NOTYET */ 22052419Sjulian if (control) { 22152419Sjulian error = EINVAL; 22252419Sjulian goto release; 22352419Sjulian } 22452419Sjulian#endif /* NOTYET */ 22552419Sjulian 226163463Sglebius /* Require destination as there may be >= 1 hooks on this node. */ 22752419Sjulian if (addr == NULL) { 22852419Sjulian error = EDESTADDRREQ; 22952419Sjulian goto release; 23052419Sjulian } 23152419Sjulian 232163463Sglebius /* 233163463Sglebius * Allocate an expendable buffer for the path, chop off 234163463Sglebius * the sockaddr header, and make sure it's NUL terminated. 235163463Sglebius */ 23652419Sjulian len = sap->sg_len - 2; 237163463Sglebius path = malloc(len + 1, M_NETGRAPH_PATH, M_WAITOK); 23852419Sjulian bcopy(sap->sg_data, path, len); 23952419Sjulian path[len] = '\0'; 24052419Sjulian 241163463Sglebius /* 242163463Sglebius * Move the actual message out of mbufs into a linear buffer. 243163463Sglebius * Start by adding up the size of the data. (could use mh_len?) 244163463Sglebius */ 24552419Sjulian for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next) 24652419Sjulian len += m0->m_len; 24752419Sjulian 248163463Sglebius /* 249163463Sglebius * Move the data into a linear buffer as well. 250163463Sglebius * Messages are not delivered in mbufs. 251163463Sglebius */ 252163463Sglebius msg = malloc(len + 1, M_NETGRAPH_MSG, M_WAITOK); 25370700Sjulian m_copydata(m, 0, len, (char *)msg); 25452419Sjulian 255141308Sglebius if (msg->header.version != NG_VERSION) { 256163463Sglebius free(msg, M_NETGRAPH_MSG); 257141308Sglebius error = EINVAL; 258141308Sglebius goto release; 259141308Sglebius } 260141308Sglebius 261132705Sglebius /* 262132705Sglebius * Hack alert! 263132705Sglebius * We look into the message and if it mkpeers a node of unknown type, we 264132705Sglebius * try to load it. We need to do this now, in syscall thread, because if 265132705Sglebius * message gets queued and applied later we will get panic. 266132705Sglebius */ 267132939Sglebius if (msg->header.typecookie == NGM_GENERIC_COOKIE && 268132939Sglebius msg->header.cmd == NGM_MKPEER) { 269132705Sglebius struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 270132705Sglebius 271185183Smav if (ng_findtype(mkp->type) == NULL) { 272132705Sglebius char filename[NG_TYPESIZ + 3]; 273159590Sjhb int fileid; 274132705Sglebius 275146296Sglebius /* Not found, try to load it as a loadable module. */ 276146296Sglebius snprintf(filename, sizeof(filename), "ng_%s", 277146296Sglebius mkp->type); 278159590Sjhb error = kern_kldload(curthread, filename, &fileid); 279132705Sglebius if (error != 0) { 280163463Sglebius free(msg, M_NETGRAPH_MSG); 281132705Sglebius goto release; 282132705Sglebius } 283132705Sglebius 284146296Sglebius /* See if type has been loaded successfully. */ 285185183Smav if (ng_findtype(mkp->type) == NULL) { 286163463Sglebius free(msg, M_NETGRAPH_MSG); 287159590Sjhb (void)kern_kldunload(curthread, fileid, 288159590Sjhb LINKER_UNLOAD_NORMAL); 289132705Sglebius error = ENXIO; 290132705Sglebius goto release; 291132705Sglebius } 292132705Sglebius } 293132705Sglebius } 294132705Sglebius 295163463Sglebius item = ng_package_msg(msg, M_WAITOK); 296163463Sglebius if ((error = ng_address_path((pcbp->sockdata->node), item, path, 0)) 297163463Sglebius != 0) { 298146296Sglebius#ifdef TRACE_MESSAGES 299146317Sglebius printf("ng_address_path: errx=%d\n", error); 300146317Sglebius#endif 301146317Sglebius goto release; 302146317Sglebius } 303146296Sglebius 304146317Sglebius#ifdef TRACE_MESSAGES 305146317Sglebius printf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n", 306146317Sglebius item->el_dest->nd_ID, 307146317Sglebius msg->header.typecookie, 308146317Sglebius msg->header.cmd, 309146317Sglebius msg->header.cmdstr, 310146317Sglebius msg->header.flags, 311146317Sglebius msg->header.token, 312146317Sglebius item->el_dest->nd_type->name); 31370784Sjulian#endif 314146317Sglebius SAVE_LINE(item); 315147774Sglebius /* 316147774Sglebius * We do not want to return from syscall until the item 317147774Sglebius * is processed by destination node. We register callback 318147774Sglebius * on the item, which will update priv->error when item 319147774Sglebius * was applied. 320147774Sglebius * If ng_snd_item() has queued item, we sleep until 321147774Sglebius * callback wakes us up. 322147774Sglebius */ 323172806Smav bzero(&apply, sizeof(apply)); 324172806Smav apply.apply = ng_socket_item_applied; 325172806Smav apply.context = priv; 326172806Smav item->apply = &apply; 327147774Sglebius priv->error = -1; 328146296Sglebius 329172806Smav error = ng_snd_item(item, 0); 330147774Sglebius 331172806Smav mtx_lock(&priv->mtx); 332172806Smav if (priv->error == -1) 333172806Smav msleep(priv, &priv->mtx, 0, "ngsock", 0); 334172806Smav mtx_unlock(&priv->mtx); 335172806Smav KASSERT(priv->error != -1, 336172806Smav ("ng_socket: priv->error wasn't updated")); 337172806Smav error = priv->error; 338147774Sglebius 33952419Sjulianrelease: 34052419Sjulian if (path != NULL) 341163463Sglebius free(path, M_NETGRAPH_PATH); 34252419Sjulian if (control != NULL) 34352419Sjulian m_freem(control); 34452419Sjulian if (m != NULL) 34552419Sjulian m_freem(m); 34652419Sjulian return (error); 34752419Sjulian} 34852419Sjulian 34952419Sjulianstatic int 35083366Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 35152419Sjulian{ 35252419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 35352419Sjulian 35452419Sjulian if (pcbp == 0) 35552419Sjulian return (EINVAL); 35652419Sjulian return (ng_bind(nam, pcbp)); 35752419Sjulian} 35852419Sjulian 35952419Sjulianstatic int 36083366Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 36152419Sjulian{ 36270700Sjulian /* 36370784Sjulian * At this time refuse to do this.. it used to 36470700Sjulian * do something but it was undocumented and not used. 36570700Sjulian */ 366163463Sglebius printf("program tried to connect control socket to remote node\n"); 36770700Sjulian return (EINVAL); 36852419Sjulian} 36952419Sjulian 37052419Sjulian/*************************************************************** 37152419Sjulian Data sockets 37252419Sjulian***************************************************************/ 37352419Sjulian 37452419Sjulianstatic int 37583366Sjulianngd_attach(struct socket *so, int proto, struct thread *td) 37652419Sjulian{ 37752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 37852419Sjulian 37952419Sjulian if (pcbp != NULL) 38052419Sjulian return (EISCONN); 38152419Sjulian return (ng_attach_data(so)); 38252419Sjulian} 38352419Sjulian 384157370Srwatsonstatic void 38552419Sjulianngd_detach(struct socket *so) 38652419Sjulian{ 38752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 38852419Sjulian 389157558Srwatson KASSERT(pcbp != NULL, ("ngd_detach: pcbp == NULL")); 390151975Sglebius ng_detach_common(pcbp, NG_DATA); 39152419Sjulian} 39252419Sjulian 39352419Sjulianstatic int 39452419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 39583366Sjulian struct mbuf *control, struct thread *td) 39652419Sjulian{ 39752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 39852419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 399163463Sglebius int len, error; 40053498Sjulian hook_p hook = NULL; 401125028Sharti char hookname[NG_HOOKSIZ]; 40252419Sjulian 40352419Sjulian if ((pcbp == NULL) || (control != NULL)) { 40452419Sjulian error = EINVAL; 40552419Sjulian goto release; 40652419Sjulian } 40752419Sjulian if (pcbp->sockdata == NULL) { 40852419Sjulian error = ENOTCONN; 40952419Sjulian goto release; 41052419Sjulian } 411146718Sbz 412146718Sbz if (sap == NULL) 413146718Sbz len = 0; /* Make compiler happy. */ 414146718Sbz else 415146718Sbz len = sap->sg_len - 2; 416146718Sbz 41753498Sjulian /* 41853498Sjulian * If the user used any of these ways to not specify an address 41953498Sjulian * then handle specially. 42053498Sjulian */ 421146718Sbz if ((sap == NULL) || (len <= 0) || (*sap->sg_data == '\0')) { 42270784Sjulian if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) { 42353498Sjulian error = EDESTADDRREQ; 42453498Sjulian goto release; 42553498Sjulian } 42653498Sjulian /* 427163463Sglebius * If exactly one hook exists, just use it. 42853498Sjulian * Special case to allow write(2) to work on an ng_socket. 42953498Sjulian */ 43070784Sjulian hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks); 43153498Sjulian } else { 432125028Sharti if (len >= NG_HOOKSIZ) { 43353498Sjulian error = EINVAL; 43453498Sjulian goto release; 43553498Sjulian } 43652419Sjulian 43753498Sjulian /* 43853498Sjulian * chop off the sockaddr header, and make sure it's NUL 43953498Sjulian * terminated 44053498Sjulian */ 44153498Sjulian bcopy(sap->sg_data, hookname, len); 44253498Sjulian hookname[len] = '\0'; 44352419Sjulian 44453498Sjulian /* Find the correct hook from 'hookname' */ 445163463Sglebius hook = ng_findhook(pcbp->sockdata->node, hookname); 44672053Sjulian if (hook == NULL) { 44753498Sjulian error = EHOSTUNREACH; 448163463Sglebius goto release; 44972053Sjulian } 45052419Sjulian } 45152419Sjulian 452163463Sglebius /* Send data. */ 453163463Sglebius NG_SEND_DATA_FLAGS(error, hook, m, NG_WAITOK); 45452419Sjulian 45552419Sjulianrelease: 45652419Sjulian if (control != NULL) 45752419Sjulian m_freem(control); 45852419Sjulian if (m != NULL) 45952419Sjulian m_freem(m); 46052419Sjulian return (error); 46152419Sjulian} 46252419Sjulian 46352419Sjulianstatic int 46483366Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 46552419Sjulian{ 46652419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 46752419Sjulian 46852419Sjulian if (pcbp == 0) 46952419Sjulian return (EINVAL); 47052419Sjulian return (ng_connect_data(nam, pcbp)); 47152419Sjulian} 47252419Sjulian 47352419Sjulian/* 47452419Sjulian * Used for both data and control sockets 47552419Sjulian */ 47652419Sjulianstatic int 477169462Srwatsonng_getsockaddr(struct socket *so, struct sockaddr **addr) 47852419Sjulian{ 47953098Sbrian struct ngpcb *pcbp; 48053098Sbrian struct sockaddr_ng *sg; 481151975Sglebius int sg_len; 482151975Sglebius int error = 0; 48352419Sjulian 48453098Sbrian /* Why isn't sg_data a `char[1]' ? :-( */ 48553098Sbrian sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1; 48653098Sbrian 48753098Sbrian pcbp = sotongpcb(so); 488151975Sglebius if ((pcbp == NULL) || (pcbp->sockdata == NULL)) 489151975Sglebius /* XXXGL: can this still happen? */ 49052419Sjulian return (EINVAL); 49153098Sbrian 492151975Sglebius mtx_lock(&pcbp->sockdata->mtx); 493151975Sglebius if (pcbp->sockdata->node != NULL) { 494151975Sglebius node_p node = pcbp->sockdata->node; 495151975Sglebius int namelen = 0; /* silence compiler! */ 49653098Sbrian 497151975Sglebius if (NG_NODE_HAS_NAME(node)) 498151975Sglebius sg_len += namelen = strlen(NG_NODE_NAME(node)); 49953098Sbrian 500151975Sglebius sg = malloc(sg_len, M_SONAME, M_WAITOK | M_ZERO); 50153098Sbrian 502151975Sglebius if (NG_NODE_HAS_NAME(node)) 503151975Sglebius bcopy(NG_NODE_NAME(node), sg->sg_data, namelen); 50453098Sbrian 505151975Sglebius sg->sg_len = sg_len; 506151975Sglebius sg->sg_family = AF_NETGRAPH; 507151975Sglebius *addr = (struct sockaddr *)sg; 508151975Sglebius mtx_unlock(&pcbp->sockdata->mtx); 509151975Sglebius } else { 510151975Sglebius mtx_unlock(&pcbp->sockdata->mtx); 511151975Sglebius error = EINVAL; 512151975Sglebius } 513151975Sglebius 514151975Sglebius return (error); 51552419Sjulian} 51652419Sjulian 51752419Sjulian/* 51852419Sjulian * Attach a socket to it's protocol specific partner. 51952419Sjulian * For a control socket, actually create a netgraph node and attach 52052419Sjulian * to it as well. 52152419Sjulian */ 52252419Sjulian 52352419Sjulianstatic int 52452419Sjulianng_attach_cntl(struct socket *so) 52552419Sjulian{ 526151975Sglebius struct ngsock *priv; 52752419Sjulian struct ngpcb *pcbp; 52852419Sjulian int error; 52952419Sjulian 530151975Sglebius /* Allocate node private info */ 531163463Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO); 532151975Sglebius 53352419Sjulian /* Setup protocol control block */ 534151975Sglebius if ((error = ng_attach_common(so, NG_CONTROL)) != 0) { 535163463Sglebius free(priv, M_NETGRAPH_SOCK); 53652419Sjulian return (error); 537151975Sglebius } 53853526Sjulian pcbp = sotongpcb(so); 53952419Sjulian 540151975Sglebius /* Link the pcb the private data. */ 541151975Sglebius priv->ctlsock = pcbp; 542151975Sglebius pcbp->sockdata = priv; 543151975Sglebius priv->refs++; 54452419Sjulian 545151975Sglebius /* Initialize mutex. */ 546151975Sglebius mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF); 547151975Sglebius 54852419Sjulian /* Make the generic node components */ 549151975Sglebius if ((error = ng_make_node_common(&typestruct, &priv->node)) != 0) { 550163463Sglebius free(priv, M_NETGRAPH_SOCK); 551151975Sglebius ng_detach_common(pcbp, NG_CONTROL); 55252419Sjulian return (error); 55352419Sjulian } 55452419Sjulian 555151975Sglebius /* Link the node and the private data. */ 556151975Sglebius NG_NODE_SET_PRIVATE(priv->node, priv); 557151975Sglebius NG_NODE_REF(priv->node); 558151975Sglebius priv->refs++; 559147774Sglebius 56052419Sjulian return (0); 56152419Sjulian} 56252419Sjulian 56352419Sjulianstatic int 56452419Sjulianng_attach_data(struct socket *so) 56552419Sjulian{ 566163463Sglebius return (ng_attach_common(so, NG_DATA)); 56752419Sjulian} 56852419Sjulian 56952419Sjulian/* 57052419Sjulian * Set up a socket protocol control block. 57152419Sjulian * This code is shared between control and data sockets. 57252419Sjulian */ 57352419Sjulianstatic int 57452419Sjulianng_attach_common(struct socket *so, int type) 57552419Sjulian{ 57652419Sjulian struct ngpcb *pcbp; 57752419Sjulian int error; 57852419Sjulian 579163463Sglebius /* Standard socket setup stuff. */ 58052419Sjulian error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace); 58152419Sjulian if (error) 58252419Sjulian return (error); 58352419Sjulian 584163463Sglebius /* Allocate the pcb. */ 585163463Sglebius pcbp = malloc(sizeof(struct ngpcb), M_PCB, M_WAITOK | M_ZERO); 58652419Sjulian pcbp->type = type; 58752419Sjulian 588163463Sglebius /* Link the pcb and the socket. */ 589163463Sglebius so->so_pcb = (caddr_t)pcbp; 59052419Sjulian pcbp->ng_socket = so; 59152419Sjulian 592205082Sglebius /* Add the socket to linked list */ 593205082Sglebius mtx_lock(&ngsocketlist_mtx); 594205082Sglebius LIST_INSERT_HEAD(&ngsocklist, pcbp, socks); 595205082Sglebius mtx_unlock(&ngsocketlist_mtx); 59652419Sjulian return (0); 59752419Sjulian} 59852419Sjulian 59952419Sjulian/* 60052419Sjulian * Disassociate the socket from it's protocol specific 60152419Sjulian * partner. If it's attached to a node's private data structure, 60252419Sjulian * then unlink from that too. If we were the last socket attached to it, 60352419Sjulian * then shut down the entire node. Shared code for control and data sockets. 60452419Sjulian */ 60552419Sjulianstatic void 606151975Sglebiusng_detach_common(struct ngpcb *pcbp, int which) 60752419Sjulian{ 608151975Sglebius struct ngsock *priv = pcbp->sockdata; 60952419Sjulian 610151975Sglebius if (priv != NULL) { 611151975Sglebius mtx_lock(&priv->mtx); 612146290Sglebius 61352419Sjulian switch (which) { 61452419Sjulian case NG_CONTROL: 61572053Sjulian priv->ctlsock = NULL; 61652419Sjulian break; 61752419Sjulian case NG_DATA: 61872053Sjulian priv->datasock = NULL; 61952419Sjulian break; 62052419Sjulian default: 62187599Sobrien panic(__func__); 62252419Sjulian } 623151975Sglebius pcbp->sockdata = NULL; 624151975Sglebius 625151975Sglebius ng_socket_free_priv(priv); 62652419Sjulian } 627151975Sglebius 62852419Sjulian pcbp->ng_socket->so_pcb = NULL; 629205082Sglebius mtx_lock(&ngsocketlist_mtx); 630205082Sglebius LIST_REMOVE(pcbp, socks); 631205082Sglebius mtx_unlock(&ngsocketlist_mtx); 632163463Sglebius free(pcbp, M_PCB); 63352419Sjulian} 63452419Sjulian 635151975Sglebius/* 636151975Sglebius * Remove a reference from node private data. 637151975Sglebius */ 638151975Sglebiusstatic void 639151975Sglebiusng_socket_free_priv(struct ngsock *priv) 640151975Sglebius{ 641151975Sglebius mtx_assert(&priv->mtx, MA_OWNED); 642151975Sglebius 643151975Sglebius priv->refs--; 644151975Sglebius 645151975Sglebius if (priv->refs == 0) { 646151975Sglebius mtx_destroy(&priv->mtx); 647163463Sglebius free(priv, M_NETGRAPH_SOCK); 648151975Sglebius return; 649151975Sglebius } 650151975Sglebius 651151975Sglebius if ((priv->refs == 1) && (priv->node != NULL)) { 652151975Sglebius node_p node = priv->node; 653151975Sglebius 654151975Sglebius priv->node = NULL; 655151975Sglebius mtx_unlock(&priv->mtx); 656151975Sglebius NG_NODE_UNREF(node); 657151975Sglebius ng_rmnode_self(node); 658151975Sglebius } else 659151975Sglebius mtx_unlock(&priv->mtx); 660151975Sglebius} 661151975Sglebius 66252419Sjulian#ifdef NOTYET 66352419Sjulian/* 664108533Sschweikh * File descriptors can be passed into an AF_NETGRAPH socket. 66552419Sjulian * Note, that file descriptors cannot be passed OUT. 66652419Sjulian * Only character device descriptors are accepted. 66752419Sjulian * Character devices are useful to connect a graph to a device, 66852419Sjulian * which after all is the purpose of this whole system. 66952419Sjulian */ 67052419Sjulianstatic int 67183366Sjulianng_internalize(struct mbuf *control, struct thread *td) 67252419Sjulian{ 67397897Sarchie const struct cmsghdr *cm = mtod(control, const struct cmsghdr *); 67452419Sjulian struct file *fp; 67552419Sjulian struct vnode *vn; 67652419Sjulian int oldfds; 67752419Sjulian int fd; 67852419Sjulian 67952419Sjulian if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 68052419Sjulian cm->cmsg_len != control->m_len) { 68152419Sjulian TRAP_ERROR; 68252419Sjulian return (EINVAL); 68352419Sjulian } 68452419Sjulian 68552419Sjulian /* Check there is only one FD. XXX what would more than one signify? */ 68684472Sdwmalone oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int); 68752419Sjulian if (oldfds != 1) { 68852419Sjulian TRAP_ERROR; 68952419Sjulian return (EINVAL); 69052419Sjulian } 69152419Sjulian 69252419Sjulian /* Check that the FD given is legit. and change it to a pointer to a 69352419Sjulian * struct file. */ 69484472Sdwmalone fd = CMSG_DATA(cm); 69589319Salfred if ((error = fget(td, fd, &fp)) != 0) 69689319Salfred return (error); 69752419Sjulian 69852419Sjulian /* Depending on what kind of resource it is, act differently. For 699108533Sschweikh * devices, we treat it as a file. For an AF_NETGRAPH socket, 70052419Sjulian * shortcut straight to the node. */ 70152419Sjulian switch (fp->f_type) { 70252419Sjulian case DTYPE_VNODE: 703109153Sdillon vn = fp->f_data; 70452419Sjulian if (vn && (vn->v_type == VCHR)) { 70552419Sjulian /* for a VCHR, actually reference the FILE */ 706174988Sjeff fhold(fp); 70752419Sjulian /* XXX then what :) */ 70852419Sjulian /* how to pass on to other modules? */ 70952419Sjulian } else { 71089306Salfred fdrop(fp, td); 71152419Sjulian TRAP_ERROR; 71252419Sjulian return (EINVAL); 71352419Sjulian } 71452419Sjulian break; 71552419Sjulian default: 71689306Salfred fdrop(fp, td); 71752419Sjulian TRAP_ERROR; 71852419Sjulian return (EINVAL); 71952419Sjulian } 72089306Salfred fdrop(fp, td); 72152419Sjulian return (0); 72252419Sjulian} 72352419Sjulian#endif /* NOTYET */ 72452419Sjulian 72552419Sjulian/* 72652419Sjulian * Connect the data socket to a named control socket node. 72752419Sjulian */ 72852419Sjulianstatic int 72952419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) 73052419Sjulian{ 73152419Sjulian struct sockaddr_ng *sap; 73252419Sjulian node_p farnode; 73372053Sjulian struct ngsock *priv; 73452419Sjulian int error; 73570700Sjulian item_p item; 73652419Sjulian 737163463Sglebius /* If we are already connected, don't do it again. */ 73852419Sjulian if (pcbp->sockdata != NULL) 73952419Sjulian return (EISCONN); 74052419Sjulian 741163463Sglebius /* 742163463Sglebius * Find the target (victim) and check it doesn't already have 743163463Sglebius * a data socket. Also check it is a 'socket' type node. 744163463Sglebius * Use ng_package_data() and ng_address_path() to do this. 74570700Sjulian */ 74670700Sjulian 74752419Sjulian sap = (struct sockaddr_ng *) nam; 748163463Sglebius /* The item will hold the node reference. */ 749146284Sglebius item = ng_package_data(NULL, NG_WAITOK); 750163463Sglebius 751102244Sarchie if ((error = ng_address_path(NULL, item, sap->sg_data, 0))) 75270700Sjulian return (error); /* item is freed on failure */ 75352419Sjulian 75470700Sjulian /* 75570784Sjulian * Extract node from item and free item. Remember we now have 75670700Sjulian * a reference on the node. The item holds it for us. 75770700Sjulian * when we free the item we release the reference. 75870700Sjulian */ 75970700Sjulian farnode = item->el_dest; /* shortcut */ 76070784Sjulian if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) { 76170700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 76252419Sjulian return (EINVAL); 76370700Sjulian } 76472053Sjulian priv = NG_NODE_PRIVATE(farnode); 76572053Sjulian if (priv->datasock != NULL) { 76670700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 76752419Sjulian return (EADDRINUSE); 76870700Sjulian } 76952419Sjulian 77070700Sjulian /* 77170700Sjulian * Link the PCB and the private data struct. and note the extra 77270700Sjulian * reference. Drop the extra reference on the node. 77370700Sjulian */ 774151975Sglebius mtx_lock(&priv->mtx); 77572053Sjulian priv->datasock = pcbp; 77672053Sjulian pcbp->sockdata = priv; 777151975Sglebius priv->refs++; 778151975Sglebius mtx_unlock(&priv->mtx); 77970700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 78052419Sjulian return (0); 78152419Sjulian} 78252419Sjulian 78352419Sjulian/* 78452419Sjulian * Binding a socket means giving the corresponding node a name 78552419Sjulian */ 78652419Sjulianstatic int 78752419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp) 78852419Sjulian{ 78972053Sjulian struct ngsock *const priv = pcbp->sockdata; 79052419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; 79152419Sjulian 79272053Sjulian if (priv == NULL) { 79352419Sjulian TRAP_ERROR; 79452419Sjulian return (EINVAL); 79552419Sjulian } 796163463Sglebius if ((sap->sg_len < 4) || (sap->sg_len > (NG_NODESIZ + 2)) || 797163463Sglebius (sap->sg_data[0] == '\0') || 798163463Sglebius (sap->sg_data[sap->sg_len - 3] != '\0')) { 79952419Sjulian TRAP_ERROR; 80052419Sjulian return (EINVAL); 80152419Sjulian } 80272053Sjulian return (ng_name_node(priv->node, sap->sg_data)); 80352419Sjulian} 80452419Sjulian 805147774Sglebius/*************************************************************** 806147774Sglebius Netgraph node 807147774Sglebius***************************************************************/ 808147774Sglebius 80952419Sjulian/* 81052419Sjulian * You can only create new nodes from the socket end of things. 81152419Sjulian */ 81252419Sjulianstatic int 81370700Sjulianngs_constructor(node_p nodep) 81452419Sjulian{ 81552419Sjulian return (EINVAL); 81652419Sjulian} 81752419Sjulian 81852419Sjulian/* 81952419Sjulian * We allow any hook to be connected to the node. 82052419Sjulian * There is no per-hook private information though. 82152419Sjulian */ 82252419Sjulianstatic int 82352419Sjulianngs_newhook(node_p node, hook_p hook, const char *name) 82452419Sjulian{ 82570784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 82652419Sjulian return (0); 82752419Sjulian} 82852419Sjulian 829163463Sglebius/* 830163463Sglebius * If only one hook, allow read(2) and write(2) to work. 83172053Sjulian */ 83272053Sjulianstatic int 83372053Sjulianngs_connect(hook_p hook) 83472053Sjulian{ 83572053Sjulian node_p node = NG_HOOK_NODE(hook); 83672053Sjulian struct ngsock *priv = NG_NODE_PRIVATE(node); 83772053Sjulian 838163463Sglebius if ((priv->datasock) && (priv->datasock->ng_socket)) { 839163463Sglebius if (NG_NODE_NUMHOOKS(node) == 1) 84072053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 841163463Sglebius else 84272053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 84372053Sjulian } 84472053Sjulian return (0); 84572053Sjulian} 84672053Sjulian 84752419Sjulian/* 84852419Sjulian * Incoming messages get passed up to the control socket. 84952885Sjulian * Unless they are for us specifically (socket_type) 85052419Sjulian */ 85152419Sjulianstatic int 85270700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook) 85352419Sjulian{ 85472053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 85572053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 856163475Sglebius struct socket *so; 857163468Sglebius struct sockaddr_ng addr; 858163468Sglebius struct ng_mesg *msg; 859163468Sglebius struct mbuf *m; 860163468Sglebius ng_ID_t retaddr = NGI_RETADDR(item); 86152419Sjulian int addrlen; 86252419Sjulian int error = 0; 86352419Sjulian 86470700Sjulian NGI_GET_MSG(item, msg); 865163468Sglebius NG_FREE_ITEM(item); 86670700Sjulian 867163468Sglebius /* 868163468Sglebius * Only allow mesgs to be passed if we have the control socket. 869163468Sglebius * Data sockets can only support the generic messages. 870163468Sglebius */ 87152419Sjulian if (pcbp == NULL) { 87252419Sjulian TRAP_ERROR; 873163468Sglebius NG_FREE_MSG(msg); 87452419Sjulian return (EINVAL); 87552419Sjulian } 876163475Sglebius so = pcbp->ng_socket; 877146296Sglebius 87870784Sjulian#ifdef TRACE_MESSAGES 879146296Sglebius printf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n", 880146296Sglebius retaddr, 881146296Sglebius msg->header.typecookie, 882146296Sglebius msg->header.cmd, 883146296Sglebius msg->header.cmdstr, 884146296Sglebius msg->header.flags, 885146296Sglebius msg->header.token); 88670784Sjulian#endif 88770784Sjulian 88852885Sjulian if (msg->header.typecookie == NGM_SOCKET_COOKIE) { 88952885Sjulian switch (msg->header.cmd) { 89052885Sjulian case NGM_SOCK_CMD_NOLINGER: 89172053Sjulian priv->flags |= NGS_FLAG_NOLINGER; 89252885Sjulian break; 89352885Sjulian case NGM_SOCK_CMD_LINGER: 89472053Sjulian priv->flags &= ~NGS_FLAG_NOLINGER; 89552885Sjulian break; 89652885Sjulian default: 89752885Sjulian error = EINVAL; /* unknown command */ 89852885Sjulian } 899163468Sglebius /* Free the message and return. */ 90070700Sjulian NG_FREE_MSG(msg); 901163468Sglebius return (error); 902163468Sglebius } 90352885Sjulian 904163468Sglebius /* Get the return address into a sockaddr. */ 905163468Sglebius bzero(&addr, sizeof(addr)); 906163468Sglebius addr.sg_len = sizeof(addr); 907163468Sglebius addr.sg_family = AF_NETGRAPH; 908163468Sglebius addrlen = snprintf((char *)&addr.sg_data, sizeof(addr.sg_data), 909163468Sglebius "[%x]:", retaddr); 910163468Sglebius if (addrlen < 0 || addrlen > sizeof(addr.sg_data)) { 911163468Sglebius printf("%s: snprintf([%x]) failed - %d\n", __func__, retaddr, 912163468Sglebius addrlen); 913163468Sglebius NG_FREE_MSG(msg); 914163468Sglebius return (EINVAL); 91552885Sjulian } 916163468Sglebius 917163468Sglebius /* Copy the message itself into an mbuf chain. */ 918163468Sglebius m = m_devget((caddr_t)msg, sizeof(struct ng_mesg) + msg->header.arglen, 919163468Sglebius 0, NULL, NULL); 920163468Sglebius 921163468Sglebius /* 922163468Sglebius * Here we free the message. We need to do that 923163468Sglebius * regardless of whether we got mbufs. 924163468Sglebius */ 925163468Sglebius NG_FREE_MSG(msg); 926163468Sglebius 927163468Sglebius if (m == NULL) { 92852419Sjulian TRAP_ERROR; 929163468Sglebius return (ENOBUFS); 93052419Sjulian } 93152419Sjulian 932163468Sglebius /* Send it up to the socket. */ 933163468Sglebius if (sbappendaddr(&so->so_rcv, (struct sockaddr *)&addr, m, NULL) == 0) { 934163468Sglebius TRAP_ERROR; 935163468Sglebius m_freem(m); 936177071Smav return (ENOBUFS); 937163468Sglebius } 938163468Sglebius sorwakeup(so); 939163468Sglebius 94052419Sjulian return (error); 94152419Sjulian} 94252419Sjulian 94352419Sjulian/* 94452419Sjulian * Receive data on a hook 94552419Sjulian */ 94652419Sjulianstatic int 94770700Sjulianngs_rcvdata(hook_p hook, item_p item) 94852419Sjulian{ 94972053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 95072053Sjulian struct ngpcb *const pcbp = priv->datasock; 95152419Sjulian struct socket *so; 95252419Sjulian struct sockaddr_ng *addr; 953125028Sharti char *addrbuf[NG_HOOKSIZ + 4]; 95452419Sjulian int addrlen; 95570700Sjulian struct mbuf *m; 95652419Sjulian 95770700Sjulian NGI_GET_M(item, m); 95870700Sjulian NG_FREE_ITEM(item); 959163463Sglebius 960163463Sglebius /* If there is no data socket, black-hole it. */ 96152419Sjulian if (pcbp == NULL) { 96270700Sjulian NG_FREE_M(m); 96352419Sjulian return (0); 96452419Sjulian } 96552419Sjulian so = pcbp->ng_socket; 96652419Sjulian 96752419Sjulian /* Get the return address into a sockaddr. */ 968125028Sharti addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKSIZ - 1 */ 96952419Sjulian addr = (struct sockaddr_ng *) addrbuf; 97052419Sjulian addr->sg_len = addrlen + 3; 97152419Sjulian addr->sg_family = AF_NETGRAPH; 97270784Sjulian bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); 97352419Sjulian addr->sg_data[addrlen] = '\0'; 97452419Sjulian 975163463Sglebius /* Try to tell the socket which hook it came in on. */ 976163463Sglebius if (sbappendaddr(&so->so_rcv, (struct sockaddr *)addr, m, NULL) == 0) { 97752419Sjulian m_freem(m); 97852419Sjulian TRAP_ERROR; 97952419Sjulian return (ENOBUFS); 98052419Sjulian } 98152419Sjulian sorwakeup(so); 98252419Sjulian return (0); 98352419Sjulian} 98452419Sjulian 98552419Sjulian/* 98653498Sjulian * Hook disconnection 98752885Sjulian * 98852885Sjulian * For this type, removal of the last link destroys the node 98952885Sjulian * if the NOLINGER flag is set. 99052885Sjulian */ 99152885Sjulianstatic int 99252885Sjulianngs_disconnect(hook_p hook) 99352885Sjulian{ 99472053Sjulian node_p node = NG_HOOK_NODE(hook); 99572053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 99652885Sjulian 997163463Sglebius if ((priv->datasock) && (priv->datasock->ng_socket)) { 998163463Sglebius if (NG_NODE_NUMHOOKS(node) == 1) 99972053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 1000163463Sglebius else 100172053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 100252885Sjulian } 100372053Sjulian 1004163463Sglebius if ((priv->flags & NGS_FLAG_NOLINGER) && 1005163463Sglebius (NG_NODE_NUMHOOKS(node) == 0) && (NG_NODE_IS_VALID(node))) 100672053Sjulian ng_rmnode_self(node); 1007163463Sglebius 100852885Sjulian return (0); 100952885Sjulian} 101052885Sjulian 101152885Sjulian/* 101252419Sjulian * Do local shutdown processing. 101352419Sjulian * In this case, that involves making sure the socket 101452419Sjulian * knows we should be shutting down. 101552419Sjulian */ 101652419Sjulianstatic int 101770700Sjulianngs_shutdown(node_p node) 101852419Sjulian{ 101972053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 102072053Sjulian struct ngpcb *const dpcbp = priv->datasock; 102172053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 102252419Sjulian 1023151975Sglebius if (dpcbp != NULL) 102452419Sjulian soisdisconnected(dpcbp->ng_socket); 1025151975Sglebius 1026151975Sglebius if (pcbp != NULL) 102752419Sjulian soisdisconnected(pcbp->ng_socket); 1028151975Sglebius 1029151975Sglebius mtx_lock(&priv->mtx); 1030151975Sglebius priv->node = NULL; 103170784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 1032151975Sglebius ng_socket_free_priv(priv); 1033151975Sglebius 103470784Sjulian NG_NODE_UNREF(node); 103552419Sjulian return (0); 103652419Sjulian} 103752419Sjulian 1038147774Sglebiusstatic void 1039147774Sglebiusng_socket_item_applied(void *context, int error) 1040147774Sglebius{ 1041147774Sglebius struct ngsock *const priv = (struct ngsock *)context; 1042147774Sglebius 1043147774Sglebius mtx_lock(&priv->mtx); 1044147774Sglebius priv->error = error; 1045147774Sglebius wakeup(priv); 1046147774Sglebius mtx_unlock(&priv->mtx); 1047147774Sglebius 1048147774Sglebius} 1049147774Sglebius 105072055Sjulianstatic int 105172055Sjuliandummy_disconnect(struct socket *so) 105272055Sjulian{ 105372055Sjulian return (0); 105472055Sjulian} 105552419Sjulian/* 105652419Sjulian * Control and data socket type descriptors 1057160549Srwatson * 1058160549Srwatson * XXXRW: Perhaps _close should do something? 105952419Sjulian */ 106052419Sjulian 106152419Sjulianstatic struct pr_usrreqs ngc_usrreqs = { 1062137386Sphk .pru_abort = NULL, 1063137386Sphk .pru_attach = ngc_attach, 1064137386Sphk .pru_bind = ngc_bind, 1065137386Sphk .pru_connect = ngc_connect, 1066137386Sphk .pru_detach = ngc_detach, 1067137386Sphk .pru_disconnect = dummy_disconnect, 1068137386Sphk .pru_peeraddr = NULL, 1069137386Sphk .pru_send = ngc_send, 1070137386Sphk .pru_shutdown = NULL, 1071169462Srwatson .pru_sockaddr = ng_getsockaddr, 1072160549Srwatson .pru_close = NULL, 107352419Sjulian}; 107452419Sjulian 107552419Sjulianstatic struct pr_usrreqs ngd_usrreqs = { 1076137386Sphk .pru_abort = NULL, 1077137386Sphk .pru_attach = ngd_attach, 1078137386Sphk .pru_bind = NULL, 1079137386Sphk .pru_connect = ngd_connect, 1080137386Sphk .pru_detach = ngd_detach, 1081137386Sphk .pru_disconnect = dummy_disconnect, 1082137386Sphk .pru_peeraddr = NULL, 1083137386Sphk .pru_send = ngd_send, 1084137386Sphk .pru_shutdown = NULL, 1085169462Srwatson .pru_sockaddr = ng_getsockaddr, 1086160549Srwatson .pru_close = NULL, 108752419Sjulian}; 108852419Sjulian 108952419Sjulian/* 109052419Sjulian * Definitions of protocols supported in the NETGRAPH domain. 109152419Sjulian */ 109252419Sjulian 109352419Sjulianextern struct domain ngdomain; /* stop compiler warnings */ 109452419Sjulian 109552419Sjulianstatic struct protosw ngsw[] = { 1096152242Sru{ 1097152242Sru .pr_type = SOCK_DGRAM, 1098152242Sru .pr_domain = &ngdomain, 1099152242Sru .pr_protocol = NG_CONTROL, 1100152242Sru .pr_flags = PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, 1101152242Sru .pr_usrreqs = &ngc_usrreqs 1102152242Sru}, 1103152242Sru{ 1104152242Sru .pr_type = SOCK_DGRAM, 1105152242Sru .pr_domain = &ngdomain, 1106152242Sru .pr_protocol = NG_DATA, 1107152242Sru .pr_flags = PR_ATOMIC | PR_ADDR, 1108152242Sru .pr_usrreqs = &ngd_usrreqs 1109152242Sru} 111052419Sjulian}; 111152419Sjulian 111252419Sjulianstruct domain ngdomain = { 1113152242Sru .dom_family = AF_NETGRAPH, 1114152242Sru .dom_name = "netgraph", 1115152242Sru .dom_protosw = ngsw, 1116152242Sru .dom_protoswNPROTOSW = &ngsw[sizeof(ngsw) / sizeof(ngsw[0])] 111752419Sjulian}; 111852419Sjulian 111952419Sjulian/* 1120163463Sglebius * Handle loading and unloading for this node type. 112152419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition). 112252419Sjulian */ 112352419Sjulianstatic int 112452419Sjulianngs_mod_event(module_t mod, int event, void *data) 112552419Sjulian{ 112652419Sjulian int error = 0; 112752419Sjulian 112852419Sjulian switch (event) { 112952419Sjulian case MOD_LOAD: 1130205082Sglebius mtx_init(&ngsocketlist_mtx, "ng_socketlist", NULL, MTX_DEF); 113152419Sjulian break; 113252419Sjulian case MOD_UNLOAD: 1133205082Sglebius /* Ensure there are no open netgraph sockets. */ 1134205082Sglebius if (!LIST_EMPTY(&ngsocklist)) { 1135205082Sglebius error = EBUSY; 1136205082Sglebius break; 1137205082Sglebius } 113852419Sjulian#ifdef NOTYET 113952419Sjulian /* Unregister protocol domain XXX can't do this yet.. */ 114052419Sjulian#endif 1141195837Srwatson error = EBUSY; 114252419Sjulian break; 114352419Sjulian default: 114452419Sjulian error = EOPNOTSUPP; 114552419Sjulian break; 114652419Sjulian } 114752419Sjulian return (error); 114852419Sjulian} 114952419Sjulian 1150195837SrwatsonVNET_DOMAIN_SET(ng); 1151195837Srwatson 115252419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, ""); 115352419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); 115452419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, ""); 115552419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); 115652419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, ""); 115752419Sjulian 1158