ng_socket.c revision 177071
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 177071 2008-03-11 21:58:48Z mav $ 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 7052419Sjulian#include <netgraph/ng_message.h> 7152419Sjulian#include <netgraph/netgraph.h> 7252919Sjulian#include <netgraph/ng_socketvar.h> 7352419Sjulian#include <netgraph/ng_socket.h> 7452419Sjulian 7570870Sjulian#ifdef NG_SEPARATE_MALLOC 7670870SjulianMALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info "); 7770870SjulianMALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info "); 7870870Sjulian#else 7970870Sjulian#define M_NETGRAPH_PATH M_NETGRAPH 8070870Sjulian#define M_NETGRAPH_SOCK M_NETGRAPH 8170870Sjulian#endif 8270870Sjulian 8352419Sjulian/* 8452419Sjulian * It's Ascii-art time! 8552419Sjulian * +-------------+ +-------------+ 8652419Sjulian * |socket (ctl)| |socket (data)| 8752419Sjulian * +-------------+ +-------------+ 8852419Sjulian * ^ ^ 8952419Sjulian * | | 9052419Sjulian * v v 9152419Sjulian * +-----------+ +-----------+ 9252419Sjulian * |pcb (ctl)| |pcb (data)| 9352419Sjulian * +-----------+ +-----------+ 9452419Sjulian * ^ ^ 9552419Sjulian * | | 9652419Sjulian * v v 9752419Sjulian * +--------------------------+ 9852419Sjulian * | Socket type private | 9952419Sjulian * | data | 10052419Sjulian * +--------------------------+ 10152419Sjulian * ^ 10252419Sjulian * | 10352419Sjulian * v 10452419Sjulian * +----------------+ 10552419Sjulian * | struct ng_node | 10652419Sjulian * +----------------+ 10752419Sjulian */ 10852419Sjulian 10952419Sjulian/* Netgraph node methods */ 11052752Sjulianstatic ng_constructor_t ngs_constructor; 11152752Sjulianstatic ng_rcvmsg_t ngs_rcvmsg; 11270700Sjulianstatic ng_shutdown_t ngs_shutdown; 11352752Sjulianstatic ng_newhook_t ngs_newhook; 11472053Sjulianstatic ng_connect_t ngs_connect; 11552752Sjulianstatic ng_rcvdata_t ngs_rcvdata; 11652885Sjulianstatic ng_disconnect_t ngs_disconnect; 11752419Sjulian 11852419Sjulian/* Internal methods */ 11952419Sjulianstatic int ng_attach_data(struct socket *so); 12052419Sjulianstatic int ng_attach_cntl(struct socket *so); 12152419Sjulianstatic int ng_attach_common(struct socket *so, int type); 122151975Sglebiusstatic void ng_detach_common(struct ngpcb *pcbp, int type); 123151975Sglebiusstatic void ng_socket_free_priv(struct ngsock *priv); 124163463Sglebius#ifdef NOTYET 125163463Sglebiusstatic int ng_internalize(struct mbuf *m, struct thread *p); 126163463Sglebius#endif 12752419Sjulianstatic int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp); 12852419Sjulianstatic int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); 12952419Sjulian 13052419Sjulianstatic int ngs_mod_event(module_t mod, int event, void *data); 131147774Sglebiusstatic void ng_socket_item_applied(void *context, int error); 13252419Sjulian 13352419Sjulian/* Netgraph type descriptor */ 13452419Sjulianstatic struct ng_type typestruct = { 135129823Sjulian .version = NG_ABI_VERSION, 136129823Sjulian .name = NG_SOCKET_NODE_TYPE, 137129823Sjulian .mod_event = ngs_mod_event, 138129823Sjulian .constructor = ngs_constructor, 139129823Sjulian .rcvmsg = ngs_rcvmsg, 140129823Sjulian .shutdown = ngs_shutdown, 141129823Sjulian .newhook = ngs_newhook, 142129823Sjulian .connect = ngs_connect, 143129823Sjulian .rcvdata = ngs_rcvdata, 144129823Sjulian .disconnect = ngs_disconnect, 14552419Sjulian}; 146138238SmlaierNETGRAPH_INIT_ORDERED(socket, &typestruct, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 14752419Sjulian 14852419Sjulian/* Buffer space */ 14964512Sarchiestatic u_long ngpdg_sendspace = 20 * 1024; /* really max datagram size */ 150124871SruSYSCTL_INT(_net_graph, OID_AUTO, maxdgram, CTLFLAG_RW, 151124871Sru &ngpdg_sendspace , 0, "Maximum outgoing Netgraph datagram size"); 15252419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024; 153124871SruSYSCTL_INT(_net_graph, OID_AUTO, recvspace, CTLFLAG_RW, 154125116Sru &ngpdg_recvspace , 0, "Maximum space for incoming Netgraph datagrams"); 15552419Sjulian 15653526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb) 15752419Sjulian 158131933Smarcel/* If getting unexplained errors returned, set this to "kdb_enter("X"); */ 15952419Sjulian#ifndef TRAP_ERROR 16052419Sjulian#define TRAP_ERROR 16152419Sjulian#endif 16252419Sjulian 16352419Sjulian/*************************************************************** 16452419Sjulian Control sockets 16552419Sjulian***************************************************************/ 16652419Sjulian 16752419Sjulianstatic int 16883366Sjulianngc_attach(struct socket *so, int proto, struct thread *td) 16952419Sjulian{ 17052419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 171164033Srwatson int error; 17252419Sjulian 173164033Srwatson error = priv_check(td, PRIV_NETGRAPH_CONTROL); 174164033Srwatson if (error) 175164033Srwatson return (error); 17652419Sjulian if (pcbp != NULL) 17752419Sjulian return (EISCONN); 17852419Sjulian return (ng_attach_cntl(so)); 17952419Sjulian} 18052419Sjulian 181157370Srwatsonstatic void 18252419Sjulianngc_detach(struct socket *so) 18352419Sjulian{ 18452419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 18552419Sjulian 186157370Srwatson KASSERT(pcbp != NULL, ("ngc_detach: pcbp == NULL")); 187151975Sglebius ng_detach_common(pcbp, NG_CONTROL); 18852419Sjulian} 18952419Sjulian 19052419Sjulianstatic int 19152419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 19283366Sjulian struct mbuf *control, struct thread *td) 19352419Sjulian{ 19452419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 195147774Sglebius struct ngsock *const priv = NG_NODE_PRIVATE(pcbp->sockdata->node); 19652419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 19770700Sjulian struct ng_mesg *msg; 19852419Sjulian struct mbuf *m0; 199146317Sglebius item_p item; 20070700Sjulian char *path = NULL; 20152419Sjulian int len, error = 0; 202172806Smav struct ng_apply_info apply; 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 218163463Sglebius /* Require destination as there may be >= 1 hooks on this node. */ 21952419Sjulian if (addr == NULL) { 22052419Sjulian error = EDESTADDRREQ; 22152419Sjulian goto release; 22252419Sjulian } 22352419Sjulian 224163463Sglebius /* 225163463Sglebius * Allocate an expendable buffer for the path, chop off 226163463Sglebius * the sockaddr header, and make sure it's NUL terminated. 227163463Sglebius */ 22852419Sjulian len = sap->sg_len - 2; 229163463Sglebius path = malloc(len + 1, M_NETGRAPH_PATH, M_WAITOK); 23052419Sjulian bcopy(sap->sg_data, path, len); 23152419Sjulian path[len] = '\0'; 23252419Sjulian 233163463Sglebius /* 234163463Sglebius * Move the actual message out of mbufs into a linear buffer. 235163463Sglebius * Start by adding up the size of the data. (could use mh_len?) 236163463Sglebius */ 23752419Sjulian for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next) 23852419Sjulian len += m0->m_len; 23952419Sjulian 240163463Sglebius /* 241163463Sglebius * Move the data into a linear buffer as well. 242163463Sglebius * Messages are not delivered in mbufs. 243163463Sglebius */ 244163463Sglebius msg = malloc(len + 1, M_NETGRAPH_MSG, M_WAITOK); 24570700Sjulian m_copydata(m, 0, len, (char *)msg); 24652419Sjulian 247141308Sglebius if (msg->header.version != NG_VERSION) { 248163463Sglebius free(msg, M_NETGRAPH_MSG); 249141308Sglebius error = EINVAL; 250141308Sglebius goto release; 251141308Sglebius } 252141308Sglebius 253132705Sglebius /* 254132705Sglebius * Hack alert! 255132705Sglebius * We look into the message and if it mkpeers a node of unknown type, we 256132705Sglebius * try to load it. We need to do this now, in syscall thread, because if 257132705Sglebius * message gets queued and applied later we will get panic. 258132705Sglebius */ 259132939Sglebius if (msg->header.typecookie == NGM_GENERIC_COOKIE && 260132939Sglebius msg->header.cmd == NGM_MKPEER) { 261132705Sglebius struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 262132705Sglebius struct ng_type *type; 263132705Sglebius 264132705Sglebius if ((type = ng_findtype(mkp->type)) == NULL) { 265132705Sglebius char filename[NG_TYPESIZ + 3]; 266159590Sjhb int fileid; 267132705Sglebius 268146296Sglebius /* Not found, try to load it as a loadable module. */ 269146296Sglebius snprintf(filename, sizeof(filename), "ng_%s", 270146296Sglebius mkp->type); 271159590Sjhb error = kern_kldload(curthread, filename, &fileid); 272132705Sglebius if (error != 0) { 273163463Sglebius free(msg, M_NETGRAPH_MSG); 274132705Sglebius goto release; 275132705Sglebius } 276132705Sglebius 277146296Sglebius /* See if type has been loaded successfully. */ 278132705Sglebius if ((type = ng_findtype(mkp->type)) == NULL) { 279163463Sglebius free(msg, M_NETGRAPH_MSG); 280159590Sjhb (void)kern_kldunload(curthread, fileid, 281159590Sjhb LINKER_UNLOAD_NORMAL); 282132705Sglebius error = ENXIO; 283132705Sglebius goto release; 284132705Sglebius } 285132705Sglebius } 286132705Sglebius } 287132705Sglebius 288163463Sglebius item = ng_package_msg(msg, M_WAITOK); 289163463Sglebius if ((error = ng_address_path((pcbp->sockdata->node), item, path, 0)) 290163463Sglebius != 0) { 291146296Sglebius#ifdef TRACE_MESSAGES 292146317Sglebius printf("ng_address_path: errx=%d\n", error); 293146317Sglebius#endif 294146317Sglebius goto release; 295146317Sglebius } 296146296Sglebius 297146317Sglebius#ifdef TRACE_MESSAGES 298146317Sglebius printf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n", 299146317Sglebius item->el_dest->nd_ID, 300146317Sglebius msg->header.typecookie, 301146317Sglebius msg->header.cmd, 302146317Sglebius msg->header.cmdstr, 303146317Sglebius msg->header.flags, 304146317Sglebius msg->header.token, 305146317Sglebius item->el_dest->nd_type->name); 30670784Sjulian#endif 307146317Sglebius SAVE_LINE(item); 308147774Sglebius /* 309147774Sglebius * We do not want to return from syscall until the item 310147774Sglebius * is processed by destination node. We register callback 311147774Sglebius * on the item, which will update priv->error when item 312147774Sglebius * was applied. 313147774Sglebius * If ng_snd_item() has queued item, we sleep until 314147774Sglebius * callback wakes us up. 315147774Sglebius */ 316172806Smav bzero(&apply, sizeof(apply)); 317172806Smav apply.apply = ng_socket_item_applied; 318172806Smav apply.context = priv; 319172806Smav item->apply = &apply; 320147774Sglebius priv->error = -1; 321146296Sglebius 322172806Smav error = ng_snd_item(item, 0); 323147774Sglebius 324172806Smav mtx_lock(&priv->mtx); 325172806Smav if (priv->error == -1) 326172806Smav msleep(priv, &priv->mtx, 0, "ngsock", 0); 327172806Smav mtx_unlock(&priv->mtx); 328172806Smav KASSERT(priv->error != -1, 329172806Smav ("ng_socket: priv->error wasn't updated")); 330172806Smav error = priv->error; 331147774Sglebius 33252419Sjulianrelease: 33352419Sjulian if (path != NULL) 334163463Sglebius free(path, M_NETGRAPH_PATH); 33552419Sjulian if (control != NULL) 33652419Sjulian m_freem(control); 33752419Sjulian if (m != NULL) 33852419Sjulian m_freem(m); 33952419Sjulian return (error); 34052419Sjulian} 34152419Sjulian 34252419Sjulianstatic int 34383366Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 34452419Sjulian{ 34552419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 34652419Sjulian 34752419Sjulian if (pcbp == 0) 34852419Sjulian return (EINVAL); 34952419Sjulian return (ng_bind(nam, pcbp)); 35052419Sjulian} 35152419Sjulian 35252419Sjulianstatic int 35383366Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 35452419Sjulian{ 35570700Sjulian /* 35670784Sjulian * At this time refuse to do this.. it used to 35770700Sjulian * do something but it was undocumented and not used. 35870700Sjulian */ 359163463Sglebius printf("program tried to connect control socket to remote node\n"); 36070700Sjulian return (EINVAL); 36152419Sjulian} 36252419Sjulian 36352419Sjulian/*************************************************************** 36452419Sjulian Data sockets 36552419Sjulian***************************************************************/ 36652419Sjulian 36752419Sjulianstatic int 36883366Sjulianngd_attach(struct socket *so, int proto, struct thread *td) 36952419Sjulian{ 37052419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 37152419Sjulian 37252419Sjulian if (pcbp != NULL) 37352419Sjulian return (EISCONN); 37452419Sjulian return (ng_attach_data(so)); 37552419Sjulian} 37652419Sjulian 377157370Srwatsonstatic void 37852419Sjulianngd_detach(struct socket *so) 37952419Sjulian{ 38052419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 38152419Sjulian 382157558Srwatson KASSERT(pcbp != NULL, ("ngd_detach: pcbp == NULL")); 383151975Sglebius ng_detach_common(pcbp, NG_DATA); 38452419Sjulian} 38552419Sjulian 38652419Sjulianstatic int 38752419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 38883366Sjulian struct mbuf *control, struct thread *td) 38952419Sjulian{ 39052419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 39152419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 392163463Sglebius int len, error; 39353498Sjulian hook_p hook = NULL; 394125028Sharti char hookname[NG_HOOKSIZ]; 39552419Sjulian 39652419Sjulian if ((pcbp == NULL) || (control != NULL)) { 39752419Sjulian error = EINVAL; 39852419Sjulian goto release; 39952419Sjulian } 40052419Sjulian if (pcbp->sockdata == NULL) { 40152419Sjulian error = ENOTCONN; 40252419Sjulian goto release; 40352419Sjulian } 404146718Sbz 405146718Sbz if (sap == NULL) 406146718Sbz len = 0; /* Make compiler happy. */ 407146718Sbz else 408146718Sbz len = sap->sg_len - 2; 409146718Sbz 41053498Sjulian /* 41153498Sjulian * If the user used any of these ways to not specify an address 41253498Sjulian * then handle specially. 41353498Sjulian */ 414146718Sbz if ((sap == NULL) || (len <= 0) || (*sap->sg_data == '\0')) { 41570784Sjulian if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) { 41653498Sjulian error = EDESTADDRREQ; 41753498Sjulian goto release; 41853498Sjulian } 41953498Sjulian /* 420163463Sglebius * If exactly one hook exists, just use it. 42153498Sjulian * Special case to allow write(2) to work on an ng_socket. 42253498Sjulian */ 42370784Sjulian hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks); 42453498Sjulian } else { 425125028Sharti if (len >= NG_HOOKSIZ) { 42653498Sjulian error = EINVAL; 42753498Sjulian goto release; 42853498Sjulian } 42952419Sjulian 43053498Sjulian /* 43153498Sjulian * chop off the sockaddr header, and make sure it's NUL 43253498Sjulian * terminated 43353498Sjulian */ 43453498Sjulian bcopy(sap->sg_data, hookname, len); 43553498Sjulian hookname[len] = '\0'; 43652419Sjulian 43753498Sjulian /* Find the correct hook from 'hookname' */ 438163463Sglebius hook = ng_findhook(pcbp->sockdata->node, hookname); 43972053Sjulian if (hook == NULL) { 44053498Sjulian error = EHOSTUNREACH; 441163463Sglebius goto release; 44272053Sjulian } 44352419Sjulian } 44452419Sjulian 445163463Sglebius /* Send data. */ 446163463Sglebius NG_SEND_DATA_FLAGS(error, hook, m, NG_WAITOK); 44752419Sjulian 44852419Sjulianrelease: 44952419Sjulian if (control != NULL) 45052419Sjulian m_freem(control); 45152419Sjulian if (m != NULL) 45252419Sjulian m_freem(m); 45352419Sjulian return (error); 45452419Sjulian} 45552419Sjulian 45652419Sjulianstatic int 45783366Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 45852419Sjulian{ 45952419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 46052419Sjulian 46152419Sjulian if (pcbp == 0) 46252419Sjulian return (EINVAL); 46352419Sjulian return (ng_connect_data(nam, pcbp)); 46452419Sjulian} 46552419Sjulian 46652419Sjulian/* 46752419Sjulian * Used for both data and control sockets 46852419Sjulian */ 46952419Sjulianstatic int 470169462Srwatsonng_getsockaddr(struct socket *so, struct sockaddr **addr) 47152419Sjulian{ 47253098Sbrian struct ngpcb *pcbp; 47353098Sbrian struct sockaddr_ng *sg; 474151975Sglebius int sg_len; 475151975Sglebius int error = 0; 47652419Sjulian 47753098Sbrian /* Why isn't sg_data a `char[1]' ? :-( */ 47853098Sbrian sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1; 47953098Sbrian 48053098Sbrian pcbp = sotongpcb(so); 481151975Sglebius if ((pcbp == NULL) || (pcbp->sockdata == NULL)) 482151975Sglebius /* XXXGL: can this still happen? */ 48352419Sjulian return (EINVAL); 48453098Sbrian 485151975Sglebius mtx_lock(&pcbp->sockdata->mtx); 486151975Sglebius if (pcbp->sockdata->node != NULL) { 487151975Sglebius node_p node = pcbp->sockdata->node; 488151975Sglebius int namelen = 0; /* silence compiler! */ 48953098Sbrian 490151975Sglebius if (NG_NODE_HAS_NAME(node)) 491151975Sglebius sg_len += namelen = strlen(NG_NODE_NAME(node)); 49253098Sbrian 493151975Sglebius sg = malloc(sg_len, M_SONAME, M_WAITOK | M_ZERO); 49453098Sbrian 495151975Sglebius if (NG_NODE_HAS_NAME(node)) 496151975Sglebius bcopy(NG_NODE_NAME(node), sg->sg_data, namelen); 49753098Sbrian 498151975Sglebius sg->sg_len = sg_len; 499151975Sglebius sg->sg_family = AF_NETGRAPH; 500151975Sglebius *addr = (struct sockaddr *)sg; 501151975Sglebius mtx_unlock(&pcbp->sockdata->mtx); 502151975Sglebius } else { 503151975Sglebius mtx_unlock(&pcbp->sockdata->mtx); 504151975Sglebius error = EINVAL; 505151975Sglebius } 506151975Sglebius 507151975Sglebius return (error); 50852419Sjulian} 50952419Sjulian 51052419Sjulian/* 51152419Sjulian * Attach a socket to it's protocol specific partner. 51252419Sjulian * For a control socket, actually create a netgraph node and attach 51352419Sjulian * to it as well. 51452419Sjulian */ 51552419Sjulian 51652419Sjulianstatic int 51752419Sjulianng_attach_cntl(struct socket *so) 51852419Sjulian{ 519151975Sglebius struct ngsock *priv; 52052419Sjulian struct ngpcb *pcbp; 52152419Sjulian int error; 52252419Sjulian 523151975Sglebius /* Allocate node private info */ 524163463Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO); 525151975Sglebius 52652419Sjulian /* Setup protocol control block */ 527151975Sglebius if ((error = ng_attach_common(so, NG_CONTROL)) != 0) { 528163463Sglebius free(priv, M_NETGRAPH_SOCK); 52952419Sjulian return (error); 530151975Sglebius } 53153526Sjulian pcbp = sotongpcb(so); 53252419Sjulian 533151975Sglebius /* Link the pcb the private data. */ 534151975Sglebius priv->ctlsock = pcbp; 535151975Sglebius pcbp->sockdata = priv; 536151975Sglebius priv->refs++; 53752419Sjulian 538151975Sglebius /* Initialize mutex. */ 539151975Sglebius mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF); 540151975Sglebius 54152419Sjulian /* Make the generic node components */ 542151975Sglebius if ((error = ng_make_node_common(&typestruct, &priv->node)) != 0) { 543163463Sglebius free(priv, M_NETGRAPH_SOCK); 544151975Sglebius ng_detach_common(pcbp, NG_CONTROL); 54552419Sjulian return (error); 54652419Sjulian } 54752419Sjulian 548151975Sglebius /* Link the node and the private data. */ 549151975Sglebius NG_NODE_SET_PRIVATE(priv->node, priv); 550151975Sglebius NG_NODE_REF(priv->node); 551151975Sglebius priv->refs++; 552147774Sglebius 55352419Sjulian return (0); 55452419Sjulian} 55552419Sjulian 55652419Sjulianstatic int 55752419Sjulianng_attach_data(struct socket *so) 55852419Sjulian{ 559163463Sglebius return (ng_attach_common(so, NG_DATA)); 56052419Sjulian} 56152419Sjulian 56252419Sjulian/* 56352419Sjulian * Set up a socket protocol control block. 56452419Sjulian * This code is shared between control and data sockets. 56552419Sjulian */ 56652419Sjulianstatic int 56752419Sjulianng_attach_common(struct socket *so, int type) 56852419Sjulian{ 56952419Sjulian struct ngpcb *pcbp; 57052419Sjulian int error; 57152419Sjulian 572163463Sglebius /* Standard socket setup stuff. */ 57352419Sjulian error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace); 57452419Sjulian if (error) 57552419Sjulian return (error); 57652419Sjulian 577163463Sglebius /* Allocate the pcb. */ 578163463Sglebius pcbp = malloc(sizeof(struct ngpcb), M_PCB, M_WAITOK | M_ZERO); 57952419Sjulian pcbp->type = type; 58052419Sjulian 581163463Sglebius /* Link the pcb and the socket. */ 582163463Sglebius so->so_pcb = (caddr_t)pcbp; 58352419Sjulian pcbp->ng_socket = so; 58452419Sjulian 58552419Sjulian return (0); 58652419Sjulian} 58752419Sjulian 58852419Sjulian/* 58952419Sjulian * Disassociate the socket from it's protocol specific 59052419Sjulian * partner. If it's attached to a node's private data structure, 59152419Sjulian * then unlink from that too. If we were the last socket attached to it, 59252419Sjulian * then shut down the entire node. Shared code for control and data sockets. 59352419Sjulian */ 59452419Sjulianstatic void 595151975Sglebiusng_detach_common(struct ngpcb *pcbp, int which) 59652419Sjulian{ 597151975Sglebius struct ngsock *priv = pcbp->sockdata; 59852419Sjulian 599151975Sglebius if (priv != NULL) { 600151975Sglebius mtx_lock(&priv->mtx); 601146290Sglebius 60252419Sjulian switch (which) { 60352419Sjulian case NG_CONTROL: 60472053Sjulian priv->ctlsock = NULL; 60552419Sjulian break; 60652419Sjulian case NG_DATA: 60772053Sjulian priv->datasock = NULL; 60852419Sjulian break; 60952419Sjulian default: 61087599Sobrien panic(__func__); 61152419Sjulian } 612151975Sglebius pcbp->sockdata = NULL; 613151975Sglebius 614151975Sglebius ng_socket_free_priv(priv); 61552419Sjulian } 616151975Sglebius 61752419Sjulian pcbp->ng_socket->so_pcb = NULL; 618163463Sglebius free(pcbp, M_PCB); 61952419Sjulian} 62052419Sjulian 621151975Sglebius/* 622151975Sglebius * Remove a reference from node private data. 623151975Sglebius */ 624151975Sglebiusstatic void 625151975Sglebiusng_socket_free_priv(struct ngsock *priv) 626151975Sglebius{ 627151975Sglebius mtx_assert(&priv->mtx, MA_OWNED); 628151975Sglebius 629151975Sglebius priv->refs--; 630151975Sglebius 631151975Sglebius if (priv->refs == 0) { 632151975Sglebius mtx_destroy(&priv->mtx); 633163463Sglebius free(priv, M_NETGRAPH_SOCK); 634151975Sglebius return; 635151975Sglebius } 636151975Sglebius 637151975Sglebius if ((priv->refs == 1) && (priv->node != NULL)) { 638151975Sglebius node_p node = priv->node; 639151975Sglebius 640151975Sglebius priv->node = NULL; 641151975Sglebius mtx_unlock(&priv->mtx); 642151975Sglebius NG_NODE_UNREF(node); 643151975Sglebius ng_rmnode_self(node); 644151975Sglebius } else 645151975Sglebius mtx_unlock(&priv->mtx); 646151975Sglebius} 647151975Sglebius 64852419Sjulian#ifdef NOTYET 64952419Sjulian/* 650108533Sschweikh * File descriptors can be passed into an AF_NETGRAPH socket. 65152419Sjulian * Note, that file descriptors cannot be passed OUT. 65252419Sjulian * Only character device descriptors are accepted. 65352419Sjulian * Character devices are useful to connect a graph to a device, 65452419Sjulian * which after all is the purpose of this whole system. 65552419Sjulian */ 65652419Sjulianstatic int 65783366Sjulianng_internalize(struct mbuf *control, struct thread *td) 65852419Sjulian{ 65997897Sarchie const struct cmsghdr *cm = mtod(control, const struct cmsghdr *); 66052419Sjulian struct file *fp; 66152419Sjulian struct vnode *vn; 66252419Sjulian int oldfds; 66352419Sjulian int fd; 66452419Sjulian 66552419Sjulian if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 66652419Sjulian cm->cmsg_len != control->m_len) { 66752419Sjulian TRAP_ERROR; 66852419Sjulian return (EINVAL); 66952419Sjulian } 67052419Sjulian 67152419Sjulian /* Check there is only one FD. XXX what would more than one signify? */ 67284472Sdwmalone oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int); 67352419Sjulian if (oldfds != 1) { 67452419Sjulian TRAP_ERROR; 67552419Sjulian return (EINVAL); 67652419Sjulian } 67752419Sjulian 67852419Sjulian /* Check that the FD given is legit. and change it to a pointer to a 67952419Sjulian * struct file. */ 68084472Sdwmalone fd = CMSG_DATA(cm); 68189319Salfred if ((error = fget(td, fd, &fp)) != 0) 68289319Salfred return (error); 68352419Sjulian 68452419Sjulian /* Depending on what kind of resource it is, act differently. For 685108533Sschweikh * devices, we treat it as a file. For an AF_NETGRAPH socket, 68652419Sjulian * shortcut straight to the node. */ 68752419Sjulian switch (fp->f_type) { 68852419Sjulian case DTYPE_VNODE: 689109153Sdillon vn = fp->f_data; 69052419Sjulian if (vn && (vn->v_type == VCHR)) { 69152419Sjulian /* for a VCHR, actually reference the FILE */ 692174988Sjeff fhold(fp); 69352419Sjulian /* XXX then what :) */ 69452419Sjulian /* how to pass on to other modules? */ 69552419Sjulian } else { 69689306Salfred fdrop(fp, td); 69752419Sjulian TRAP_ERROR; 69852419Sjulian return (EINVAL); 69952419Sjulian } 70052419Sjulian break; 70152419Sjulian default: 70289306Salfred fdrop(fp, td); 70352419Sjulian TRAP_ERROR; 70452419Sjulian return (EINVAL); 70552419Sjulian } 70689306Salfred fdrop(fp, td); 70752419Sjulian return (0); 70852419Sjulian} 70952419Sjulian#endif /* NOTYET */ 71052419Sjulian 71152419Sjulian/* 71252419Sjulian * Connect the data socket to a named control socket node. 71352419Sjulian */ 71452419Sjulianstatic int 71552419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) 71652419Sjulian{ 71752419Sjulian struct sockaddr_ng *sap; 71852419Sjulian node_p farnode; 71972053Sjulian struct ngsock *priv; 72052419Sjulian int error; 72170700Sjulian item_p item; 72252419Sjulian 723163463Sglebius /* If we are already connected, don't do it again. */ 72452419Sjulian if (pcbp->sockdata != NULL) 72552419Sjulian return (EISCONN); 72652419Sjulian 727163463Sglebius /* 728163463Sglebius * Find the target (victim) and check it doesn't already have 729163463Sglebius * a data socket. Also check it is a 'socket' type node. 730163463Sglebius * Use ng_package_data() and ng_address_path() to do this. 73170700Sjulian */ 73270700Sjulian 73352419Sjulian sap = (struct sockaddr_ng *) nam; 734163463Sglebius /* The item will hold the node reference. */ 735146284Sglebius item = ng_package_data(NULL, NG_WAITOK); 736163463Sglebius 737102244Sarchie if ((error = ng_address_path(NULL, item, sap->sg_data, 0))) 73870700Sjulian return (error); /* item is freed on failure */ 73952419Sjulian 74070700Sjulian /* 74170784Sjulian * Extract node from item and free item. Remember we now have 74270700Sjulian * a reference on the node. The item holds it for us. 74370700Sjulian * when we free the item we release the reference. 74470700Sjulian */ 74570700Sjulian farnode = item->el_dest; /* shortcut */ 74670784Sjulian if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) { 74770700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 74852419Sjulian return (EINVAL); 74970700Sjulian } 75072053Sjulian priv = NG_NODE_PRIVATE(farnode); 75172053Sjulian if (priv->datasock != NULL) { 75270700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 75352419Sjulian return (EADDRINUSE); 75470700Sjulian } 75552419Sjulian 75670700Sjulian /* 75770700Sjulian * Link the PCB and the private data struct. and note the extra 75870700Sjulian * reference. Drop the extra reference on the node. 75970700Sjulian */ 760151975Sglebius mtx_lock(&priv->mtx); 76172053Sjulian priv->datasock = pcbp; 76272053Sjulian pcbp->sockdata = priv; 763151975Sglebius priv->refs++; 764151975Sglebius mtx_unlock(&priv->mtx); 76570700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 76652419Sjulian return (0); 76752419Sjulian} 76852419Sjulian 76952419Sjulian/* 77052419Sjulian * Binding a socket means giving the corresponding node a name 77152419Sjulian */ 77252419Sjulianstatic int 77352419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp) 77452419Sjulian{ 77572053Sjulian struct ngsock *const priv = pcbp->sockdata; 77652419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; 77752419Sjulian 77872053Sjulian if (priv == NULL) { 77952419Sjulian TRAP_ERROR; 78052419Sjulian return (EINVAL); 78152419Sjulian } 782163463Sglebius if ((sap->sg_len < 4) || (sap->sg_len > (NG_NODESIZ + 2)) || 783163463Sglebius (sap->sg_data[0] == '\0') || 784163463Sglebius (sap->sg_data[sap->sg_len - 3] != '\0')) { 78552419Sjulian TRAP_ERROR; 78652419Sjulian return (EINVAL); 78752419Sjulian } 78872053Sjulian return (ng_name_node(priv->node, sap->sg_data)); 78952419Sjulian} 79052419Sjulian 791147774Sglebius/*************************************************************** 792147774Sglebius Netgraph node 793147774Sglebius***************************************************************/ 794147774Sglebius 79552419Sjulian/* 79652419Sjulian * You can only create new nodes from the socket end of things. 79752419Sjulian */ 79852419Sjulianstatic int 79970700Sjulianngs_constructor(node_p nodep) 80052419Sjulian{ 80152419Sjulian return (EINVAL); 80252419Sjulian} 80352419Sjulian 80452419Sjulian/* 80552419Sjulian * We allow any hook to be connected to the node. 80652419Sjulian * There is no per-hook private information though. 80752419Sjulian */ 80852419Sjulianstatic int 80952419Sjulianngs_newhook(node_p node, hook_p hook, const char *name) 81052419Sjulian{ 81170784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 81252419Sjulian return (0); 81352419Sjulian} 81452419Sjulian 815163463Sglebius/* 816163463Sglebius * If only one hook, allow read(2) and write(2) to work. 81772053Sjulian */ 81872053Sjulianstatic int 81972053Sjulianngs_connect(hook_p hook) 82072053Sjulian{ 82172053Sjulian node_p node = NG_HOOK_NODE(hook); 82272053Sjulian struct ngsock *priv = NG_NODE_PRIVATE(node); 82372053Sjulian 824163463Sglebius if ((priv->datasock) && (priv->datasock->ng_socket)) { 825163463Sglebius if (NG_NODE_NUMHOOKS(node) == 1) 82672053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 827163463Sglebius else 82872053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 82972053Sjulian } 83072053Sjulian return (0); 83172053Sjulian} 83272053Sjulian 83352419Sjulian/* 83452419Sjulian * Incoming messages get passed up to the control socket. 83552885Sjulian * Unless they are for us specifically (socket_type) 83652419Sjulian */ 83752419Sjulianstatic int 83870700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook) 83952419Sjulian{ 84072053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 84172053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 842163475Sglebius struct socket *so; 843163468Sglebius struct sockaddr_ng addr; 844163468Sglebius struct ng_mesg *msg; 845163468Sglebius struct mbuf *m; 846163468Sglebius ng_ID_t retaddr = NGI_RETADDR(item); 84752419Sjulian int addrlen; 84852419Sjulian int error = 0; 84952419Sjulian 85070700Sjulian NGI_GET_MSG(item, msg); 851163468Sglebius NG_FREE_ITEM(item); 85270700Sjulian 853163468Sglebius /* 854163468Sglebius * Only allow mesgs to be passed if we have the control socket. 855163468Sglebius * Data sockets can only support the generic messages. 856163468Sglebius */ 85752419Sjulian if (pcbp == NULL) { 85852419Sjulian TRAP_ERROR; 859163468Sglebius NG_FREE_MSG(msg); 86052419Sjulian return (EINVAL); 86152419Sjulian } 862163475Sglebius so = pcbp->ng_socket; 863146296Sglebius 86470784Sjulian#ifdef TRACE_MESSAGES 865146296Sglebius printf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n", 866146296Sglebius retaddr, 867146296Sglebius msg->header.typecookie, 868146296Sglebius msg->header.cmd, 869146296Sglebius msg->header.cmdstr, 870146296Sglebius msg->header.flags, 871146296Sglebius msg->header.token); 87270784Sjulian#endif 87370784Sjulian 87452885Sjulian if (msg->header.typecookie == NGM_SOCKET_COOKIE) { 87552885Sjulian switch (msg->header.cmd) { 87652885Sjulian case NGM_SOCK_CMD_NOLINGER: 87772053Sjulian priv->flags |= NGS_FLAG_NOLINGER; 87852885Sjulian break; 87952885Sjulian case NGM_SOCK_CMD_LINGER: 88072053Sjulian priv->flags &= ~NGS_FLAG_NOLINGER; 88152885Sjulian break; 88252885Sjulian default: 88352885Sjulian error = EINVAL; /* unknown command */ 88452885Sjulian } 885163468Sglebius /* Free the message and return. */ 88670700Sjulian NG_FREE_MSG(msg); 887163468Sglebius return (error); 888163468Sglebius } 88952885Sjulian 890163468Sglebius /* Get the return address into a sockaddr. */ 891163468Sglebius bzero(&addr, sizeof(addr)); 892163468Sglebius addr.sg_len = sizeof(addr); 893163468Sglebius addr.sg_family = AF_NETGRAPH; 894163468Sglebius addrlen = snprintf((char *)&addr.sg_data, sizeof(addr.sg_data), 895163468Sglebius "[%x]:", retaddr); 896163468Sglebius if (addrlen < 0 || addrlen > sizeof(addr.sg_data)) { 897163468Sglebius printf("%s: snprintf([%x]) failed - %d\n", __func__, retaddr, 898163468Sglebius addrlen); 899163468Sglebius NG_FREE_MSG(msg); 900163468Sglebius return (EINVAL); 90152885Sjulian } 902163468Sglebius 903163468Sglebius /* Copy the message itself into an mbuf chain. */ 904163468Sglebius m = m_devget((caddr_t)msg, sizeof(struct ng_mesg) + msg->header.arglen, 905163468Sglebius 0, NULL, NULL); 906163468Sglebius 907163468Sglebius /* 908163468Sglebius * Here we free the message. We need to do that 909163468Sglebius * regardless of whether we got mbufs. 910163468Sglebius */ 911163468Sglebius NG_FREE_MSG(msg); 912163468Sglebius 913163468Sglebius if (m == NULL) { 91452419Sjulian TRAP_ERROR; 915163468Sglebius return (ENOBUFS); 91652419Sjulian } 91752419Sjulian 918163468Sglebius /* Send it up to the socket. */ 919163468Sglebius if (sbappendaddr(&so->so_rcv, (struct sockaddr *)&addr, m, NULL) == 0) { 920163468Sglebius TRAP_ERROR; 921163468Sglebius m_freem(m); 922177071Smav return (ENOBUFS); 923163468Sglebius } 924163468Sglebius sorwakeup(so); 925163468Sglebius 92652419Sjulian return (error); 92752419Sjulian} 92852419Sjulian 92952419Sjulian/* 93052419Sjulian * Receive data on a hook 93152419Sjulian */ 93252419Sjulianstatic int 93370700Sjulianngs_rcvdata(hook_p hook, item_p item) 93452419Sjulian{ 93572053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 93672053Sjulian struct ngpcb *const pcbp = priv->datasock; 93752419Sjulian struct socket *so; 93852419Sjulian struct sockaddr_ng *addr; 939125028Sharti char *addrbuf[NG_HOOKSIZ + 4]; 94052419Sjulian int addrlen; 94170700Sjulian struct mbuf *m; 94252419Sjulian 94370700Sjulian NGI_GET_M(item, m); 94470700Sjulian NG_FREE_ITEM(item); 945163463Sglebius 946163463Sglebius /* If there is no data socket, black-hole it. */ 94752419Sjulian if (pcbp == NULL) { 94870700Sjulian NG_FREE_M(m); 94952419Sjulian return (0); 95052419Sjulian } 95152419Sjulian so = pcbp->ng_socket; 95252419Sjulian 95352419Sjulian /* Get the return address into a sockaddr. */ 954125028Sharti addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKSIZ - 1 */ 95552419Sjulian addr = (struct sockaddr_ng *) addrbuf; 95652419Sjulian addr->sg_len = addrlen + 3; 95752419Sjulian addr->sg_family = AF_NETGRAPH; 95870784Sjulian bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); 95952419Sjulian addr->sg_data[addrlen] = '\0'; 96052419Sjulian 961163463Sglebius /* Try to tell the socket which hook it came in on. */ 962163463Sglebius if (sbappendaddr(&so->so_rcv, (struct sockaddr *)addr, m, NULL) == 0) { 96352419Sjulian m_freem(m); 96452419Sjulian TRAP_ERROR; 96552419Sjulian return (ENOBUFS); 96652419Sjulian } 96752419Sjulian sorwakeup(so); 96852419Sjulian return (0); 96952419Sjulian} 97052419Sjulian 97152419Sjulian/* 97253498Sjulian * Hook disconnection 97352885Sjulian * 97452885Sjulian * For this type, removal of the last link destroys the node 97552885Sjulian * if the NOLINGER flag is set. 97652885Sjulian */ 97752885Sjulianstatic int 97852885Sjulianngs_disconnect(hook_p hook) 97952885Sjulian{ 98072053Sjulian node_p node = NG_HOOK_NODE(hook); 98172053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 98252885Sjulian 983163463Sglebius if ((priv->datasock) && (priv->datasock->ng_socket)) { 984163463Sglebius if (NG_NODE_NUMHOOKS(node) == 1) 98572053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 986163463Sglebius else 98772053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 98852885Sjulian } 98972053Sjulian 990163463Sglebius if ((priv->flags & NGS_FLAG_NOLINGER) && 991163463Sglebius (NG_NODE_NUMHOOKS(node) == 0) && (NG_NODE_IS_VALID(node))) 99272053Sjulian ng_rmnode_self(node); 993163463Sglebius 99452885Sjulian return (0); 99552885Sjulian} 99652885Sjulian 99752885Sjulian/* 99852419Sjulian * Do local shutdown processing. 99952419Sjulian * In this case, that involves making sure the socket 100052419Sjulian * knows we should be shutting down. 100152419Sjulian */ 100252419Sjulianstatic int 100370700Sjulianngs_shutdown(node_p node) 100452419Sjulian{ 100572053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 100672053Sjulian struct ngpcb *const dpcbp = priv->datasock; 100772053Sjulian struct ngpcb *const pcbp = priv->ctlsock; 100852419Sjulian 1009151975Sglebius if (dpcbp != NULL) 101052419Sjulian soisdisconnected(dpcbp->ng_socket); 1011151975Sglebius 1012151975Sglebius if (pcbp != NULL) 101352419Sjulian soisdisconnected(pcbp->ng_socket); 1014151975Sglebius 1015151975Sglebius mtx_lock(&priv->mtx); 1016151975Sglebius priv->node = NULL; 101770784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 1018151975Sglebius ng_socket_free_priv(priv); 1019151975Sglebius 102070784Sjulian NG_NODE_UNREF(node); 102152419Sjulian return (0); 102252419Sjulian} 102352419Sjulian 1024147774Sglebiusstatic void 1025147774Sglebiusng_socket_item_applied(void *context, int error) 1026147774Sglebius{ 1027147774Sglebius struct ngsock *const priv = (struct ngsock *)context; 1028147774Sglebius 1029147774Sglebius mtx_lock(&priv->mtx); 1030147774Sglebius priv->error = error; 1031147774Sglebius wakeup(priv); 1032147774Sglebius mtx_unlock(&priv->mtx); 1033147774Sglebius 1034147774Sglebius} 1035147774Sglebius 103672055Sjulianstatic int 103772055Sjuliandummy_disconnect(struct socket *so) 103872055Sjulian{ 103972055Sjulian return (0); 104072055Sjulian} 104152419Sjulian/* 104252419Sjulian * Control and data socket type descriptors 1043160549Srwatson * 1044160549Srwatson * XXXRW: Perhaps _close should do something? 104552419Sjulian */ 104652419Sjulian 104752419Sjulianstatic struct pr_usrreqs ngc_usrreqs = { 1048137386Sphk .pru_abort = NULL, 1049137386Sphk .pru_attach = ngc_attach, 1050137386Sphk .pru_bind = ngc_bind, 1051137386Sphk .pru_connect = ngc_connect, 1052137386Sphk .pru_detach = ngc_detach, 1053137386Sphk .pru_disconnect = dummy_disconnect, 1054137386Sphk .pru_peeraddr = NULL, 1055137386Sphk .pru_send = ngc_send, 1056137386Sphk .pru_shutdown = NULL, 1057169462Srwatson .pru_sockaddr = ng_getsockaddr, 1058160549Srwatson .pru_close = NULL, 105952419Sjulian}; 106052419Sjulian 106152419Sjulianstatic struct pr_usrreqs ngd_usrreqs = { 1062137386Sphk .pru_abort = NULL, 1063137386Sphk .pru_attach = ngd_attach, 1064137386Sphk .pru_bind = NULL, 1065137386Sphk .pru_connect = ngd_connect, 1066137386Sphk .pru_detach = ngd_detach, 1067137386Sphk .pru_disconnect = dummy_disconnect, 1068137386Sphk .pru_peeraddr = NULL, 1069137386Sphk .pru_send = ngd_send, 1070137386Sphk .pru_shutdown = NULL, 1071169462Srwatson .pru_sockaddr = ng_getsockaddr, 1072160549Srwatson .pru_close = NULL, 107352419Sjulian}; 107452419Sjulian 107552419Sjulian/* 107652419Sjulian * Definitions of protocols supported in the NETGRAPH domain. 107752419Sjulian */ 107852419Sjulian 107952419Sjulianextern struct domain ngdomain; /* stop compiler warnings */ 108052419Sjulian 108152419Sjulianstatic struct protosw ngsw[] = { 1082152242Sru{ 1083152242Sru .pr_type = SOCK_DGRAM, 1084152242Sru .pr_domain = &ngdomain, 1085152242Sru .pr_protocol = NG_CONTROL, 1086152242Sru .pr_flags = PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, 1087152242Sru .pr_usrreqs = &ngc_usrreqs 1088152242Sru}, 1089152242Sru{ 1090152242Sru .pr_type = SOCK_DGRAM, 1091152242Sru .pr_domain = &ngdomain, 1092152242Sru .pr_protocol = NG_DATA, 1093152242Sru .pr_flags = PR_ATOMIC | PR_ADDR, 1094152242Sru .pr_usrreqs = &ngd_usrreqs 1095152242Sru} 109652419Sjulian}; 109752419Sjulian 109852419Sjulianstruct domain ngdomain = { 1099152242Sru .dom_family = AF_NETGRAPH, 1100152242Sru .dom_name = "netgraph", 1101152242Sru .dom_protosw = ngsw, 1102152242Sru .dom_protoswNPROTOSW = &ngsw[sizeof(ngsw) / sizeof(ngsw[0])] 110352419Sjulian}; 110452419Sjulian 110552419Sjulian/* 1106163463Sglebius * Handle loading and unloading for this node type. 110752419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition). 110852419Sjulian */ 110952419Sjulianstatic int 111052419Sjulianngs_mod_event(module_t mod, int event, void *data) 111152419Sjulian{ 111252419Sjulian int error = 0; 111352419Sjulian 111452419Sjulian switch (event) { 111552419Sjulian case MOD_LOAD: 1116163463Sglebius /* Register protocol domain. */ 111752419Sjulian net_add_domain(&ngdomain); 111852419Sjulian break; 111952419Sjulian case MOD_UNLOAD: 112052419Sjulian#ifdef NOTYET 112152419Sjulian /* Unregister protocol domain XXX can't do this yet.. */ 1122163463Sglebius if ((error = net_rm_domain(&ngdomain)) != 0) 1123163463Sglebius break; 1124163463Sglebius else 112552419Sjulian#endif 112670700Sjulian error = EBUSY; 112752419Sjulian break; 112852419Sjulian default: 112952419Sjulian error = EOPNOTSUPP; 113052419Sjulian break; 113152419Sjulian } 113252419Sjulian return (error); 113352419Sjulian} 113452419Sjulian 113552419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, ""); 113652419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); 113752419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, ""); 113852419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); 113952419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, ""); 114052419Sjulian 1141