ng_socket.c revision 53098
152419Sjulian 252419Sjulian/* 352419Sjulian * ng_socket.c 452419Sjulian * 552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 652419Sjulian * All rights reserved. 752419Sjulian * 852419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 952419Sjulian * redistribution of this software, in source or object code forms, with or 1052419Sjulian * without modifications are expressly permitted by Whistle Communications; 1152419Sjulian * provided, however, that: 1252419Sjulian * 1. Any and all reproductions of the source or object code must include the 1352419Sjulian * copyright notice above and the following disclaimer of warranties; and 1452419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1552419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1652419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1752419Sjulian * such appears in the above copyright notice or in the software. 1852419Sjulian * 1952419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2052419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2152419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2252419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2352419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2452419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2552419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2652419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2752419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2852419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2952419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3052419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3152419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3252419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3352419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3452419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3552419Sjulian * OF SUCH DAMAGE. 3652419Sjulian * 3752419Sjulian * Author: Julian Elischer <julian@whistle.com> 3852419Sjulian * 3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_socket.c 53098 1999-11-11 20:08:04Z brian $ 4052752Sjulian * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $ 4152419Sjulian */ 4252419Sjulian 4352419Sjulian/* 4452419Sjulian * Netgraph socket nodes 4552419Sjulian * 4652419Sjulian * There are two types of netgraph sockets, control and data. 4752419Sjulian * Control sockets have a netgraph node, but data sockets are 4852419Sjulian * parasitic on control sockets, and have no node of their own. 4952419Sjulian */ 5052419Sjulian 5152419Sjulian#include <sys/param.h> 5252419Sjulian#include <sys/systm.h> 5352419Sjulian#include <sys/proc.h> 5452419Sjulian#include <sys/domain.h> 5552419Sjulian#include <sys/errno.h> 5652419Sjulian#include <sys/kernel.h> 5752419Sjulian#include <sys/file.h> 5852419Sjulian#include <sys/filedesc.h> 5952419Sjulian#include <sys/malloc.h> 6052419Sjulian#include <sys/queue.h> 6152419Sjulian#include <sys/mbuf.h> 6252419Sjulian#include <sys/protosw.h> 6352419Sjulian#include <sys/socket.h> 6452419Sjulian#include <sys/socketvar.h> 6552419Sjulian#include <sys/sysctl.h> 6652419Sjulian#ifdef NOTYET 6752419Sjulian#include <sys/vnode.h> 6852419Sjulian#endif 6952419Sjulian#include <netgraph/ng_message.h> 7052419Sjulian#include <netgraph/netgraph.h> 7152919Sjulian#include <netgraph/ng_socketvar.h> 7252419Sjulian#include <netgraph/ng_socket.h> 7352419Sjulian 7452419Sjulian/* 7552419Sjulian * It's Ascii-art time! 7652419Sjulian * +-------------+ +-------------+ 7752419Sjulian * |socket (ctl)| |socket (data)| 7852419Sjulian * +-------------+ +-------------+ 7952419Sjulian * ^ ^ 8052419Sjulian * | | 8152419Sjulian * v v 8252419Sjulian * +-----------+ +-----------+ 8352419Sjulian * |pcb (ctl)| |pcb (data)| 8452419Sjulian * +-----------+ +-----------+ 8552419Sjulian * ^ ^ 8652419Sjulian * | | 8752419Sjulian * v v 8852419Sjulian * +--------------------------+ 8952419Sjulian * | Socket type private | 9052419Sjulian * | data | 9152419Sjulian * +--------------------------+ 9252419Sjulian * ^ 9352419Sjulian * | 9452419Sjulian * v 9552419Sjulian * +----------------+ 9652419Sjulian * | struct ng_node | 9752419Sjulian * +----------------+ 9852419Sjulian */ 9952419Sjulian 10052419Sjulian/* Netgraph node methods */ 10152752Sjulianstatic ng_constructor_t ngs_constructor; 10252752Sjulianstatic ng_rcvmsg_t ngs_rcvmsg; 10352752Sjulianstatic ng_shutdown_t ngs_rmnode; 10452752Sjulianstatic ng_newhook_t ngs_newhook; 10552752Sjulianstatic ng_rcvdata_t ngs_rcvdata; 10652885Sjulianstatic ng_disconnect_t ngs_disconnect; 10752419Sjulian 10852419Sjulian/* Internal methods */ 10952419Sjulianstatic int ng_attach_data(struct socket *so); 11052419Sjulianstatic int ng_attach_cntl(struct socket *so); 11152419Sjulianstatic int ng_attach_common(struct socket *so, int type); 11252419Sjulianstatic void ng_detach_common(struct ngpcb *pcbp, int type); 11352419Sjulian/*static int ng_internalize(struct mbuf *m, struct proc *p); */ 11452419Sjulian 11552419Sjulianstatic int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp); 11652419Sjulianstatic int ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp); 11752419Sjulianstatic int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); 11852419Sjulian 11952419Sjulianstatic int ngs_mod_event(module_t mod, int event, void *data); 12052419Sjulianstatic int ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, 12152419Sjulian struct sockaddr_ng *addr); 12252419Sjulian 12352419Sjulian/* Netgraph type descriptor */ 12452419Sjulianstatic struct ng_type typestruct = { 12552419Sjulian NG_VERSION, 12652419Sjulian NG_SOCKET_NODE_TYPE, 12752419Sjulian ngs_mod_event, 12852419Sjulian ngs_constructor, 12952419Sjulian ngs_rcvmsg, 13052419Sjulian ngs_rmnode, 13152419Sjulian ngs_newhook, 13252419Sjulian NULL, 13352419Sjulian NULL, 13452419Sjulian ngs_rcvdata, 13552419Sjulian ngs_rcvdata, 13652885Sjulian ngs_disconnect 13752419Sjulian}; 13852419SjulianNETGRAPH_INIT(socket, &typestruct); 13952419Sjulian 14052419Sjulian/* Buffer space */ 14152419Sjulianstatic u_long ngpdg_sendspace = 2 * 1024; /* really max datagram size */ 14252419Sjulianstatic u_long ngpdg_recvspace = 20 * 1024; 14352419Sjulian 14452419Sjulian/* List of all sockets */ 14552419SjulianLIST_HEAD(, ngpcb) ngsocklist; 14652419Sjulian 14752419Sjulian#define sotongpcb(so) ((struct ngpcb *)so->so_pcb) 14852419Sjulian 14952419Sjulian/* If getting unexplained errors returned, set this to "Debugger("X"); */ 15052419Sjulian#ifndef TRAP_ERROR 15152419Sjulian#define TRAP_ERROR 15252419Sjulian#endif 15352419Sjulian 15452419Sjulian/*************************************************************** 15552419Sjulian Control sockets 15652419Sjulian***************************************************************/ 15752419Sjulian 15852419Sjulianstatic int 15952419Sjulianngc_attach(struct socket *so, int proto, struct proc *p) 16052419Sjulian{ 16152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 16252419Sjulian 16352419Sjulian if (pcbp != NULL) 16452419Sjulian return (EISCONN); 16552419Sjulian return (ng_attach_cntl(so)); 16652419Sjulian} 16752419Sjulian 16852419Sjulianstatic int 16952419Sjulianngc_detach(struct socket *so) 17052419Sjulian{ 17152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 17252419Sjulian 17352419Sjulian if (pcbp == NULL) 17452419Sjulian return (EINVAL); 17552419Sjulian ng_detach_common(pcbp, NG_CONTROL); 17652419Sjulian return (0); 17752419Sjulian} 17852419Sjulian 17952419Sjulianstatic int 18052419Sjulianngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 18152419Sjulian struct mbuf *control, struct proc *p) 18252419Sjulian{ 18352419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 18452419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 18552419Sjulian struct ng_mesg *resp; 18652419Sjulian struct mbuf *m0; 18752419Sjulian char *msg, *path = NULL; 18852419Sjulian int len, error = 0; 18952419Sjulian 19052419Sjulian if (pcbp == NULL) { 19152419Sjulian error = EINVAL; 19252419Sjulian goto release; 19352419Sjulian } 19452419Sjulian#ifdef NOTYET 19552419Sjulian if (control && (error = ng_internalize(control, p))) { 19652419Sjulian if (pcbp->sockdata == NULL) { 19752419Sjulian error = ENOTCONN; 19852419Sjulian goto release; 19952419Sjulian } 20052419Sjulian } 20152419Sjulian#else /* NOTYET */ 20252419Sjulian if (control) { 20352419Sjulian error = EINVAL; 20452419Sjulian goto release; 20552419Sjulian } 20652419Sjulian#endif /* NOTYET */ 20752419Sjulian 20852419Sjulian /* Require destination as there may be >= 1 hooks on this node */ 20952419Sjulian if (addr == NULL) { 21052419Sjulian error = EDESTADDRREQ; 21152419Sjulian goto release; 21252419Sjulian } 21352419Sjulian 21452419Sjulian /* Allocate an expendable buffer for the path, chop off 21552419Sjulian * the sockaddr header, and make sure it's NUL terminated */ 21652419Sjulian len = sap->sg_len - 2; 21752419Sjulian MALLOC(path, char *, len + 1, M_NETGRAPH, M_WAITOK); 21852419Sjulian if (path == NULL) { 21952419Sjulian error = ENOMEM; 22052419Sjulian goto release; 22152419Sjulian } 22252419Sjulian bcopy(sap->sg_data, path, len); 22352419Sjulian path[len] = '\0'; 22452419Sjulian 22552419Sjulian /* Move the actual message out of mbufs into a linear buffer. 22652419Sjulian * Start by adding up the size of the data. (could use mh_len?) */ 22752419Sjulian for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next) 22852419Sjulian len += m0->m_len; 22952419Sjulian 23052419Sjulian /* Move the data into a linear buffer as well. Messages are not 23152419Sjulian * delivered in mbufs. */ 23252419Sjulian MALLOC(msg, char *, len + 1, M_NETGRAPH, M_WAITOK); 23352419Sjulian if (msg == NULL) { 23452419Sjulian error = ENOMEM; 23552419Sjulian goto release; 23652419Sjulian } 23752419Sjulian m_copydata(m, 0, len, msg); 23852419Sjulian 23952419Sjulian /* The callee will free the msg when done. The addr is our business. */ 24052419Sjulian error = ng_send_msg(pcbp->sockdata->node, 24152419Sjulian (struct ng_mesg *) msg, path, &resp); 24252419Sjulian 24352419Sjulian /* If the callee responded with a synchronous response, then put it 24452419Sjulian * back on the receive side of the socket; sap is source address. */ 24552419Sjulian if (error == 0 && resp != NULL) 24652419Sjulian error = ship_msg(pcbp, resp, sap); 24752419Sjulian 24852419Sjulianrelease: 24952419Sjulian if (path != NULL) 25052419Sjulian FREE(path, M_NETGRAPH); 25152419Sjulian if (control != NULL) 25252419Sjulian m_freem(control); 25352419Sjulian if (m != NULL) 25452419Sjulian m_freem(m); 25552419Sjulian return (error); 25652419Sjulian} 25752419Sjulian 25852419Sjulianstatic int 25952419Sjulianngc_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 26052419Sjulian{ 26152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 26252419Sjulian 26352419Sjulian if (pcbp == 0) 26452419Sjulian return (EINVAL); 26552419Sjulian return (ng_bind(nam, pcbp)); 26652419Sjulian} 26752419Sjulian 26852419Sjulianstatic int 26952419Sjulianngc_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 27052419Sjulian{ 27152419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 27252419Sjulian 27352419Sjulian if (pcbp == 0) 27452419Sjulian return (EINVAL); 27552419Sjulian return (ng_connect_cntl(nam, pcbp)); 27652419Sjulian} 27752419Sjulian 27852419Sjulian/*************************************************************** 27952419Sjulian Data sockets 28052419Sjulian***************************************************************/ 28152419Sjulian 28252419Sjulianstatic int 28352419Sjulianngd_attach(struct socket *so, int proto, struct proc *p) 28452419Sjulian{ 28552419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 28652419Sjulian 28752419Sjulian if (pcbp != NULL) 28852419Sjulian return (EISCONN); 28952419Sjulian return (ng_attach_data(so)); 29052419Sjulian} 29152419Sjulian 29252419Sjulianstatic int 29352419Sjulianngd_detach(struct socket *so) 29452419Sjulian{ 29552419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 29652419Sjulian 29752419Sjulian if (pcbp == NULL) 29852419Sjulian return (EINVAL); 29952419Sjulian ng_detach_common(pcbp, NG_DATA); 30052419Sjulian return (0); 30152419Sjulian} 30252419Sjulian 30352419Sjulianstatic int 30452419Sjulianngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 30552419Sjulian struct mbuf *control, struct proc *p) 30652419Sjulian{ 30752419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 30852419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; 30952419Sjulian char *hookname = NULL; 31052419Sjulian meta_p mp = NULL; 31152419Sjulian int len, error; 31252419Sjulian hook_p hook; 31352419Sjulian 31452419Sjulian if ((pcbp == NULL) || (control != NULL)) { 31552419Sjulian error = EINVAL; 31652419Sjulian goto release; 31752419Sjulian } 31852419Sjulian if (pcbp->sockdata == NULL) { 31952419Sjulian error = ENOTCONN; 32052419Sjulian goto release; 32152419Sjulian } 32252419Sjulian if (addr == NULL) { 32352419Sjulian error = EDESTADDRREQ; 32452419Sjulian goto release; 32552419Sjulian } 32652419Sjulian 32752419Sjulian /* Allocate an expendable buffer for the hook name, chop off 32852419Sjulian * the sockaddr header, and make sure it's NUL terminated */ 32952419Sjulian len = sap->sg_len - 2; 33052419Sjulian MALLOC(hookname, char *, len + 1, M_NETGRAPH, M_WAITOK); 33152419Sjulian if (hookname == NULL) { 33252419Sjulian error = ENOMEM; 33352419Sjulian goto release; 33452419Sjulian } 33552419Sjulian bcopy(sap->sg_data, hookname, len); 33652419Sjulian hookname[len] = '\0'; 33752419Sjulian 33852419Sjulian /* Find the correct hook from 'hookname' */ 33952419Sjulian LIST_FOREACH(hook, &pcbp->sockdata->node->hooks, hooks) { 34052419Sjulian if (strcmp(hookname, hook->name) == 0) 34152419Sjulian break; 34252419Sjulian } 34352419Sjulian 34452419Sjulian /* Send data (OK if hook is NULL) */ 34552419Sjulian NG_SEND_DATA(error, hook, m, mp); /* makes m NULL */ 34652419Sjulian 34752419Sjulianrelease: 34852419Sjulian if (hookname != NULL) 34952419Sjulian FREE(hookname, M_NETGRAPH); 35052419Sjulian if (control != NULL) 35152419Sjulian m_freem(control); 35252419Sjulian if (m != NULL) 35352419Sjulian m_freem(m); 35452419Sjulian return (error); 35552419Sjulian} 35652419Sjulian 35752419Sjulianstatic int 35852419Sjulianngd_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 35952419Sjulian{ 36052419Sjulian struct ngpcb *const pcbp = sotongpcb(so); 36152419Sjulian 36252419Sjulian if (pcbp == 0) 36352419Sjulian return (EINVAL); 36452419Sjulian return (ng_connect_data(nam, pcbp)); 36552419Sjulian} 36652419Sjulian 36752419Sjulian/* 36852419Sjulian * Used for both data and control sockets 36952419Sjulian */ 37052419Sjulianstatic int 37152419Sjulianng_setsockaddr(struct socket *so, struct sockaddr **addr) 37252419Sjulian{ 37353098Sbrian struct ngpcb *pcbp; 37453098Sbrian struct sockaddr_ng *sg; 37553098Sbrian int sg_len, namelen, s; 37652419Sjulian 37753098Sbrian /* Why isn't sg_data a `char[1]' ? :-( */ 37853098Sbrian sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1; 37953098Sbrian 38053098Sbrian s = splnet(); 38153098Sbrian pcbp = sotongpcb(so); 38253098Sbrian if (pcbp == 0) { 38353098Sbrian splx(s); 38452419Sjulian return (EINVAL); 38553098Sbrian } 38653098Sbrian 38753098Sbrian namelen = 0; /* silence compiler ! */ 38853098Sbrian 38953098Sbrian if (pcbp->sockdata->node->name != NULL) 39053098Sbrian sg_len += namelen = strlen(pcbp->sockdata->node->name); 39153098Sbrian 39253098Sbrian MALLOC(sg, struct sockaddr_ng *, sg_len, M_SONAME, M_WAITOK); 39353098Sbrian bzero(sg, sg_len); 39453098Sbrian 39553098Sbrian if (pcbp->sockdata->node->name != NULL) 39653098Sbrian bcopy(pcbp->sockdata->node->name, sg->sg_data, namelen); 39753098Sbrian splx(s); 39853098Sbrian 39953098Sbrian sg->sg_len = sg_len; 40053098Sbrian sg->sg_family = AF_NETGRAPH; 40153098Sbrian *addr = (struct sockaddr *)sg; 40253098Sbrian 40352419Sjulian return (0); 40452419Sjulian} 40552419Sjulian 40652419Sjulian/* 40752419Sjulian * Attach a socket to it's protocol specific partner. 40852419Sjulian * For a control socket, actually create a netgraph node and attach 40952419Sjulian * to it as well. 41052419Sjulian */ 41152419Sjulian 41252419Sjulianstatic int 41352419Sjulianng_attach_cntl(struct socket *so) 41452419Sjulian{ 41552419Sjulian struct ngsock *privdata; 41652419Sjulian struct ngpcb *pcbp; 41752419Sjulian int error; 41852419Sjulian 41952419Sjulian /* Setup protocol control block */ 42052419Sjulian if ((error = ng_attach_common(so, NG_CONTROL)) != 0) 42152419Sjulian return (error); 42252419Sjulian pcbp = (struct ngpcb *) so->so_pcb; 42352419Sjulian 42452419Sjulian /* Allocate node private info */ 42552419Sjulian MALLOC(privdata, struct ngsock *, 42652419Sjulian sizeof(*privdata), M_NETGRAPH, M_WAITOK); 42752419Sjulian if (privdata == NULL) { 42852419Sjulian ng_detach_common(pcbp, NG_CONTROL); 42952419Sjulian return (ENOMEM); 43052419Sjulian } 43152419Sjulian bzero(privdata, sizeof(*privdata)); 43252419Sjulian 43352419Sjulian /* Make the generic node components */ 43452419Sjulian if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) { 43552419Sjulian FREE(privdata, M_NETGRAPH); 43652419Sjulian ng_detach_common(pcbp, NG_CONTROL); 43752419Sjulian return (error); 43852419Sjulian } 43952419Sjulian privdata->node->private = privdata; 44052419Sjulian 44152419Sjulian /* Link the pcb and the node private data */ 44252419Sjulian privdata->ctlsock = pcbp; 44352419Sjulian pcbp->sockdata = privdata; 44452419Sjulian privdata->refs++; 44552419Sjulian return (0); 44652419Sjulian} 44752419Sjulian 44852419Sjulianstatic int 44952419Sjulianng_attach_data(struct socket *so) 45052419Sjulian{ 45152419Sjulian return(ng_attach_common(so, NG_DATA)); 45252419Sjulian} 45352419Sjulian 45452419Sjulian/* 45552419Sjulian * Set up a socket protocol control block. 45652419Sjulian * This code is shared between control and data sockets. 45752419Sjulian */ 45852419Sjulianstatic int 45952419Sjulianng_attach_common(struct socket *so, int type) 46052419Sjulian{ 46152419Sjulian struct ngpcb *pcbp; 46252419Sjulian int error; 46352419Sjulian 46452419Sjulian /* Standard socket setup stuff */ 46552419Sjulian error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace); 46652419Sjulian if (error) 46752419Sjulian return (error); 46852419Sjulian 46952419Sjulian /* Allocate the pcb */ 47052419Sjulian MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK); 47152419Sjulian if (pcbp == NULL) 47252419Sjulian return (ENOMEM); 47352419Sjulian bzero(pcbp, sizeof(*pcbp)); 47452419Sjulian pcbp->type = type; 47552419Sjulian 47652419Sjulian /* Link the pcb and the socket */ 47752419Sjulian so->so_pcb = (caddr_t) pcbp; 47852419Sjulian pcbp->ng_socket = so; 47952419Sjulian 48052419Sjulian /* Add the socket to linked list */ 48152419Sjulian LIST_INSERT_HEAD(&ngsocklist, pcbp, socks); 48252419Sjulian return (0); 48352419Sjulian} 48452419Sjulian 48552419Sjulian/* 48652419Sjulian * Disassociate the socket from it's protocol specific 48752419Sjulian * partner. If it's attached to a node's private data structure, 48852419Sjulian * then unlink from that too. If we were the last socket attached to it, 48952419Sjulian * then shut down the entire node. Shared code for control and data sockets. 49052419Sjulian */ 49152419Sjulianstatic void 49252419Sjulianng_detach_common(struct ngpcb *pcbp, int which) 49352419Sjulian{ 49452419Sjulian struct ngsock *sockdata; 49552419Sjulian 49652419Sjulian if (pcbp->sockdata) { 49752419Sjulian sockdata = pcbp->sockdata; 49852419Sjulian pcbp->sockdata = NULL; 49952419Sjulian switch (which) { 50052419Sjulian case NG_CONTROL: 50152419Sjulian sockdata->ctlsock = NULL; 50252419Sjulian break; 50352419Sjulian case NG_DATA: 50452419Sjulian sockdata->datasock = NULL; 50552419Sjulian break; 50652419Sjulian default: 50752419Sjulian panic(__FUNCTION__); 50852419Sjulian } 50952419Sjulian if ((--sockdata->refs == 0) && (sockdata->node != NULL)) 51052419Sjulian ng_rmnode(sockdata->node); 51152419Sjulian } 51252419Sjulian pcbp->ng_socket->so_pcb = NULL; 51352419Sjulian pcbp->ng_socket = NULL; 51452419Sjulian LIST_REMOVE(pcbp, socks); 51552419Sjulian FREE(pcbp, M_PCB); 51652419Sjulian} 51752419Sjulian 51852419Sjulian#ifdef NOTYET 51952419Sjulian/* 52052419Sjulian * File descriptors can be passed into a AF_NETGRAPH socket. 52152419Sjulian * Note, that file descriptors cannot be passed OUT. 52252419Sjulian * Only character device descriptors are accepted. 52352419Sjulian * Character devices are useful to connect a graph to a device, 52452419Sjulian * which after all is the purpose of this whole system. 52552419Sjulian */ 52652419Sjulianstatic int 52752419Sjulianng_internalize(struct mbuf *control, struct proc *p) 52852419Sjulian{ 52952419Sjulian struct filedesc *fdp = p->p_fd; 53052419Sjulian struct cmsghdr *cm = mtod(control, struct cmsghdr *); 53152419Sjulian struct file *fp; 53252419Sjulian struct vnode *vn; 53352419Sjulian int oldfds; 53452419Sjulian int fd; 53552419Sjulian 53652419Sjulian if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 53752419Sjulian cm->cmsg_len != control->m_len) { 53852419Sjulian TRAP_ERROR; 53952419Sjulian return (EINVAL); 54052419Sjulian } 54152419Sjulian 54252419Sjulian /* Check there is only one FD. XXX what would more than one signify? */ 54352419Sjulian oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int); 54452419Sjulian if (oldfds != 1) { 54552419Sjulian TRAP_ERROR; 54652419Sjulian return (EINVAL); 54752419Sjulian } 54852419Sjulian 54952419Sjulian /* Check that the FD given is legit. and change it to a pointer to a 55052419Sjulian * struct file. */ 55152419Sjulian fd = *(int *) (cm + 1); 55252419Sjulian if ((unsigned) fd >= fdp->fd_nfiles 55352419Sjulian || (fp = fdp->fd_ofiles[fd]) == NULL) { 55452419Sjulian return (EBADF); 55552419Sjulian } 55652419Sjulian 55752419Sjulian /* Depending on what kind of resource it is, act differently. For 55852419Sjulian * devices, we treat it as a file. For a AF_NETGRAPH socket, 55952419Sjulian * shortcut straight to the node. */ 56052419Sjulian switch (fp->f_type) { 56152419Sjulian case DTYPE_VNODE: 56252419Sjulian vn = (struct vnode *) fp->f_data; 56352419Sjulian if (vn && (vn->v_type == VCHR)) { 56452419Sjulian /* for a VCHR, actually reference the FILE */ 56552419Sjulian fp->f_count++; 56652419Sjulian /* XXX then what :) */ 56752419Sjulian /* how to pass on to other modules? */ 56852419Sjulian } else { 56952419Sjulian TRAP_ERROR; 57052419Sjulian return (EINVAL); 57152419Sjulian } 57252419Sjulian break; 57352419Sjulian default: 57452419Sjulian TRAP_ERROR; 57552419Sjulian return (EINVAL); 57652419Sjulian } 57752419Sjulian return (0); 57852419Sjulian} 57952419Sjulian#endif /* NOTYET */ 58052419Sjulian 58152419Sjulian/* 58252419Sjulian * Connect the data socket to a named control socket node. 58352419Sjulian */ 58452419Sjulianstatic int 58552419Sjulianng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) 58652419Sjulian{ 58752419Sjulian struct sockaddr_ng *sap; 58852419Sjulian node_p farnode; 58952419Sjulian struct ngsock *sockdata; 59052419Sjulian int error; 59152419Sjulian 59252419Sjulian /* If we are already connected, don't do it again */ 59352419Sjulian if (pcbp->sockdata != NULL) 59452419Sjulian return (EISCONN); 59552419Sjulian 59652419Sjulian /* Find the target (victim) and check it doesn't already have a data 59752419Sjulian * socket. Also check it is a 'socket' type node. */ 59852419Sjulian sap = (struct sockaddr_ng *) nam; 59952419Sjulian if ((error = ng_path2node(NULL, sap->sg_data, &farnode, NULL))) 60052419Sjulian return (error); 60152419Sjulian 60252419Sjulian if (strcmp(farnode->type->name, NG_SOCKET_NODE_TYPE) != 0) 60352419Sjulian return (EINVAL); 60452419Sjulian sockdata = farnode->private; 60552419Sjulian if (sockdata->datasock != NULL) 60652419Sjulian return (EADDRINUSE); 60752419Sjulian 60852419Sjulian /* Link the PCB and the private data struct. and note the extra 60952419Sjulian * reference */ 61052419Sjulian sockdata->datasock = pcbp; 61152419Sjulian pcbp->sockdata = sockdata; 61252419Sjulian sockdata->refs++; 61352419Sjulian return (0); 61452419Sjulian} 61552419Sjulian 61652419Sjulian/* 61752419Sjulian * Connect the existing control socket node to a named node:hook. 61852419Sjulian * The hook we use on this end is the same name as the remote node name. 61952419Sjulian */ 62052419Sjulianstatic int 62152419Sjulianng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp) 62252419Sjulian{ 62352419Sjulian struct ngsock *const sockdata = pcbp->sockdata; 62452419Sjulian struct sockaddr_ng *sap; 62552419Sjulian char *node, *hook; 62652419Sjulian node_p farnode; 62752419Sjulian int rtn, error; 62852419Sjulian 62952419Sjulian sap = (struct sockaddr_ng *) nam; 63052419Sjulian rtn = ng_path_parse(sap->sg_data, &node, NULL, &hook); 63152419Sjulian if (rtn < 0 || node == NULL || hook == NULL) { 63252419Sjulian TRAP_ERROR; 63352419Sjulian return (EINVAL); 63452419Sjulian } 63552419Sjulian farnode = ng_findname(sockdata->node, node); 63652419Sjulian if (farnode == NULL) { 63752419Sjulian TRAP_ERROR; 63852419Sjulian return (EADDRNOTAVAIL); 63952419Sjulian } 64052419Sjulian 64152419Sjulian /* Connect, using a hook name the same as the far node name. */ 64252419Sjulian error = ng_con_nodes(sockdata->node, node, farnode, hook); 64352419Sjulian return error; 64452419Sjulian} 64552419Sjulian 64652419Sjulian/* 64752419Sjulian * Binding a socket means giving the corresponding node a name 64852419Sjulian */ 64952419Sjulianstatic int 65052419Sjulianng_bind(struct sockaddr *nam, struct ngpcb *pcbp) 65152419Sjulian{ 65252419Sjulian struct ngsock *const sockdata = pcbp->sockdata; 65352419Sjulian struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; 65452419Sjulian 65552419Sjulian if (sockdata == NULL) { 65652419Sjulian TRAP_ERROR; 65752419Sjulian return (EINVAL); 65852419Sjulian } 65952419Sjulian if (sap->sg_len < 3 || sap->sg_data[sap->sg_len - 3] != '\0') { 66052419Sjulian TRAP_ERROR; 66152419Sjulian return (EINVAL); 66252419Sjulian } 66352419Sjulian return (ng_name_node(sockdata->node, sap->sg_data)); 66452419Sjulian} 66552419Sjulian 66652419Sjulian/* 66752419Sjulian * Take a message and pass it up to the control socket associated 66852419Sjulian * with the node. 66952419Sjulian */ 67052419Sjulianstatic int 67152419Sjulianship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr) 67252419Sjulian{ 67352419Sjulian struct socket *const so = pcbp->ng_socket; 67452419Sjulian struct mbuf *mdata; 67552419Sjulian int msglen; 67652419Sjulian 67752419Sjulian /* Copy the message itself into an mbuf chain */ 67852419Sjulian msglen = sizeof(struct ng_mesg) + msg->header.arglen; 67952419Sjulian mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL); 68052419Sjulian 68152419Sjulian /* Here we free the message, as we are the end of the line. 68252419Sjulian * We need to do that regardless of whether we got mbufs. */ 68352419Sjulian FREE(msg, M_NETGRAPH); 68452419Sjulian 68552419Sjulian if (mdata == NULL) { 68652419Sjulian TRAP_ERROR; 68752419Sjulian return (ENOBUFS); 68852419Sjulian } 68952419Sjulian 69052419Sjulian /* Send it up to the socket */ 69152419Sjulian if (sbappendaddr(&so->so_rcv, 69252419Sjulian (struct sockaddr *) addr, mdata, NULL) == 0) { 69352419Sjulian TRAP_ERROR; 69452419Sjulian m_freem(mdata); 69552419Sjulian return (ENOBUFS); 69652419Sjulian } 69752419Sjulian sorwakeup(so); 69852419Sjulian return (0); 69952419Sjulian} 70052419Sjulian 70152419Sjulian/* 70252419Sjulian * You can only create new nodes from the socket end of things. 70352419Sjulian */ 70452419Sjulianstatic int 70552419Sjulianngs_constructor(node_p *nodep) 70652419Sjulian{ 70752419Sjulian return (EINVAL); 70852419Sjulian} 70952419Sjulian 71052419Sjulian/* 71152419Sjulian * We allow any hook to be connected to the node. 71252419Sjulian * There is no per-hook private information though. 71352419Sjulian */ 71452419Sjulianstatic int 71552419Sjulianngs_newhook(node_p node, hook_p hook, const char *name) 71652419Sjulian{ 71752419Sjulian hook->private = node->private; 71852419Sjulian return (0); 71952419Sjulian} 72052419Sjulian 72152419Sjulian/* 72252419Sjulian * Incoming messages get passed up to the control socket. 72352885Sjulian * Unless they are for us specifically (socket_type) 72452419Sjulian */ 72552419Sjulianstatic int 72652419Sjulianngs_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 72752419Sjulian struct ng_mesg **resp) 72852419Sjulian{ 72952419Sjulian struct ngsock *const sockdata = node->private; 73052419Sjulian struct ngpcb *const pcbp = sockdata->ctlsock; 73152419Sjulian struct sockaddr_ng *addr; 73252419Sjulian int addrlen; 73352419Sjulian int error = 0; 73452419Sjulian 73552419Sjulian /* Only allow mesgs to be passed if we have the control socket. 73652419Sjulian * Data sockets can only support the generic messages. */ 73752419Sjulian if (pcbp == NULL) { 73852419Sjulian TRAP_ERROR; 73952419Sjulian return (EINVAL); 74052419Sjulian } 74152419Sjulian 74252885Sjulian if (msg->header.typecookie == NGM_SOCKET_COOKIE) { 74352885Sjulian switch (msg->header.cmd) { 74452885Sjulian case NGM_SOCK_CMD_NOLINGER: 74552885Sjulian sockdata->flags |= NGS_FLAG_NOLINGER; 74652885Sjulian break; 74752885Sjulian case NGM_SOCK_CMD_LINGER: 74852885Sjulian sockdata->flags &= ~NGS_FLAG_NOLINGER; 74952885Sjulian break; 75052885Sjulian default: 75152885Sjulian error = EINVAL; /* unknown command */ 75252885Sjulian } 75352885Sjulian /* Free the message and return */ 75452885Sjulian FREE(msg, M_NETGRAPH); 75552885Sjulian return(error); 75652885Sjulian 75752885Sjulian } 75852419Sjulian /* Get the return address into a sockaddr */ 75952419Sjulian if ((retaddr == NULL) || (*retaddr == '\0')) 76052419Sjulian retaddr = ""; 76152419Sjulian addrlen = strlen(retaddr); 76252419Sjulian MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH, M_NOWAIT); 76352419Sjulian if (addr == NULL) { 76452419Sjulian TRAP_ERROR; 76552419Sjulian return (ENOMEM); 76652419Sjulian } 76752419Sjulian addr->sg_len = addrlen + 3; 76852419Sjulian addr->sg_family = AF_NETGRAPH; 76952419Sjulian bcopy(retaddr, addr->sg_data, addrlen); 77052419Sjulian addr->sg_data[addrlen] = '\0'; 77152419Sjulian 77252419Sjulian /* Send it up */ 77352419Sjulian error = ship_msg(pcbp, msg, addr); 77452419Sjulian FREE(addr, M_NETGRAPH); 77552419Sjulian return (error); 77652419Sjulian} 77752419Sjulian 77852419Sjulian/* 77952419Sjulian * Receive data on a hook 78052419Sjulian */ 78152419Sjulianstatic int 78252419Sjulianngs_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 78352419Sjulian{ 78452419Sjulian struct ngsock *const sockdata = hook->node->private; 78552419Sjulian struct ngpcb *const pcbp = sockdata->datasock; 78652419Sjulian struct socket *so; 78752419Sjulian struct sockaddr_ng *addr; 78852419Sjulian char *addrbuf[NG_HOOKLEN + 1 + 4]; 78952419Sjulian int addrlen; 79052419Sjulian 79152419Sjulian /* If there is no data socket, black-hole it */ 79252419Sjulian if (pcbp == NULL) { 79352419Sjulian NG_FREE_DATA(m, meta); 79452419Sjulian return (0); 79552419Sjulian } 79652419Sjulian so = pcbp->ng_socket; 79752419Sjulian 79852419Sjulian /* Get the return address into a sockaddr. */ 79952419Sjulian addrlen = strlen(hook->name); /* <= NG_HOOKLEN */ 80052419Sjulian addr = (struct sockaddr_ng *) addrbuf; 80152419Sjulian addr->sg_len = addrlen + 3; 80252419Sjulian addr->sg_family = AF_NETGRAPH; 80352419Sjulian bcopy(hook->name, addr->sg_data, addrlen); 80452419Sjulian addr->sg_data[addrlen] = '\0'; 80552419Sjulian 80652419Sjulian /* We have no use for the meta data, free/clear it now. */ 80752419Sjulian NG_FREE_META(meta); 80852419Sjulian 80952419Sjulian /* Try to tell the socket which hook it came in on */ 81052419Sjulian if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) { 81152419Sjulian m_freem(m); 81252419Sjulian TRAP_ERROR; 81352419Sjulian return (ENOBUFS); 81452419Sjulian } 81552419Sjulian sorwakeup(so); 81652419Sjulian return (0); 81752419Sjulian} 81852419Sjulian 81952419Sjulian/* 82052885Sjulian * Dook disconnection 82152885Sjulian * 82252885Sjulian * For this type, removal of the last link destroys the node 82352885Sjulian * if the NOLINGER flag is set. 82452885Sjulian */ 82552885Sjulianstatic int 82652885Sjulianngs_disconnect(hook_p hook) 82752885Sjulian{ 82852885Sjulian struct ngsock *const sockdata = hook->node->private; 82952885Sjulian 83052885Sjulian if ((sockdata->flags & NGS_FLAG_NOLINGER ) 83152885Sjulian && (hook->node->numhooks == 0)) { 83252885Sjulian ng_rmnode(hook->node); 83352885Sjulian } 83452885Sjulian return (0); 83552885Sjulian} 83652885Sjulian 83752885Sjulian/* 83852419Sjulian * Do local shutdown processing. 83952419Sjulian * In this case, that involves making sure the socket 84052419Sjulian * knows we should be shutting down. 84152419Sjulian */ 84252419Sjulianstatic int 84352419Sjulianngs_rmnode(node_p node) 84452419Sjulian{ 84552419Sjulian struct ngsock *const sockdata = node->private; 84652419Sjulian struct ngpcb *const dpcbp = sockdata->datasock; 84752419Sjulian struct ngpcb *const pcbp = sockdata->ctlsock; 84852419Sjulian 84952419Sjulian ng_cutlinks(node); 85052419Sjulian ng_unname(node); 85152419Sjulian 85252419Sjulian if (dpcbp != NULL) { 85352419Sjulian soisdisconnected(dpcbp->ng_socket); 85452419Sjulian dpcbp->sockdata = NULL; 85552419Sjulian sockdata->datasock = NULL; 85652419Sjulian sockdata->refs--; 85752419Sjulian } 85852419Sjulian if (pcbp != NULL) { 85952419Sjulian soisdisconnected(pcbp->ng_socket); 86052419Sjulian pcbp->sockdata = NULL; 86152419Sjulian sockdata->ctlsock = NULL; 86252419Sjulian sockdata->refs--; 86352419Sjulian } 86452419Sjulian node->private = NULL; 86552419Sjulian ng_unref(node); 86652419Sjulian FREE(sockdata, M_NETGRAPH); 86752419Sjulian return (0); 86852419Sjulian} 86952419Sjulian 87052419Sjulian/* 87152419Sjulian * Control and data socket type descriptors 87252419Sjulian */ 87352419Sjulian 87452419Sjulianstatic struct pr_usrreqs ngc_usrreqs = { 87552419Sjulian NULL, /* abort */ 87652419Sjulian pru_accept_notsupp, 87752419Sjulian ngc_attach, 87852419Sjulian ngc_bind, 87952419Sjulian ngc_connect, 88052419Sjulian pru_connect2_notsupp, 88152419Sjulian pru_control_notsupp, 88252419Sjulian ngc_detach, 88352419Sjulian NULL, /* disconnect */ 88452419Sjulian pru_listen_notsupp, 88552419Sjulian NULL, /* setpeeraddr */ 88652419Sjulian pru_rcvd_notsupp, 88752419Sjulian pru_rcvoob_notsupp, 88852419Sjulian ngc_send, 88952419Sjulian pru_sense_null, 89052419Sjulian NULL, /* shutdown */ 89152419Sjulian ng_setsockaddr, 89252419Sjulian sosend, 89352419Sjulian soreceive, 89452419Sjulian sopoll 89552419Sjulian}; 89652419Sjulian 89752419Sjulianstatic struct pr_usrreqs ngd_usrreqs = { 89852419Sjulian NULL, /* abort */ 89952419Sjulian pru_accept_notsupp, 90052419Sjulian ngd_attach, 90152419Sjulian NULL, /* bind */ 90252419Sjulian ngd_connect, 90352419Sjulian pru_connect2_notsupp, 90452419Sjulian pru_control_notsupp, 90552419Sjulian ngd_detach, 90652419Sjulian NULL, /* disconnect */ 90752419Sjulian pru_listen_notsupp, 90852419Sjulian NULL, /* setpeeraddr */ 90952419Sjulian pru_rcvd_notsupp, 91052419Sjulian pru_rcvoob_notsupp, 91152419Sjulian ngd_send, 91252419Sjulian pru_sense_null, 91352419Sjulian NULL, /* shutdown */ 91452419Sjulian ng_setsockaddr, 91552419Sjulian sosend, 91652419Sjulian soreceive, 91752419Sjulian sopoll 91852419Sjulian}; 91952419Sjulian 92052419Sjulian/* 92152419Sjulian * Definitions of protocols supported in the NETGRAPH domain. 92252419Sjulian */ 92352419Sjulian 92452419Sjulianextern struct domain ngdomain; /* stop compiler warnings */ 92552419Sjulian 92652419Sjulianstatic struct protosw ngsw[] = { 92752419Sjulian { 92852419Sjulian SOCK_DGRAM, 92952419Sjulian &ngdomain, 93052419Sjulian NG_CONTROL, 93152419Sjulian PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, 93252419Sjulian 0, 0, 0, 0, 93352419Sjulian NULL, 93452419Sjulian 0, 0, 0, 0, 93552419Sjulian &ngc_usrreqs 93652419Sjulian }, 93752419Sjulian { 93852419Sjulian SOCK_DGRAM, 93952419Sjulian &ngdomain, 94052419Sjulian NG_DATA, 94152419Sjulian PR_ATOMIC | PR_ADDR, 94252419Sjulian 0, 0, 0, 0, 94352419Sjulian NULL, 94452419Sjulian 0, 0, 0, 0, 94552419Sjulian &ngd_usrreqs 94652419Sjulian } 94752419Sjulian}; 94852419Sjulian 94952419Sjulianstruct domain ngdomain = { 95052419Sjulian AF_NETGRAPH, 95152419Sjulian "netgraph", 95252419Sjulian 0, 95352419Sjulian NULL, 95452419Sjulian NULL, 95552419Sjulian ngsw, 95652419Sjulian &ngsw[sizeof(ngsw) / sizeof(ngsw[0])], 95752419Sjulian 0, 95852419Sjulian NULL, 95952419Sjulian 0, 96052419Sjulian 0 96152419Sjulian}; 96252419Sjulian 96352419Sjulian/* 96452419Sjulian * Handle loading and unloading for this node type 96552419Sjulian * This is to handle auxiliary linkages (e.g protocol domain addition). 96652419Sjulian */ 96752419Sjulianstatic int 96852419Sjulianngs_mod_event(module_t mod, int event, void *data) 96952419Sjulian{ 97052419Sjulian int error = 0; 97152419Sjulian 97252419Sjulian switch (event) { 97352419Sjulian case MOD_LOAD: 97452419Sjulian /* Register protocol domain */ 97552419Sjulian net_add_domain(&ngdomain); 97652419Sjulian break; 97752419Sjulian case MOD_UNLOAD: 97852419Sjulian /* Insure there are no open netgraph sockets */ 97952419Sjulian if (!LIST_EMPTY(&ngsocklist)) { 98052419Sjulian error = EBUSY; 98152419Sjulian break; 98252419Sjulian } 98352419Sjulian 98452419Sjulian#ifdef NOTYET 98552419Sjulian /* Unregister protocol domain XXX can't do this yet.. */ 98652419Sjulian if ((error = net_rm_domain(&ngdomain)) != 0) 98752419Sjulian break; 98852419Sjulian#else 98952419Sjulian error = EBUSY; 99052419Sjulian#endif 99152419Sjulian break; 99252419Sjulian default: 99352419Sjulian error = EOPNOTSUPP; 99452419Sjulian break; 99552419Sjulian } 99652419Sjulian return (error); 99752419Sjulian} 99852419Sjulian 99952419SjulianSYSCTL_NODE(_net, AF_NETGRAPH, graph, CTLFLAG_RW, 0, "netgraph Family"); 100052419SjulianSYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, ""); 100152419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); 100252419SjulianSYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, ""); 100352419SjulianSYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); 100452419SjulianSYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, ""); 100552419Sjulian 1006