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: releng/11.0/sys/netgraph/ng_socket.c 298431 2016-04-21 19:40:10Z pfg $ 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> 54230487Sglebius#include <sys/hash.h> 5552419Sjulian#include <sys/kernel.h> 56132705Sglebius#include <sys/linker.h> 5795759Stanimura#include <sys/lock.h> 5852419Sjulian#include <sys/malloc.h> 5952419Sjulian#include <sys/mbuf.h> 60132013Srwatson#include <sys/mutex.h> 61164033Srwatson#include <sys/priv.h> 6252419Sjulian#include <sys/protosw.h> 6395759Stanimura#include <sys/queue.h> 6452419Sjulian#include <sys/socket.h> 6552419Sjulian#include <sys/socketvar.h> 66159590Sjhb#include <sys/syscallsubr.h> 6752419Sjulian#include <sys/sysctl.h> 68195837Srwatson 69195837Srwatson#include <net/vnet.h> 70195837Srwatson 7152419Sjulian#include <netgraph/ng_message.h> 7252419Sjulian#include <netgraph/netgraph.h> 7352919Sjulian#include <netgraph/ng_socketvar.h> 7452419Sjulian#include <netgraph/ng_socket.h> 7552419Sjulian 7670870Sjulian#ifdef NG_SEPARATE_MALLOC 77227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info"); 78227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info"); 7970870Sjulian#else 8070870Sjulian#define M_NETGRAPH_PATH M_NETGRAPH 8170870Sjulian#define M_NETGRAPH_SOCK M_NETGRAPH 8270870Sjulian#endif 8370870Sjulian 8452419Sjulian/* 8552419Sjulian * It's Ascii-art time! 8652419Sjulian * +-------------+ +-------------+ 8752419Sjulian * |socket (ctl)| |socket (data)| 8852419Sjulian * +-------------+ +-------------+ 8952419Sjulian * ^ ^ 9052419Sjulian * | | 9152419Sjulian * v v 9252419Sjulian * +-----------+ +-----------+ 9352419Sjulian * |pcb (ctl)| |pcb (data)| 9452419Sjulian * +-----------+ +-----------+ 9552419Sjulian * ^ ^ 9652419Sjulian * | | 9752419Sjulian * v v 9852419Sjulian * +--------------------------+ 9952419Sjulian * | Socket type private | 10052419Sjulian * | data | 10152419Sjulian * +--------------------------+ 10252419Sjulian * ^ 10352419Sjulian * | 10452419Sjulian * v 10552419Sjulian * +----------------+ 10652419Sjulian * | struct ng_node | 10752419Sjulian * +----------------+ 10852419Sjulian */ 10952419Sjulian 11052419Sjulian/* Netgraph node methods */ 11152752Sjulianstatic ng_constructor_t ngs_constructor; 11252752Sjulianstatic ng_rcvmsg_t ngs_rcvmsg; 11370700Sjulianstatic ng_shutdown_t ngs_shutdown; 11452752Sjulianstatic ng_newhook_t ngs_newhook; 11572053Sjulianstatic ng_connect_t ngs_connect; 116230487Sglebiusstatic ng_findhook_t ngs_findhook; 11752752Sjulianstatic ng_rcvdata_t ngs_rcvdata; 11852885Sjulianstatic ng_disconnect_t ngs_disconnect; 11952419Sjulian 12052419Sjulian/* Internal methods */ 12152419Sjulianstatic int ng_attach_data(struct socket *so); 12252419Sjulianstatic int ng_attach_cntl(struct socket *so); 12352419Sjulianstatic int ng_attach_common(struct socket *so, int type); 124151975Sglebiusstatic void ng_detach_common(struct ngpcb *pcbp, int type); 125151975Sglebiusstatic void ng_socket_free_priv(struct ngsock *priv); 12652419Sjulianstatic int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp); 12752419Sjulianstatic int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); 12852419Sjulian 12952419Sjulianstatic int ngs_mod_event(module_t mod, int event, void *data); 130147774Sglebiusstatic void ng_socket_item_applied(void *context, int error); 13152419Sjulian 13252419Sjulian/* Netgraph type descriptor */ 13352419Sjulianstatic struct ng_type typestruct = { 134129823Sjulian .version = NG_ABI_VERSION, 135129823Sjulian .name = NG_SOCKET_NODE_TYPE, 136129823Sjulian .mod_event = ngs_mod_event, 137129823Sjulian .constructor = ngs_constructor, 138129823Sjulian .rcvmsg = ngs_rcvmsg, 139129823Sjulian .shutdown = ngs_shutdown, 140129823Sjulian .newhook = ngs_newhook, 141129823Sjulian .connect = ngs_connect, 142230487Sglebius .findhook = ngs_findhook, 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 */ 150217320SmdfSYSCTL_ULONG(_net_graph, OID_AUTO, maxdgram, CTLFLAG_RW, 151124871Sru &ngpdg_sendspace , 0, "Maximum outgoing Netgraph datagram size"); 15252419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024; 153217320SmdfSYSCTL_ULONG(_net_graph, OID_AUTO, recvspace, CTLFLAG_RW, 154125116Sru &ngpdg_recvspace , 0, "Maximum space for incoming Netgraph datagrams"); 15552419Sjulian 156205082Sglebius/* List of all sockets (for netstat -f netgraph) */ 157205082Sglebiusstatic LIST_HEAD(, ngpcb) ngsocklist; 158205082Sglebius 159205082Sglebiusstatic struct mtx ngsocketlist_mtx; 160205082Sglebius 16153526Sjulian#define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb) 16252419Sjulian 163131933Smarcel/* If getting unexplained errors returned, set this to "kdb_enter("X"); */ 16452419Sjulian#ifndef TRAP_ERROR 16552419Sjulian#define TRAP_ERROR 16652419Sjulian#endif 16752419Sjulian 168230487Sglebiusstruct hookpriv { 169230487Sglebius LIST_ENTRY(hookpriv) next; 170230487Sglebius hook_p hook; 171230487Sglebius}; 172230487SglebiusLIST_HEAD(ngshash, hookpriv); 173230487Sglebius 174230481Sglebius/* Per-node private data */ 175230481Sglebiusstruct ngsock { 176230481Sglebius struct ng_node *node; /* the associated netgraph node */ 177230481Sglebius struct ngpcb *datasock; /* optional data socket */ 178230481Sglebius struct ngpcb *ctlsock; /* optional control socket */ 179230487Sglebius struct ngshash *hash; /* hash for hook names */ 180230487Sglebius u_long hmask; /* hash mask */ 181230481Sglebius int flags; 182230481Sglebius int refs; 183230481Sglebius struct mtx mtx; /* mtx to wait on */ 184230481Sglebius int error; /* place to store error */ 185230481Sglebius}; 186230481Sglebius 187230481Sglebius#define NGS_FLAG_NOLINGER 1 /* close with last hook */ 188230481Sglebius 18952419Sjulian/*************************************************************** 19052419Sjulian Control sockets 19152419Sjulian***************************************************************/ 19252419Sjulian 19352419Sjulianstatic int 19483366Sjulianngc_attach(struct socket *so, int proto, struct thread *td) 19552419Sjulian{ 19652419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 197164033Srwatson int error; 19852419Sjulian 199164033Srwatson error = priv_check(td, PRIV_NETGRAPH_CONTROL); 200164033Srwatson if (error) 201164033Srwatson return (error); 20252419Sjulian if (pcbp != NULL) 20352419Sjulian return (EISCONN); 20452419Sjulian return (ng_attach_cntl(so)); 20552419Sjulian} 20652419Sjulian 207157370Srwatsonstatic void 20852419Sjulianngc_detach(struct socket *so) 20952419Sjulian{ 21052419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 21152419Sjulian 212157370Srwatson KASSERT(pcbp != NULL, ("ngc_detach: pcbp == NULL")); 213151975Sglebius ng_detach_common(pcbp, NG_CONTROL); 21452419Sjulian} 21552419Sjulian 21652419Sjulianstatic int 21752419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 21883366Sjulian struct mbuf *control, struct thread *td) 21952419Sjulian{ 22052419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 221147774Sglebius struct ngsock *const priv = NG_NODE_PRIVATE(pcbp->sockdata->node); 22252419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 22370700Sjulian struct ng_mesg *msg; 22452419Sjulian struct mbuf *m0; 225146317Sglebius item_p item; 22670700Sjulian char *path = NULL; 22752419Sjulian int len, error = 0; 228172806Smav struct ng_apply_info apply; 22952419Sjulian 23052419Sjulian if (control) { 23152419Sjulian error = EINVAL; 23252419Sjulian goto release; 23352419Sjulian } 23452419Sjulian 235163463Sglebius /* Require destination as there may be >= 1 hooks on this node. */ 23652419Sjulian if (addr == NULL) { 23752419Sjulian error = EDESTADDRREQ; 23852419Sjulian goto release; 23952419Sjulian } 24052419Sjulian 241163463Sglebius /* 242163463Sglebius * Allocate an expendable buffer for the path, chop off 243163463Sglebius * the sockaddr header, and make sure it's NUL terminated. 244163463Sglebius */ 24552419Sjulian len = sap->sg_len - 2; 246163463Sglebius path = malloc(len + 1, M_NETGRAPH_PATH, M_WAITOK); 24752419Sjulian bcopy(sap->sg_data, path, len); 24852419Sjulian path[len] = '\0'; 24952419Sjulian 250163463Sglebius /* 251163463Sglebius * Move the actual message out of mbufs into a linear buffer. 252163463Sglebius * Start by adding up the size of the data. (could use mh_len?) 253163463Sglebius */ 25452419Sjulian for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next) 25552419Sjulian len += m0->m_len; 25652419Sjulian 257163463Sglebius /* 258163463Sglebius * Move the data into a linear buffer as well. 259163463Sglebius * Messages are not delivered in mbufs. 260163463Sglebius */ 261163463Sglebius msg = malloc(len + 1, M_NETGRAPH_MSG, M_WAITOK); 26270700Sjulian m_copydata(m, 0, len, (char *)msg); 26352419Sjulian 264141308Sglebius if (msg->header.version != NG_VERSION) { 265163463Sglebius free(msg, M_NETGRAPH_MSG); 266141308Sglebius error = EINVAL; 267141308Sglebius goto release; 268141308Sglebius } 269141308Sglebius 270132705Sglebius /* 271132705Sglebius * Hack alert! 272132705Sglebius * We look into the message and if it mkpeers a node of unknown type, we 273132705Sglebius * try to load it. We need to do this now, in syscall thread, because if 274132705Sglebius * message gets queued and applied later we will get panic. 275132705Sglebius */ 276132939Sglebius if (msg->header.typecookie == NGM_GENERIC_COOKIE && 277132939Sglebius msg->header.cmd == NGM_MKPEER) { 278132705Sglebius struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 279132705Sglebius 280185183Smav if (ng_findtype(mkp->type) == NULL) { 281132705Sglebius char filename[NG_TYPESIZ + 3]; 282159590Sjhb int fileid; 283132705Sglebius 284146296Sglebius /* Not found, try to load it as a loadable module. */ 285146296Sglebius snprintf(filename, sizeof(filename), "ng_%s", 286146296Sglebius mkp->type); 287159590Sjhb error = kern_kldload(curthread, filename, &fileid); 288132705Sglebius if (error != 0) { 289163463Sglebius free(msg, M_NETGRAPH_MSG); 290132705Sglebius goto release; 291132705Sglebius } 292132705Sglebius 293146296Sglebius /* See if type has been loaded successfully. */ 294185183Smav if (ng_findtype(mkp->type) == NULL) { 295163463Sglebius free(msg, M_NETGRAPH_MSG); 296159590Sjhb (void)kern_kldunload(curthread, fileid, 297159590Sjhb LINKER_UNLOAD_NORMAL); 298132705Sglebius error = ENXIO; 299132705Sglebius goto release; 300132705Sglebius } 301132705Sglebius } 302132705Sglebius } 303132705Sglebius 304266536Smav item = ng_package_msg(msg, NG_WAITOK); 305163463Sglebius if ((error = ng_address_path((pcbp->sockdata->node), item, path, 0)) 306163463Sglebius != 0) { 307146296Sglebius#ifdef TRACE_MESSAGES 308146317Sglebius printf("ng_address_path: errx=%d\n", error); 309146317Sglebius#endif 310146317Sglebius goto release; 311146317Sglebius } 312146296Sglebius 313146317Sglebius#ifdef TRACE_MESSAGES 314146317Sglebius printf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n", 315146317Sglebius item->el_dest->nd_ID, 316146317Sglebius msg->header.typecookie, 317146317Sglebius msg->header.cmd, 318146317Sglebius msg->header.cmdstr, 319146317Sglebius msg->header.flags, 320146317Sglebius msg->header.token, 321146317Sglebius item->el_dest->nd_type->name); 32270784Sjulian#endif 323146317Sglebius SAVE_LINE(item); 324147774Sglebius /* 325147774Sglebius * We do not want to return from syscall until the item 326147774Sglebius * is processed by destination node. We register callback 327147774Sglebius * on the item, which will update priv->error when item 328147774Sglebius * was applied. 329147774Sglebius * If ng_snd_item() has queued item, we sleep until 330147774Sglebius * callback wakes us up. 331147774Sglebius */ 332172806Smav bzero(&apply, sizeof(apply)); 333172806Smav apply.apply = ng_socket_item_applied; 334172806Smav apply.context = priv; 335172806Smav item->apply = &apply; 336147774Sglebius priv->error = -1; 337146296Sglebius 338172806Smav error = ng_snd_item(item, 0); 339147774Sglebius 340172806Smav mtx_lock(&priv->mtx); 341172806Smav if (priv->error == -1) 342172806Smav msleep(priv, &priv->mtx, 0, "ngsock", 0); 343172806Smav mtx_unlock(&priv->mtx); 344172806Smav KASSERT(priv->error != -1, 345172806Smav ("ng_socket: priv->error wasn't updated")); 346172806Smav error = priv->error; 347147774Sglebius 34852419Sjulianrelease: 34952419Sjulian if (path != NULL) 350163463Sglebius free(path, M_NETGRAPH_PATH); 35152419Sjulian if (control != NULL) 35252419Sjulian m_freem(control); 35352419Sjulian if (m != NULL) 35452419Sjulian m_freem(m); 35552419Sjulian return (error); 35652419Sjulian} 35752419Sjulian 35852419Sjulianstatic int 35983366Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 36052419Sjulian{ 36152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 36252419Sjulian 363298075Spfg if (pcbp == NULL) 36452419Sjulian return (EINVAL); 36552419Sjulian return (ng_bind(nam, pcbp)); 36652419Sjulian} 36752419Sjulian 36852419Sjulianstatic int 36983366Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 37052419Sjulian{ 37170700Sjulian /* 37270784Sjulian * At this time refuse to do this.. it used to 37370700Sjulian * do something but it was undocumented and not used. 37470700Sjulian */ 375163463Sglebius printf("program tried to connect control socket to remote node\n"); 37670700Sjulian return (EINVAL); 37752419Sjulian} 37852419Sjulian 37952419Sjulian/*************************************************************** 38052419Sjulian Data sockets 38152419Sjulian***************************************************************/ 38252419Sjulian 38352419Sjulianstatic int 38483366Sjulianngd_attach(struct socket *so, int proto, struct thread *td) 38552419Sjulian{ 38652419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 38752419Sjulian 38852419Sjulian if (pcbp != NULL) 38952419Sjulian return (EISCONN); 39052419Sjulian return (ng_attach_data(so)); 39152419Sjulian} 39252419Sjulian 393157370Srwatsonstatic void 39452419Sjulianngd_detach(struct socket *so) 39552419Sjulian{ 39652419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 39752419Sjulian 398157558Srwatson KASSERT(pcbp != NULL, ("ngd_detach: pcbp == NULL")); 399151975Sglebius ng_detach_common(pcbp, NG_DATA); 40052419Sjulian} 40152419Sjulian 40252419Sjulianstatic int 40352419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 40483366Sjulian struct mbuf *control, struct thread *td) 40552419Sjulian{ 40652419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 40752419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 408163463Sglebius int len, error; 40953498Sjulian hook_p hook = NULL; 410125028Sharti char hookname[NG_HOOKSIZ]; 41152419Sjulian 41252419Sjulian if ((pcbp == NULL) || (control != NULL)) { 41352419Sjulian error = EINVAL; 41452419Sjulian goto release; 41552419Sjulian } 41652419Sjulian if (pcbp->sockdata == NULL) { 41752419Sjulian error = ENOTCONN; 41852419Sjulian goto release; 41952419Sjulian } 420146718Sbz 421146718Sbz if (sap == NULL) 422146718Sbz len = 0; /* Make compiler happy. */ 423146718Sbz else 424146718Sbz len = sap->sg_len - 2; 425146718Sbz 42653498Sjulian /* 42753498Sjulian * If the user used any of these ways to not specify an address 42853498Sjulian * then handle specially. 42953498Sjulian */ 430146718Sbz if ((sap == NULL) || (len <= 0) || (*sap->sg_data == '\0')) { 43170784Sjulian if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) { 43253498Sjulian error = EDESTADDRREQ; 43353498Sjulian goto release; 43453498Sjulian } 43553498Sjulian /* 436163463Sglebius * If exactly one hook exists, just use it. 43753498Sjulian * Special case to allow write(2) to work on an ng_socket. 43853498Sjulian */ 43970784Sjulian hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks); 44053498Sjulian } else { 441125028Sharti if (len >= NG_HOOKSIZ) { 44253498Sjulian error = EINVAL; 44353498Sjulian goto release; 44453498Sjulian } 44552419Sjulian 44653498Sjulian /* 44753498Sjulian * chop off the sockaddr header, and make sure it's NUL 44853498Sjulian * terminated 44953498Sjulian */ 45053498Sjulian bcopy(sap->sg_data, hookname, len); 45153498Sjulian hookname[len] = '\0'; 45252419Sjulian 45353498Sjulian /* Find the correct hook from 'hookname' */ 454163463Sglebius hook = ng_findhook(pcbp->sockdata->node, hookname); 45572053Sjulian if (hook == NULL) { 45653498Sjulian error = EHOSTUNREACH; 457163463Sglebius goto release; 45872053Sjulian } 45952419Sjulian } 46052419Sjulian 461163463Sglebius /* Send data. */ 462163463Sglebius NG_SEND_DATA_FLAGS(error, hook, m, NG_WAITOK); 46352419Sjulian 46452419Sjulianrelease: 46552419Sjulian if (control != NULL) 46652419Sjulian m_freem(control); 46752419Sjulian if (m != NULL) 46852419Sjulian m_freem(m); 46952419Sjulian return (error); 47052419Sjulian} 47152419Sjulian 47252419Sjulianstatic int 47383366Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 47452419Sjulian{ 47552419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 47652419Sjulian 477298075Spfg if (pcbp == NULL) 47852419Sjulian return (EINVAL); 47952419Sjulian return (ng_connect_data(nam, pcbp)); 48052419Sjulian} 48152419Sjulian 48252419Sjulian/* 48352419Sjulian * Used for both data and control sockets 48452419Sjulian */ 48552419Sjulianstatic int 486169462Srwatsonng_getsockaddr(struct socket *so, struct sockaddr **addr) 48752419Sjulian{ 48853098Sbrian struct ngpcb *pcbp; 48953098Sbrian struct sockaddr_ng *sg; 490151975Sglebius int sg_len; 491151975Sglebius int error = 0; 49252419Sjulian 49353098Sbrian pcbp = sotongpcb(so); 494151975Sglebius if ((pcbp == NULL) || (pcbp->sockdata == NULL)) 495151975Sglebius /* XXXGL: can this still happen? */ 49652419Sjulian return (EINVAL); 49753098Sbrian 498231823Sglebius sg_len = sizeof(struct sockaddr_ng) + NG_NODESIZ - 499231823Sglebius sizeof(sg->sg_data); 500231823Sglebius sg = malloc(sg_len, M_SONAME, M_WAITOK | M_ZERO); 501231823Sglebius 502151975Sglebius mtx_lock(&pcbp->sockdata->mtx); 503151975Sglebius if (pcbp->sockdata->node != NULL) { 504151975Sglebius node_p node = pcbp->sockdata->node; 50553098Sbrian 506151975Sglebius if (NG_NODE_HAS_NAME(node)) 507231823Sglebius bcopy(NG_NODE_NAME(node), sg->sg_data, 508231823Sglebius strlen(NG_NODE_NAME(node))); 509231823Sglebius mtx_unlock(&pcbp->sockdata->mtx); 51053098Sbrian 511151975Sglebius sg->sg_len = sg_len; 512151975Sglebius sg->sg_family = AF_NETGRAPH; 513151975Sglebius *addr = (struct sockaddr *)sg; 514151975Sglebius } else { 515151975Sglebius mtx_unlock(&pcbp->sockdata->mtx); 516231823Sglebius free(sg, M_SONAME); 517151975Sglebius error = EINVAL; 518151975Sglebius } 519151975Sglebius 520151975Sglebius return (error); 52152419Sjulian} 52252419Sjulian 52352419Sjulian/* 52452419Sjulian * Attach a socket to it's protocol specific partner. 52552419Sjulian * For a control socket, actually create a netgraph node and attach 52652419Sjulian * to it as well. 52752419Sjulian */ 52852419Sjulian 52952419Sjulianstatic int 53052419Sjulianng_attach_cntl(struct socket *so) 53152419Sjulian{ 532151975Sglebius struct ngsock *priv; 53352419Sjulian struct ngpcb *pcbp; 534224031Sglebius node_p node; 53552419Sjulian int error; 53652419Sjulian 53752419Sjulian /* Setup protocol control block */ 538224031Sglebius if ((error = ng_attach_common(so, NG_CONTROL)) != 0) 53952419Sjulian return (error); 54053526Sjulian pcbp = sotongpcb(so); 54152419Sjulian 542224031Sglebius /* Make the generic node components */ 543224031Sglebius if ((error = ng_make_node_common(&typestruct, &node)) != 0) { 544224031Sglebius ng_detach_common(pcbp, NG_CONTROL); 545224031Sglebius return (error); 546224031Sglebius } 547224031Sglebius 548230487Sglebius /* 549230487Sglebius * Allocate node private info and hash. We start 550230487Sglebius * with 16 hash entries, however we may grow later 551230487Sglebius * in ngs_newhook(). We can't predict how much hooks 552230487Sglebius * does this node plan to have. 553230487Sglebius */ 554224031Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO); 555230487Sglebius priv->hash = hashinit(16, M_NETGRAPH_SOCK, &priv->hmask); 556224031Sglebius 557224031Sglebius /* Initialize mutex. */ 558224031Sglebius mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF); 559224031Sglebius 560151975Sglebius /* Link the pcb the private data. */ 561151975Sglebius priv->ctlsock = pcbp; 562151975Sglebius pcbp->sockdata = priv; 563151975Sglebius priv->refs++; 564224031Sglebius priv->node = node; 565230481Sglebius pcbp->node_id = node->nd_ID; /* hint for netstat(1) */ 56652419Sjulian 567151975Sglebius /* Link the node and the private data. */ 568151975Sglebius NG_NODE_SET_PRIVATE(priv->node, priv); 569151975Sglebius NG_NODE_REF(priv->node); 570151975Sglebius priv->refs++; 571147774Sglebius 57252419Sjulian return (0); 57352419Sjulian} 57452419Sjulian 57552419Sjulianstatic int 57652419Sjulianng_attach_data(struct socket *so) 57752419Sjulian{ 578163463Sglebius return (ng_attach_common(so, NG_DATA)); 57952419Sjulian} 58052419Sjulian 58152419Sjulian/* 58252419Sjulian * Set up a socket protocol control block. 58352419Sjulian * This code is shared between control and data sockets. 58452419Sjulian */ 58552419Sjulianstatic int 58652419Sjulianng_attach_common(struct socket *so, int type) 58752419Sjulian{ 58852419Sjulian struct ngpcb *pcbp; 58952419Sjulian int error; 59052419Sjulian 591163463Sglebius /* Standard socket setup stuff. */ 59252419Sjulian error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace); 59352419Sjulian if (error) 59452419Sjulian return (error); 59552419Sjulian 596163463Sglebius /* Allocate the pcb. */ 597163463Sglebius pcbp = malloc(sizeof(struct ngpcb), M_PCB, M_WAITOK | M_ZERO); 59852419Sjulian pcbp->type = type; 59952419Sjulian 600163463Sglebius /* Link the pcb and the socket. */ 601163463Sglebius so->so_pcb = (caddr_t)pcbp; 60252419Sjulian pcbp->ng_socket = so; 60352419Sjulian 604205082Sglebius /* Add the socket to linked list */ 605205082Sglebius mtx_lock(&ngsocketlist_mtx); 606205082Sglebius LIST_INSERT_HEAD(&ngsocklist, pcbp, socks); 607205082Sglebius mtx_unlock(&ngsocketlist_mtx); 60852419Sjulian return (0); 60952419Sjulian} 61052419Sjulian 61152419Sjulian/* 61252419Sjulian * Disassociate the socket from it's protocol specific 61352419Sjulian * partner. If it's attached to a node's private data structure, 61452419Sjulian * then unlink from that too. If we were the last socket attached to it, 61552419Sjulian * then shut down the entire node. Shared code for control and data sockets. 61652419Sjulian */ 61752419Sjulianstatic void 618151975Sglebiusng_detach_common(struct ngpcb *pcbp, int which) 61952419Sjulian{ 620151975Sglebius struct ngsock *priv = pcbp->sockdata; 62152419Sjulian 622151975Sglebius if (priv != NULL) { 623151975Sglebius mtx_lock(&priv->mtx); 624146290Sglebius 62552419Sjulian switch (which) { 62652419Sjulian case NG_CONTROL: 62772053Sjulian priv->ctlsock = NULL; 62852419Sjulian break; 62952419Sjulian case NG_DATA: 63072053Sjulian priv->datasock = NULL; 63152419Sjulian break; 63252419Sjulian default: 633213794Srpaulo panic("%s", __func__); 63452419Sjulian } 635151975Sglebius pcbp->sockdata = NULL; 636230481Sglebius pcbp->node_id = 0; 637151975Sglebius 638151975Sglebius ng_socket_free_priv(priv); 63952419Sjulian } 640151975Sglebius 64152419Sjulian pcbp->ng_socket->so_pcb = NULL; 642205082Sglebius mtx_lock(&ngsocketlist_mtx); 643205082Sglebius LIST_REMOVE(pcbp, socks); 644205082Sglebius mtx_unlock(&ngsocketlist_mtx); 645163463Sglebius free(pcbp, M_PCB); 64652419Sjulian} 64752419Sjulian 648151975Sglebius/* 649151975Sglebius * Remove a reference from node private data. 650151975Sglebius */ 651151975Sglebiusstatic void 652151975Sglebiusng_socket_free_priv(struct ngsock *priv) 653151975Sglebius{ 654151975Sglebius mtx_assert(&priv->mtx, MA_OWNED); 655151975Sglebius 656151975Sglebius priv->refs--; 657151975Sglebius 658151975Sglebius if (priv->refs == 0) { 659151975Sglebius mtx_destroy(&priv->mtx); 660230487Sglebius hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask); 661163463Sglebius free(priv, M_NETGRAPH_SOCK); 662151975Sglebius return; 663151975Sglebius } 664151975Sglebius 665151975Sglebius if ((priv->refs == 1) && (priv->node != NULL)) { 666151975Sglebius node_p node = priv->node; 667151975Sglebius 668151975Sglebius priv->node = NULL; 669151975Sglebius mtx_unlock(&priv->mtx); 670151975Sglebius NG_NODE_UNREF(node); 671151975Sglebius ng_rmnode_self(node); 672151975Sglebius } else 673151975Sglebius mtx_unlock(&priv->mtx); 674151975Sglebius} 675151975Sglebius 67652419Sjulian/* 67752419Sjulian * Connect the data socket to a named control socket node. 67852419Sjulian */ 67952419Sjulianstatic int 68052419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) 68152419Sjulian{ 68252419Sjulian struct sockaddr_ng *sap; 68352419Sjulian node_p farnode; 68472053Sjulian struct ngsock *priv; 68552419Sjulian int error; 68670700Sjulian item_p item; 68752419Sjulian 688163463Sglebius /* If we are already connected, don't do it again. */ 68952419Sjulian if (pcbp->sockdata != NULL) 69052419Sjulian return (EISCONN); 69152419Sjulian 692163463Sglebius /* 693163463Sglebius * Find the target (victim) and check it doesn't already have 694163463Sglebius * a data socket. Also check it is a 'socket' type node. 695163463Sglebius * Use ng_package_data() and ng_address_path() to do this. 69670700Sjulian */ 69770700Sjulian 69852419Sjulian sap = (struct sockaddr_ng *) nam; 699163463Sglebius /* The item will hold the node reference. */ 700146284Sglebius item = ng_package_data(NULL, NG_WAITOK); 701163463Sglebius 702102244Sarchie if ((error = ng_address_path(NULL, item, sap->sg_data, 0))) 70370700Sjulian return (error); /* item is freed on failure */ 70452419Sjulian 70570700Sjulian /* 70670784Sjulian * Extract node from item and free item. Remember we now have 70770700Sjulian * a reference on the node. The item holds it for us. 70870700Sjulian * when we free the item we release the reference. 70970700Sjulian */ 71070700Sjulian farnode = item->el_dest; /* shortcut */ 71170784Sjulian if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) { 71270700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 71352419Sjulian return (EINVAL); 71470700Sjulian } 71572053Sjulian priv = NG_NODE_PRIVATE(farnode); 71672053Sjulian if (priv->datasock != NULL) { 71770700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 71852419Sjulian return (EADDRINUSE); 71970700Sjulian } 72052419Sjulian 72170700Sjulian /* 72270700Sjulian * Link the PCB and the private data struct. and note the extra 72370700Sjulian * reference. Drop the extra reference on the node. 72470700Sjulian */ 725151975Sglebius mtx_lock(&priv->mtx); 72672053Sjulian priv->datasock = pcbp; 72772053Sjulian pcbp->sockdata = priv; 728230481Sglebius pcbp->node_id = priv->node->nd_ID; /* hint for netstat(1) */ 729151975Sglebius priv->refs++; 730151975Sglebius mtx_unlock(&priv->mtx); 73170700Sjulian NG_FREE_ITEM(item); /* drop the reference to the node */ 73252419Sjulian return (0); 73352419Sjulian} 73452419Sjulian 73552419Sjulian/* 73652419Sjulian * Binding a socket means giving the corresponding node a name 73752419Sjulian */ 73852419Sjulianstatic int 73952419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp) 74052419Sjulian{ 74172053Sjulian struct ngsock *const priv = pcbp->sockdata; 74252419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; 74352419Sjulian 74472053Sjulian if (priv == NULL) { 74552419Sjulian TRAP_ERROR; 74652419Sjulian return (EINVAL); 74752419Sjulian } 748163463Sglebius if ((sap->sg_len < 4) || (sap->sg_len > (NG_NODESIZ + 2)) || 749163463Sglebius (sap->sg_data[0] == '\0') || 750163463Sglebius (sap->sg_data[sap->sg_len - 3] != '\0')) { 75152419Sjulian TRAP_ERROR; 75252419Sjulian return (EINVAL); 75352419Sjulian } 75472053Sjulian return (ng_name_node(priv->node, sap->sg_data)); 75552419Sjulian} 75652419Sjulian 757147774Sglebius/*************************************************************** 758147774Sglebius Netgraph node 759147774Sglebius***************************************************************/ 760147774Sglebius 76152419Sjulian/* 76252419Sjulian * You can only create new nodes from the socket end of things. 76352419Sjulian */ 76452419Sjulianstatic int 76570700Sjulianngs_constructor(node_p nodep) 76652419Sjulian{ 76752419Sjulian return (EINVAL); 76852419Sjulian} 76952419Sjulian 770230487Sglebiusstatic void 771230487Sglebiusngs_rehash(node_p node) 772230487Sglebius{ 773230487Sglebius struct ngsock *priv = NG_NODE_PRIVATE(node); 774230487Sglebius struct ngshash *new; 775230487Sglebius struct hookpriv *hp; 776230487Sglebius hook_p hook; 777230487Sglebius uint32_t h; 778230487Sglebius u_long hmask; 779230487Sglebius 780230487Sglebius new = hashinit_flags((priv->hmask + 1) * 2, M_NETGRAPH_SOCK, &hmask, 781230487Sglebius HASH_NOWAIT); 782230487Sglebius if (new == NULL) 783230487Sglebius return; 784230487Sglebius 785230487Sglebius LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) { 786230487Sglebius hp = NG_HOOK_PRIVATE(hook); 787230487Sglebius#ifdef INVARIANTS 788230487Sglebius LIST_REMOVE(hp, next); 789230487Sglebius#endif 790230487Sglebius h = hash32_str(NG_HOOK_NAME(hook), HASHINIT) & hmask; 791230487Sglebius LIST_INSERT_HEAD(&new[h], hp, next); 792230487Sglebius } 793230487Sglebius 794230487Sglebius hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask); 795230487Sglebius priv->hash = new; 796230487Sglebius priv->hmask = hmask; 797230487Sglebius} 798230487Sglebius 79952419Sjulian/* 80052419Sjulian * We allow any hook to be connected to the node. 80152419Sjulian * There is no per-hook private information though. 80252419Sjulian */ 80352419Sjulianstatic int 80452419Sjulianngs_newhook(node_p node, hook_p hook, const char *name) 80552419Sjulian{ 806230487Sglebius struct ngsock *const priv = NG_NODE_PRIVATE(node); 807230487Sglebius struct hookpriv *hp; 808230487Sglebius uint32_t h; 809230487Sglebius 810230487Sglebius hp = malloc(sizeof(*hp), M_NETGRAPH_SOCK, M_NOWAIT); 811230487Sglebius if (hp == NULL) 812230487Sglebius return (ENOMEM); 813230487Sglebius if (node->nd_numhooks * 2 > priv->hmask) 814230487Sglebius ngs_rehash(node); 815230487Sglebius hp->hook = hook; 816230487Sglebius h = hash32_str(name, HASHINIT) & priv->hmask; 817230487Sglebius LIST_INSERT_HEAD(&priv->hash[h], hp, next); 818230487Sglebius NG_HOOK_SET_PRIVATE(hook, hp); 819230487Sglebius 82052419Sjulian return (0); 82152419Sjulian} 82252419Sjulian 823163463Sglebius/* 824163463Sglebius * If only one hook, allow read(2) and write(2) to work. 82572053Sjulian */ 82672053Sjulianstatic int 82772053Sjulianngs_connect(hook_p hook) 82872053Sjulian{ 82972053Sjulian node_p node = NG_HOOK_NODE(hook); 83072053Sjulian struct ngsock *priv = NG_NODE_PRIVATE(node); 83172053Sjulian 832163463Sglebius if ((priv->datasock) && (priv->datasock->ng_socket)) { 833163463Sglebius if (NG_NODE_NUMHOOKS(node) == 1) 83472053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 835163463Sglebius else 83672053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 83772053Sjulian } 83872053Sjulian return (0); 83972053Sjulian} 84072053Sjulian 841230487Sglebius/* Look up hook by name */ 842230487Sglebiusstatic hook_p 843230487Sglebiusngs_findhook(node_p node, const char *name) 844230487Sglebius{ 845230487Sglebius struct ngsock *priv = NG_NODE_PRIVATE(node); 846230487Sglebius struct hookpriv *hp; 847230487Sglebius uint32_t h; 848230487Sglebius 849230487Sglebius /* 850231585Sglebius * Microoptimisation for an ng_socket with 851231585Sglebius * a single hook, which is a common case. 852230487Sglebius */ 853230487Sglebius if (node->nd_numhooks == 1) { 854230487Sglebius hook_p hook; 855230487Sglebius 856230487Sglebius hook = LIST_FIRST(&node->nd_hooks); 857230487Sglebius 858230487Sglebius if (strcmp(NG_HOOK_NAME(hook), name) == 0) 859230487Sglebius return (hook); 860230487Sglebius else 861230487Sglebius return (NULL); 862230487Sglebius } 863230487Sglebius 864230487Sglebius h = hash32_str(name, HASHINIT) & priv->hmask; 865230487Sglebius 866230487Sglebius LIST_FOREACH(hp, &priv->hash[h], next) 867230487Sglebius if (strcmp(NG_HOOK_NAME(hp->hook), name) == 0) 868230487Sglebius return (hp->hook); 869230487Sglebius 870230487Sglebius return (NULL); 871230487Sglebius} 872230487Sglebius 87352419Sjulian/* 87452419Sjulian * Incoming messages get passed up to the control socket. 87552885Sjulian * Unless they are for us specifically (socket_type) 87652419Sjulian */ 87752419Sjulianstatic int 87870700Sjulianngs_rcvmsg(node_p node, item_p item, hook_p lasthook) 87952419Sjulian{ 88072053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 881208300Sattilio struct ngpcb *pcbp; 882163475Sglebius struct socket *so; 883163468Sglebius struct sockaddr_ng addr; 884163468Sglebius struct ng_mesg *msg; 885163468Sglebius struct mbuf *m; 886163468Sglebius ng_ID_t retaddr = NGI_RETADDR(item); 88752419Sjulian int addrlen; 88852419Sjulian int error = 0; 88952419Sjulian 89070700Sjulian NGI_GET_MSG(item, msg); 891163468Sglebius NG_FREE_ITEM(item); 89270700Sjulian 893163468Sglebius /* 894208300Sattilio * Grab priv->mtx here to prevent destroying of control socket 895208300Sattilio * after checking that priv->ctlsock is not NULL. 896208300Sattilio */ 897208300Sattilio mtx_lock(&priv->mtx); 898208300Sattilio pcbp = priv->ctlsock; 899208300Sattilio 900208300Sattilio /* 901163468Sglebius * Only allow mesgs to be passed if we have the control socket. 902163468Sglebius * Data sockets can only support the generic messages. 903163468Sglebius */ 90452419Sjulian if (pcbp == NULL) { 905208300Sattilio mtx_unlock(&priv->mtx); 90652419Sjulian TRAP_ERROR; 907163468Sglebius NG_FREE_MSG(msg); 90852419Sjulian return (EINVAL); 90952419Sjulian } 910163475Sglebius so = pcbp->ng_socket; 911208300Sattilio SOCKBUF_LOCK(&so->so_rcv); 912146296Sglebius 913208300Sattilio /* As long as the race is handled, priv->mtx may be unlocked now. */ 914208300Sattilio mtx_unlock(&priv->mtx); 915208300Sattilio 91670784Sjulian#ifdef TRACE_MESSAGES 917146296Sglebius printf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n", 918146296Sglebius retaddr, 919146296Sglebius msg->header.typecookie, 920146296Sglebius msg->header.cmd, 921146296Sglebius msg->header.cmdstr, 922146296Sglebius msg->header.flags, 923146296Sglebius msg->header.token); 92470784Sjulian#endif 92570784Sjulian 92652885Sjulian if (msg->header.typecookie == NGM_SOCKET_COOKIE) { 92752885Sjulian switch (msg->header.cmd) { 92852885Sjulian case NGM_SOCK_CMD_NOLINGER: 92972053Sjulian priv->flags |= NGS_FLAG_NOLINGER; 93052885Sjulian break; 93152885Sjulian case NGM_SOCK_CMD_LINGER: 93272053Sjulian priv->flags &= ~NGS_FLAG_NOLINGER; 93352885Sjulian break; 93452885Sjulian default: 93552885Sjulian error = EINVAL; /* unknown command */ 93652885Sjulian } 937208300Sattilio SOCKBUF_UNLOCK(&so->so_rcv); 938208300Sattilio 939163468Sglebius /* Free the message and return. */ 94070700Sjulian NG_FREE_MSG(msg); 941163468Sglebius return (error); 942163468Sglebius } 94352885Sjulian 944163468Sglebius /* Get the return address into a sockaddr. */ 945163468Sglebius bzero(&addr, sizeof(addr)); 946163468Sglebius addr.sg_len = sizeof(addr); 947163468Sglebius addr.sg_family = AF_NETGRAPH; 948163468Sglebius addrlen = snprintf((char *)&addr.sg_data, sizeof(addr.sg_data), 949163468Sglebius "[%x]:", retaddr); 950163468Sglebius if (addrlen < 0 || addrlen > sizeof(addr.sg_data)) { 951208300Sattilio SOCKBUF_UNLOCK(&so->so_rcv); 952163468Sglebius printf("%s: snprintf([%x]) failed - %d\n", __func__, retaddr, 953163468Sglebius addrlen); 954163468Sglebius NG_FREE_MSG(msg); 955163468Sglebius return (EINVAL); 95652885Sjulian } 957163468Sglebius 958163468Sglebius /* Copy the message itself into an mbuf chain. */ 959163468Sglebius m = m_devget((caddr_t)msg, sizeof(struct ng_mesg) + msg->header.arglen, 960163468Sglebius 0, NULL, NULL); 961163468Sglebius 962163468Sglebius /* 963163468Sglebius * Here we free the message. We need to do that 964163468Sglebius * regardless of whether we got mbufs. 965163468Sglebius */ 966163468Sglebius NG_FREE_MSG(msg); 967163468Sglebius 968163468Sglebius if (m == NULL) { 969208300Sattilio SOCKBUF_UNLOCK(&so->so_rcv); 97052419Sjulian TRAP_ERROR; 971163468Sglebius return (ENOBUFS); 97252419Sjulian } 97352419Sjulian 974163468Sglebius /* Send it up to the socket. */ 975208300Sattilio if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)&addr, m, 976208300Sattilio NULL) == 0) { 977208300Sattilio SOCKBUF_UNLOCK(&so->so_rcv); 978163468Sglebius TRAP_ERROR; 979163468Sglebius m_freem(m); 980177071Smav return (ENOBUFS); 981163468Sglebius } 982208300Sattilio sorwakeup_locked(so); 983163468Sglebius 98452419Sjulian return (error); 98552419Sjulian} 98652419Sjulian 98752419Sjulian/* 98852419Sjulian * Receive data on a hook 98952419Sjulian */ 99052419Sjulianstatic int 99170700Sjulianngs_rcvdata(hook_p hook, item_p item) 99252419Sjulian{ 99372053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 99472053Sjulian struct ngpcb *const pcbp = priv->datasock; 99552419Sjulian struct socket *so; 99652419Sjulian struct sockaddr_ng *addr; 997125028Sharti char *addrbuf[NG_HOOKSIZ + 4]; 99852419Sjulian int addrlen; 99970700Sjulian struct mbuf *m; 100052419Sjulian 100170700Sjulian NGI_GET_M(item, m); 100270700Sjulian NG_FREE_ITEM(item); 1003163463Sglebius 1004163463Sglebius /* If there is no data socket, black-hole it. */ 100552419Sjulian if (pcbp == NULL) { 100670700Sjulian NG_FREE_M(m); 100752419Sjulian return (0); 100852419Sjulian } 100952419Sjulian so = pcbp->ng_socket; 101052419Sjulian 101152419Sjulian /* Get the return address into a sockaddr. */ 1012125028Sharti addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKSIZ - 1 */ 101352419Sjulian addr = (struct sockaddr_ng *) addrbuf; 101452419Sjulian addr->sg_len = addrlen + 3; 101552419Sjulian addr->sg_family = AF_NETGRAPH; 101670784Sjulian bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); 101752419Sjulian addr->sg_data[addrlen] = '\0'; 101852419Sjulian 1019163463Sglebius /* Try to tell the socket which hook it came in on. */ 1020163463Sglebius if (sbappendaddr(&so->so_rcv, (struct sockaddr *)addr, m, NULL) == 0) { 102152419Sjulian m_freem(m); 102252419Sjulian TRAP_ERROR; 102352419Sjulian return (ENOBUFS); 102452419Sjulian } 102552419Sjulian sorwakeup(so); 102652419Sjulian return (0); 102752419Sjulian} 102852419Sjulian 102952419Sjulian/* 103053498Sjulian * Hook disconnection 103152885Sjulian * 103252885Sjulian * For this type, removal of the last link destroys the node 103352885Sjulian * if the NOLINGER flag is set. 103452885Sjulian */ 103552885Sjulianstatic int 103652885Sjulianngs_disconnect(hook_p hook) 103752885Sjulian{ 103872053Sjulian node_p node = NG_HOOK_NODE(hook); 103972053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 1040230487Sglebius struct hookpriv *hp = NG_HOOK_PRIVATE(hook); 104152885Sjulian 1042230487Sglebius LIST_REMOVE(hp, next); 1043230487Sglebius free(hp, M_NETGRAPH_SOCK); 1044230487Sglebius 1045163463Sglebius if ((priv->datasock) && (priv->datasock->ng_socket)) { 1046163463Sglebius if (NG_NODE_NUMHOOKS(node) == 1) 104772053Sjulian priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; 1048163463Sglebius else 104972053Sjulian priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; 105052885Sjulian } 105172053Sjulian 1052163463Sglebius if ((priv->flags & NGS_FLAG_NOLINGER) && 1053163463Sglebius (NG_NODE_NUMHOOKS(node) == 0) && (NG_NODE_IS_VALID(node))) 105472053Sjulian ng_rmnode_self(node); 1055163463Sglebius 105652885Sjulian return (0); 105752885Sjulian} 105852885Sjulian 105952885Sjulian/* 106052419Sjulian * Do local shutdown processing. 106152419Sjulian * In this case, that involves making sure the socket 106252419Sjulian * knows we should be shutting down. 106352419Sjulian */ 106452419Sjulianstatic int 106570700Sjulianngs_shutdown(node_p node) 106652419Sjulian{ 106772053Sjulian struct ngsock *const priv = NG_NODE_PRIVATE(node); 1068208300Sattilio struct ngpcb *dpcbp, *pcbp; 106952419Sjulian 1070208300Sattilio mtx_lock(&priv->mtx); 1071208300Sattilio dpcbp = priv->datasock; 1072208300Sattilio pcbp = priv->ctlsock; 1073208300Sattilio 1074151975Sglebius if (dpcbp != NULL) 107552419Sjulian soisdisconnected(dpcbp->ng_socket); 1076151975Sglebius 1077151975Sglebius if (pcbp != NULL) 107852419Sjulian soisdisconnected(pcbp->ng_socket); 1079151975Sglebius 1080151975Sglebius priv->node = NULL; 108170784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 1082151975Sglebius ng_socket_free_priv(priv); 1083151975Sglebius 108470784Sjulian NG_NODE_UNREF(node); 108552419Sjulian return (0); 108652419Sjulian} 108752419Sjulian 1088147774Sglebiusstatic void 1089147774Sglebiusng_socket_item_applied(void *context, int error) 1090147774Sglebius{ 1091147774Sglebius struct ngsock *const priv = (struct ngsock *)context; 1092147774Sglebius 1093147774Sglebius mtx_lock(&priv->mtx); 1094147774Sglebius priv->error = error; 1095147774Sglebius wakeup(priv); 1096147774Sglebius mtx_unlock(&priv->mtx); 1097147774Sglebius 1098147774Sglebius} 1099147774Sglebius 110072055Sjulianstatic int 110172055Sjuliandummy_disconnect(struct socket *so) 110272055Sjulian{ 110372055Sjulian return (0); 110472055Sjulian} 110552419Sjulian/* 110652419Sjulian * Control and data socket type descriptors 1107160549Srwatson * 1108160549Srwatson * XXXRW: Perhaps _close should do something? 110952419Sjulian */ 111052419Sjulian 111152419Sjulianstatic struct pr_usrreqs ngc_usrreqs = { 1112137386Sphk .pru_abort = NULL, 1113137386Sphk .pru_attach = ngc_attach, 1114137386Sphk .pru_bind = ngc_bind, 1115137386Sphk .pru_connect = ngc_connect, 1116137386Sphk .pru_detach = ngc_detach, 1117137386Sphk .pru_disconnect = dummy_disconnect, 1118137386Sphk .pru_peeraddr = NULL, 1119137386Sphk .pru_send = ngc_send, 1120137386Sphk .pru_shutdown = NULL, 1121169462Srwatson .pru_sockaddr = ng_getsockaddr, 1122160549Srwatson .pru_close = NULL, 112352419Sjulian}; 112452419Sjulian 112552419Sjulianstatic struct pr_usrreqs ngd_usrreqs = { 1126137386Sphk .pru_abort = NULL, 1127137386Sphk .pru_attach = ngd_attach, 1128137386Sphk .pru_bind = NULL, 1129137386Sphk .pru_connect = ngd_connect, 1130137386Sphk .pru_detach = ngd_detach, 1131137386Sphk .pru_disconnect = dummy_disconnect, 1132137386Sphk .pru_peeraddr = NULL, 1133137386Sphk .pru_send = ngd_send, 1134137386Sphk .pru_shutdown = NULL, 1135169462Srwatson .pru_sockaddr = ng_getsockaddr, 1136160549Srwatson .pru_close = NULL, 113752419Sjulian}; 113852419Sjulian 113952419Sjulian/* 114052419Sjulian * Definitions of protocols supported in the NETGRAPH domain. 114152419Sjulian */ 114252419Sjulian 114352419Sjulianextern struct domain ngdomain; /* stop compiler warnings */ 114452419Sjulian 114552419Sjulianstatic struct protosw ngsw[] = { 1146152242Sru{ 1147152242Sru .pr_type = SOCK_DGRAM, 1148152242Sru .pr_domain = &ngdomain, 1149152242Sru .pr_protocol = NG_CONTROL, 1150152242Sru .pr_flags = PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, 1151152242Sru .pr_usrreqs = &ngc_usrreqs 1152152242Sru}, 1153152242Sru{ 1154152242Sru .pr_type = SOCK_DGRAM, 1155152242Sru .pr_domain = &ngdomain, 1156152242Sru .pr_protocol = NG_DATA, 1157152242Sru .pr_flags = PR_ATOMIC | PR_ADDR, 1158152242Sru .pr_usrreqs = &ngd_usrreqs 1159152242Sru} 116052419Sjulian}; 116152419Sjulian 116252419Sjulianstruct domain ngdomain = { 1163152242Sru .dom_family = AF_NETGRAPH, 1164152242Sru .dom_name = "netgraph", 1165152242Sru .dom_protosw = ngsw, 1166298431Spfg .dom_protoswNPROTOSW = &ngsw[nitems(ngsw)] 116752419Sjulian}; 116852419Sjulian 116952419Sjulian/* 1170163463Sglebius * Handle loading and unloading for this node type. 117152419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition). 117252419Sjulian */ 117352419Sjulianstatic int 117452419Sjulianngs_mod_event(module_t mod, int event, void *data) 117552419Sjulian{ 117652419Sjulian int error = 0; 117752419Sjulian 117852419Sjulian switch (event) { 117952419Sjulian case MOD_LOAD: 1180205082Sglebius mtx_init(&ngsocketlist_mtx, "ng_socketlist", NULL, MTX_DEF); 118152419Sjulian break; 118252419Sjulian case MOD_UNLOAD: 1183205082Sglebius /* Ensure there are no open netgraph sockets. */ 1184205082Sglebius if (!LIST_EMPTY(&ngsocklist)) { 1185205082Sglebius error = EBUSY; 1186205082Sglebius break; 1187205082Sglebius } 118852419Sjulian#ifdef NOTYET 118952419Sjulian /* Unregister protocol domain XXX can't do this yet.. */ 119052419Sjulian#endif 1191195837Srwatson error = EBUSY; 119252419Sjulian break; 119352419Sjulian default: 119452419Sjulian error = EOPNOTSUPP; 119552419Sjulian break; 119652419Sjulian } 119752419Sjulian return (error); 119852419Sjulian} 119952419Sjulian 1200195837SrwatsonVNET_DOMAIN_SET(ng); 1201195837Srwatson 1202273377ShselaskySYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, AF_NETGRAPH, ""); 1203227309Sedstatic SYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); 1204273377ShselaskySYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, NG_DATA, ""); 1205227309Sedstatic SYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); 1206273377ShselaskySYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, NG_CONTROL, ""); 120752419Sjulian 1208