ng_ksocket.c revision 130480
153246Sarchie 253246Sarchie/* 353246Sarchie * ng_ksocket.c 453246Sarchie * 553246Sarchie * Copyright (c) 1996-1999 Whistle Communications, Inc. 653246Sarchie * All rights reserved. 753246Sarchie * 853246Sarchie * Subject to the following obligations and disclaimer of warranty, use and 953246Sarchie * redistribution of this software, in source or object code forms, with or 1053246Sarchie * without modifications are expressly permitted by Whistle Communications; 1153246Sarchie * provided, however, that: 1253246Sarchie * 1. Any and all reproductions of the source or object code must include the 1353246Sarchie * copyright notice above and the following disclaimer of warranties; and 1453246Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1553246Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1653246Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1753246Sarchie * such appears in the above copyright notice or in the software. 1853246Sarchie * 1953246Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2053246Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2153246Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2253246Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2353246Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2453246Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2553246Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2653246Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2753246Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2853246Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2953246Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3053246Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3153246Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3253246Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3353246Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3453246Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3553246Sarchie * OF SUCH DAMAGE. 3653246Sarchie * 3767506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3853246Sarchie * 3953246Sarchie * $FreeBSD: head/sys/netgraph/ng_ksocket.c 130480 2004-06-14 18:16:22Z rwatson $ 4053246Sarchie * $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $ 4153246Sarchie */ 4253246Sarchie 4353246Sarchie/* 4453246Sarchie * Kernel socket node type. This node type is basically a kernel-mode 4553246Sarchie * version of a socket... kindof like the reverse of the socket node type. 4653246Sarchie */ 4753246Sarchie 4853246Sarchie#include <sys/param.h> 4953246Sarchie#include <sys/systm.h> 5053246Sarchie#include <sys/kernel.h> 5153246Sarchie#include <sys/mbuf.h> 5253246Sarchie#include <sys/proc.h> 5353246Sarchie#include <sys/malloc.h> 5453913Sarchie#include <sys/ctype.h> 5553246Sarchie#include <sys/protosw.h> 5653246Sarchie#include <sys/errno.h> 5753246Sarchie#include <sys/socket.h> 5853246Sarchie#include <sys/socketvar.h> 5953246Sarchie#include <sys/uio.h> 6053913Sarchie#include <sys/un.h> 6153246Sarchie 6253246Sarchie#include <netgraph/ng_message.h> 6353246Sarchie#include <netgraph/netgraph.h> 6453913Sarchie#include <netgraph/ng_parse.h> 6553246Sarchie#include <netgraph/ng_ksocket.h> 6653246Sarchie 6753246Sarchie#include <netinet/in.h> 6853246Sarchie#include <netatalk/at.h> 6953246Sarchie 7070870Sjulian#ifdef NG_SEPARATE_MALLOC 7170870SjulianMALLOC_DEFINE(M_NETGRAPH_KSOCKET, "netgraph_ksock", "netgraph ksock node "); 7270870Sjulian#else 7370870Sjulian#define M_NETGRAPH_KSOCKET M_NETGRAPH 7470870Sjulian#endif 7570870Sjulian 7653913Sarchie#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) 7753913Sarchie#define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data)) 7853913Sarchie 7953246Sarchie/* Node private data */ 8053404Sarchiestruct ng_ksocket_private { 8183186Sjulian node_p node; 8253246Sarchie hook_p hook; 8353246Sarchie struct socket *so; 8483186Sjulian LIST_HEAD(, ng_ksocket_private) embryos; 8583186Sjulian LIST_ENTRY(ng_ksocket_private) siblings; 8683186Sjulian u_int32_t flags; 8783186Sjulian u_int32_t response_token; 8883186Sjulian ng_ID_t response_addr; 8953246Sarchie}; 9053404Sarchietypedef struct ng_ksocket_private *priv_p; 9153246Sarchie 9283186Sjulian/* Flags for priv_p */ 9383186Sjulian#define KSF_CONNECTING 0x00000001 /* Waiting for connection complete */ 9483186Sjulian#define KSF_ACCEPTING 0x00000002 /* Waiting for accept complete */ 9583186Sjulian#define KSF_EOFSEEN 0x00000004 /* Have sent 0-length EOF mbuf */ 9683186Sjulian#define KSF_CLONED 0x00000008 /* Cloned from an accepting socket */ 9783186Sjulian#define KSF_EMBRYONIC 0x00000010 /* Cloned node with no hooks yet */ 9888945Sarchie#define KSF_SENDING 0x00000020 /* Sending on socket */ 9983186Sjulian 10053246Sarchie/* Netgraph node methods */ 10153246Sarchiestatic ng_constructor_t ng_ksocket_constructor; 10253246Sarchiestatic ng_rcvmsg_t ng_ksocket_rcvmsg; 10370700Sjulianstatic ng_shutdown_t ng_ksocket_shutdown; 10453246Sarchiestatic ng_newhook_t ng_ksocket_newhook; 10553246Sarchiestatic ng_rcvdata_t ng_ksocket_rcvdata; 10683186Sjulianstatic ng_connect_t ng_ksocket_connect; 10753246Sarchiestatic ng_disconnect_t ng_ksocket_disconnect; 10853246Sarchie 10953246Sarchie/* Alias structure */ 11053246Sarchiestruct ng_ksocket_alias { 11153246Sarchie const char *name; 11253246Sarchie const int value; 11353246Sarchie const int family; 11453246Sarchie}; 11553246Sarchie 11653246Sarchie/* Protocol family aliases */ 11753246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_families[] = { 11853246Sarchie { "local", PF_LOCAL }, 11953246Sarchie { "inet", PF_INET }, 12053246Sarchie { "inet6", PF_INET6 }, 12153246Sarchie { "atalk", PF_APPLETALK }, 12253246Sarchie { "ipx", PF_IPX }, 12353246Sarchie { "atm", PF_ATM }, 12453246Sarchie { NULL, -1 }, 12553246Sarchie}; 12653246Sarchie 12753246Sarchie/* Socket type aliases */ 12853246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_types[] = { 12953246Sarchie { "stream", SOCK_STREAM }, 13053246Sarchie { "dgram", SOCK_DGRAM }, 13153246Sarchie { "raw", SOCK_RAW }, 13253246Sarchie { "rdm", SOCK_RDM }, 13353246Sarchie { "seqpacket", SOCK_SEQPACKET }, 13453246Sarchie { NULL, -1 }, 13553246Sarchie}; 13653246Sarchie 13753246Sarchie/* Protocol aliases */ 13853246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_protos[] = { 13953246Sarchie { "ip", IPPROTO_IP, PF_INET }, 14084776Sarchie { "raw", IPPROTO_RAW, PF_INET }, 14153246Sarchie { "icmp", IPPROTO_ICMP, PF_INET }, 14253246Sarchie { "igmp", IPPROTO_IGMP, PF_INET }, 14353246Sarchie { "tcp", IPPROTO_TCP, PF_INET }, 14453246Sarchie { "udp", IPPROTO_UDP, PF_INET }, 14553246Sarchie { "gre", IPPROTO_GRE, PF_INET }, 14653246Sarchie { "esp", IPPROTO_ESP, PF_INET }, 14753246Sarchie { "ah", IPPROTO_AH, PF_INET }, 14853246Sarchie { "swipe", IPPROTO_SWIPE, PF_INET }, 14953246Sarchie { "encap", IPPROTO_ENCAP, PF_INET }, 15053246Sarchie { "divert", IPPROTO_DIVERT, PF_INET }, 151119187Shsu { "pim", IPPROTO_PIM, PF_INET }, 15253246Sarchie { "ddp", ATPROTO_DDP, PF_APPLETALK }, 15353246Sarchie { "aarp", ATPROTO_AARP, PF_APPLETALK }, 15453246Sarchie { NULL, -1 }, 15553246Sarchie}; 15653246Sarchie 15753913Sarchie/* Helper functions */ 15883186Sjulianstatic int ng_ksocket_check_accept(priv_p); 15983186Sjulianstatic void ng_ksocket_finish_accept(priv_p); 16053913Sarchiestatic void ng_ksocket_incoming(struct socket *so, void *arg, int waitflag); 16153913Sarchiestatic int ng_ksocket_parse(const struct ng_ksocket_alias *aliases, 16253913Sarchie const char *s, int family); 16383186Sjulianstatic void ng_ksocket_incoming2(node_p node, hook_p hook, 16483186Sjulian void *arg1, int waitflag); 16553913Sarchie 16653913Sarchie/************************************************************************ 16753913Sarchie STRUCT SOCKADDR PARSE TYPE 16853913Sarchie ************************************************************************/ 16953913Sarchie 17053913Sarchie/* Get the length of the data portion of a generic struct sockaddr */ 17153913Sarchiestatic int 17253913Sarchieng_parse_generic_sockdata_getLength(const struct ng_parse_type *type, 17353913Sarchie const u_char *start, const u_char *buf) 17453913Sarchie{ 17553913Sarchie const struct sockaddr *sa; 17653913Sarchie 17753913Sarchie sa = (const struct sockaddr *)(buf - SADATA_OFFSET); 17864470Sarchie return (sa->sa_len < SADATA_OFFSET) ? 0 : sa->sa_len - SADATA_OFFSET; 17953913Sarchie} 18053913Sarchie 18153913Sarchie/* Type for the variable length data portion of a generic struct sockaddr */ 18253913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockdata_type = { 18353913Sarchie &ng_parse_bytearray_type, 18453913Sarchie &ng_parse_generic_sockdata_getLength 18553913Sarchie}; 18653913Sarchie 18753913Sarchie/* Type for a generic struct sockaddr */ 18897685Sarchiestatic const struct ng_parse_struct_field 18997685Sarchie ng_parse_generic_sockaddr_type_fields[] = { 19064508Sarchie { "len", &ng_parse_uint8_type }, 19164508Sarchie { "family", &ng_parse_uint8_type }, 19253913Sarchie { "data", &ng_ksocket_generic_sockdata_type }, 19353913Sarchie { NULL } 19453913Sarchie}; 19553913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockaddr_type = { 19653913Sarchie &ng_parse_struct_type, 19797685Sarchie &ng_parse_generic_sockaddr_type_fields 19853913Sarchie}; 19953913Sarchie 20053913Sarchie/* Convert a struct sockaddr from ASCII to binary. If its a protocol 20153913Sarchie family that we specially handle, do that, otherwise defer to the 20253913Sarchie generic parse type ng_ksocket_generic_sockaddr_type. */ 20353913Sarchiestatic int 20453913Sarchieng_ksocket_sockaddr_parse(const struct ng_parse_type *type, 20553913Sarchie const char *s, int *off, const u_char *const start, 20653913Sarchie u_char *const buf, int *buflen) 20753913Sarchie{ 20853913Sarchie struct sockaddr *const sa = (struct sockaddr *)buf; 20953913Sarchie enum ng_parse_token tok; 21053913Sarchie char fambuf[32]; 21153913Sarchie int family, len; 21253913Sarchie char *t; 21353913Sarchie 21453913Sarchie /* If next token is a left curly brace, use generic parse type */ 21553913Sarchie if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) { 21653913Sarchie return (*ng_ksocket_generic_sockaddr_type.supertype->parse) 21753913Sarchie (&ng_ksocket_generic_sockaddr_type, 21853913Sarchie s, off, start, buf, buflen); 21953913Sarchie } 22053913Sarchie 22153913Sarchie /* Get socket address family followed by a slash */ 22253913Sarchie while (isspace(s[*off])) 22353913Sarchie (*off)++; 22453913Sarchie if ((t = index(s + *off, '/')) == NULL) 22553913Sarchie return (EINVAL); 22653913Sarchie if ((len = t - (s + *off)) > sizeof(fambuf) - 1) 22753913Sarchie return (EINVAL); 22853913Sarchie strncpy(fambuf, s + *off, len); 22953913Sarchie fambuf[len] = '\0'; 23053913Sarchie *off += len + 1; 23153913Sarchie if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1) 23253913Sarchie return (EINVAL); 23353913Sarchie 23453913Sarchie /* Set family */ 23553913Sarchie if (*buflen < SADATA_OFFSET) 23653913Sarchie return (ERANGE); 23753913Sarchie sa->sa_family = family; 23853913Sarchie 23953913Sarchie /* Set family-specific data and length */ 24053913Sarchie switch (sa->sa_family) { 24153913Sarchie case PF_LOCAL: /* Get pathname */ 24253913Sarchie { 24353913Sarchie const int pathoff = OFFSETOF(struct sockaddr_un, sun_path); 24453913Sarchie struct sockaddr_un *const sun = (struct sockaddr_un *)sa; 24553913Sarchie int toklen, pathlen; 24653913Sarchie char *path; 24753913Sarchie 24868845Sbrian if ((path = ng_get_string_token(s, off, &toklen, NULL)) == NULL) 24953913Sarchie return (EINVAL); 25053913Sarchie pathlen = strlen(path); 25153913Sarchie if (pathlen > SOCK_MAXADDRLEN) { 25270870Sjulian FREE(path, M_NETGRAPH_KSOCKET); 25353913Sarchie return (E2BIG); 25453913Sarchie } 25553913Sarchie if (*buflen < pathoff + pathlen) { 25670870Sjulian FREE(path, M_NETGRAPH_KSOCKET); 25753913Sarchie return (ERANGE); 25853913Sarchie } 25953913Sarchie *off += toklen; 26053913Sarchie bcopy(path, sun->sun_path, pathlen); 26153913Sarchie sun->sun_len = pathoff + pathlen; 26270870Sjulian FREE(path, M_NETGRAPH_KSOCKET); 26353913Sarchie break; 26453913Sarchie } 26553913Sarchie 26653913Sarchie case PF_INET: /* Get an IP address with optional port */ 26753913Sarchie { 26853913Sarchie struct sockaddr_in *const sin = (struct sockaddr_in *)sa; 26953913Sarchie int i; 27053913Sarchie 27153913Sarchie /* Parse this: <ipaddress>[:port] */ 27253913Sarchie for (i = 0; i < 4; i++) { 27353913Sarchie u_long val; 27453913Sarchie char *eptr; 27553913Sarchie 27653913Sarchie val = strtoul(s + *off, &eptr, 10); 27753913Sarchie if (val > 0xff || eptr == s + *off) 27853913Sarchie return (EINVAL); 27953913Sarchie *off += (eptr - (s + *off)); 28053913Sarchie ((u_char *)&sin->sin_addr)[i] = (u_char)val; 28153913Sarchie if (i < 3) { 28253913Sarchie if (s[*off] != '.') 28353913Sarchie return (EINVAL); 28453913Sarchie (*off)++; 28553913Sarchie } else if (s[*off] == ':') { 28653913Sarchie (*off)++; 28753913Sarchie val = strtoul(s + *off, &eptr, 10); 28853913Sarchie if (val > 0xffff || eptr == s + *off) 28953913Sarchie return (EINVAL); 29053913Sarchie *off += (eptr - (s + *off)); 29153913Sarchie sin->sin_port = htons(val); 29253913Sarchie } else 29353913Sarchie sin->sin_port = 0; 29453913Sarchie } 29553913Sarchie bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 29653913Sarchie sin->sin_len = sizeof(*sin); 29753913Sarchie break; 29853913Sarchie } 29953913Sarchie 30053913Sarchie#if 0 30153913Sarchie case PF_APPLETALK: /* XXX implement these someday */ 30253913Sarchie case PF_INET6: 30353913Sarchie case PF_IPX: 30453913Sarchie#endif 30553913Sarchie 30653913Sarchie default: 30753913Sarchie return (EINVAL); 30853913Sarchie } 30953913Sarchie 31053913Sarchie /* Done */ 31153913Sarchie *buflen = sa->sa_len; 31253913Sarchie return (0); 31353913Sarchie} 31453913Sarchie 31553913Sarchie/* Convert a struct sockaddr from binary to ASCII */ 31653913Sarchiestatic int 31753913Sarchieng_ksocket_sockaddr_unparse(const struct ng_parse_type *type, 31853913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 31953913Sarchie{ 32053913Sarchie const struct sockaddr *sa = (const struct sockaddr *)(data + *off); 32153913Sarchie int slen = 0; 32253913Sarchie 32353913Sarchie /* Output socket address, either in special or generic format */ 32453913Sarchie switch (sa->sa_family) { 32553913Sarchie case PF_LOCAL: 32653913Sarchie { 32753913Sarchie const int pathoff = OFFSETOF(struct sockaddr_un, sun_path); 32853913Sarchie const struct sockaddr_un *sun = (const struct sockaddr_un *)sa; 32953913Sarchie const int pathlen = sun->sun_len - pathoff; 33053913Sarchie char pathbuf[SOCK_MAXADDRLEN + 1]; 33153913Sarchie char *pathtoken; 33253913Sarchie 33353913Sarchie bcopy(sun->sun_path, pathbuf, pathlen); 33468845Sbrian if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL) 33553913Sarchie return (ENOMEM); 33653913Sarchie slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken); 33770870Sjulian FREE(pathtoken, M_NETGRAPH_KSOCKET); 33853913Sarchie if (slen >= cbuflen) 33953913Sarchie return (ERANGE); 34053913Sarchie *off += sun->sun_len; 34153913Sarchie return (0); 34253913Sarchie } 34353913Sarchie 34453913Sarchie case PF_INET: 34553913Sarchie { 34653913Sarchie const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 34753913Sarchie 34853913Sarchie slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d", 34953913Sarchie ((const u_char *)&sin->sin_addr)[0], 35053913Sarchie ((const u_char *)&sin->sin_addr)[1], 35153913Sarchie ((const u_char *)&sin->sin_addr)[2], 35253913Sarchie ((const u_char *)&sin->sin_addr)[3]); 35353913Sarchie if (sin->sin_port != 0) { 35453913Sarchie slen += snprintf(cbuf + strlen(cbuf), 35553913Sarchie cbuflen - strlen(cbuf), ":%d", 35653913Sarchie (u_int)ntohs(sin->sin_port)); 35753913Sarchie } 35853913Sarchie if (slen >= cbuflen) 35953913Sarchie return (ERANGE); 36053913Sarchie *off += sizeof(*sin); 36153913Sarchie return(0); 36253913Sarchie } 36353913Sarchie 36453913Sarchie#if 0 36553913Sarchie case PF_APPLETALK: /* XXX implement these someday */ 36653913Sarchie case PF_INET6: 36753913Sarchie case PF_IPX: 36853913Sarchie#endif 36953913Sarchie 37053913Sarchie default: 37153913Sarchie return (*ng_ksocket_generic_sockaddr_type.supertype->unparse) 37253913Sarchie (&ng_ksocket_generic_sockaddr_type, 37353913Sarchie data, off, cbuf, cbuflen); 37453913Sarchie } 37553913Sarchie} 37653913Sarchie 37753913Sarchie/* Parse type for struct sockaddr */ 37853913Sarchiestatic const struct ng_parse_type ng_ksocket_sockaddr_type = { 37953913Sarchie NULL, 38053913Sarchie NULL, 38153913Sarchie NULL, 38253913Sarchie &ng_ksocket_sockaddr_parse, 38353913Sarchie &ng_ksocket_sockaddr_unparse, 38453913Sarchie NULL /* no such thing as a default struct sockaddr */ 38553913Sarchie}; 38653913Sarchie 38753913Sarchie/************************************************************************ 38853913Sarchie STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE 38953913Sarchie ************************************************************************/ 39053913Sarchie 39153913Sarchie/* Get length of the struct ng_ksocket_sockopt value field, which is the 39253913Sarchie just the excess of the message argument portion over the length of 39353913Sarchie the struct ng_ksocket_sockopt. */ 39453913Sarchiestatic int 39553913Sarchieng_parse_sockoptval_getLength(const struct ng_parse_type *type, 39653913Sarchie const u_char *start, const u_char *buf) 39753913Sarchie{ 39853913Sarchie static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value); 39953913Sarchie const struct ng_ksocket_sockopt *sopt; 40053913Sarchie const struct ng_mesg *msg; 40153913Sarchie 40253913Sarchie sopt = (const struct ng_ksocket_sockopt *)(buf - offset); 40353913Sarchie msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg)); 40453913Sarchie return msg->header.arglen - sizeof(*sopt); 40553913Sarchie} 40653913Sarchie 40753913Sarchie/* Parse type for the option value part of a struct ng_ksocket_sockopt 40853913Sarchie XXX Eventually, we should handle the different socket options specially. 40953913Sarchie XXX This would avoid byte order problems, eg an integer value of 1 is 41053913Sarchie XXX going to be "[1]" for little endian or "[3=1]" for big endian. */ 41153913Sarchiestatic const struct ng_parse_type ng_ksocket_sockoptval_type = { 41253913Sarchie &ng_parse_bytearray_type, 41353913Sarchie &ng_parse_sockoptval_getLength 41453913Sarchie}; 41553913Sarchie 41653913Sarchie/* Parse type for struct ng_ksocket_sockopt */ 41797685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_sockopt_type_fields[] 41853913Sarchie = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type); 41953913Sarchiestatic const struct ng_parse_type ng_ksocket_sockopt_type = { 42053913Sarchie &ng_parse_struct_type, 42197685Sarchie &ng_ksocket_sockopt_type_fields 42253913Sarchie}; 42353913Sarchie 42483186Sjulian/* Parse type for struct ng_ksocket_accept */ 42597685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_accept_type_fields[] 42683186Sjulian = NGM_KSOCKET_ACCEPT_INFO; 42783186Sjulianstatic const struct ng_parse_type ng_ksocket_accept_type = { 42883186Sjulian &ng_parse_struct_type, 42997685Sarchie &ng_ksocket_accept_type_fields 43083186Sjulian}; 43183186Sjulian 43253913Sarchie/* List of commands and how to convert arguments to/from ASCII */ 43353913Sarchiestatic const struct ng_cmdlist ng_ksocket_cmds[] = { 43453913Sarchie { 43553913Sarchie NGM_KSOCKET_COOKIE, 43653913Sarchie NGM_KSOCKET_BIND, 43753913Sarchie "bind", 43853913Sarchie &ng_ksocket_sockaddr_type, 43953913Sarchie NULL 44053913Sarchie }, 44153913Sarchie { 44253913Sarchie NGM_KSOCKET_COOKIE, 44353913Sarchie NGM_KSOCKET_LISTEN, 44453913Sarchie "listen", 44553913Sarchie &ng_parse_int32_type, 44653913Sarchie NULL 44753913Sarchie }, 44853913Sarchie { 44953913Sarchie NGM_KSOCKET_COOKIE, 45053913Sarchie NGM_KSOCKET_ACCEPT, 45153913Sarchie "accept", 45253913Sarchie NULL, 45383186Sjulian &ng_ksocket_accept_type 45453913Sarchie }, 45553913Sarchie { 45653913Sarchie NGM_KSOCKET_COOKIE, 45753913Sarchie NGM_KSOCKET_CONNECT, 45853913Sarchie "connect", 45953913Sarchie &ng_ksocket_sockaddr_type, 46083186Sjulian &ng_parse_int32_type 46153913Sarchie }, 46253913Sarchie { 46353913Sarchie NGM_KSOCKET_COOKIE, 46453913Sarchie NGM_KSOCKET_GETNAME, 46553913Sarchie "getname", 46653913Sarchie NULL, 46753913Sarchie &ng_ksocket_sockaddr_type 46853913Sarchie }, 46953913Sarchie { 47053913Sarchie NGM_KSOCKET_COOKIE, 47153913Sarchie NGM_KSOCKET_GETPEERNAME, 47253913Sarchie "getpeername", 47353913Sarchie NULL, 47453913Sarchie &ng_ksocket_sockaddr_type 47553913Sarchie }, 47653913Sarchie { 47753913Sarchie NGM_KSOCKET_COOKIE, 47853913Sarchie NGM_KSOCKET_SETOPT, 47953913Sarchie "setopt", 48053913Sarchie &ng_ksocket_sockopt_type, 48153913Sarchie NULL 48253913Sarchie }, 48353913Sarchie { 48453913Sarchie NGM_KSOCKET_COOKIE, 48553913Sarchie NGM_KSOCKET_GETOPT, 48653913Sarchie "getopt", 48753913Sarchie &ng_ksocket_sockopt_type, 48853913Sarchie &ng_ksocket_sockopt_type 48953913Sarchie }, 49053913Sarchie { 0 } 49153913Sarchie}; 49253913Sarchie 49353913Sarchie/* Node type descriptor */ 49453913Sarchiestatic struct ng_type ng_ksocket_typestruct = { 495129823Sjulian .version = NG_ABI_VERSION, 496129823Sjulian .name = NG_KSOCKET_NODE_TYPE, 497129823Sjulian .constructor = ng_ksocket_constructor, 498129823Sjulian .rcvmsg = ng_ksocket_rcvmsg, 499129823Sjulian .shutdown = ng_ksocket_shutdown, 500129823Sjulian .newhook = ng_ksocket_newhook, 501129823Sjulian .connect = ng_ksocket_connect, 502129823Sjulian .rcvdata = ng_ksocket_rcvdata, 503129823Sjulian .disconnect = ng_ksocket_disconnect, 504129823Sjulian .cmdlist = ng_ksocket_cmds, 50553913Sarchie}; 50653913SarchieNETGRAPH_INIT(ksocket, &ng_ksocket_typestruct); 50753913Sarchie 50897658Stanimura#define ERROUT(x) do { error = (x); goto done; } while (0) 50953246Sarchie 51053246Sarchie/************************************************************************ 51153246Sarchie NETGRAPH NODE STUFF 51253246Sarchie ************************************************************************/ 51353246Sarchie 51453246Sarchie/* 51553246Sarchie * Node type constructor 51683186Sjulian * The NODE part is assumed to be all set up. 51783186Sjulian * There is already a reference to the node for us. 51853246Sarchie */ 51953246Sarchiestatic int 52070700Sjulianng_ksocket_constructor(node_p node) 52153246Sarchie{ 52253246Sarchie priv_p priv; 52353246Sarchie 52453246Sarchie /* Allocate private structure */ 52572545Sarchie MALLOC(priv, priv_p, sizeof(*priv), 52672545Sarchie M_NETGRAPH_KSOCKET, M_NOWAIT | M_ZERO); 52753246Sarchie if (priv == NULL) 52853246Sarchie return (ENOMEM); 52953246Sarchie 53083186Sjulian LIST_INIT(&priv->embryos); 53183186Sjulian /* cross link them */ 53283186Sjulian priv->node = node; 53370784Sjulian NG_NODE_SET_PRIVATE(node, priv); 53453246Sarchie 53553246Sarchie /* Done */ 53653246Sarchie return (0); 53753246Sarchie} 53853246Sarchie 53953246Sarchie/* 54053246Sarchie * Give our OK for a hook to be added. The hook name is of the 54172545Sarchie * form "<family>/<type>/<proto>" where the three components may 54253246Sarchie * be decimal numbers or else aliases from the above lists. 54353246Sarchie * 54453246Sarchie * Connecting a hook amounts to opening the socket. Disconnecting 54553246Sarchie * the hook closes the socket and destroys the node as well. 54653246Sarchie */ 54753246Sarchiestatic int 54853246Sarchieng_ksocket_newhook(node_p node, hook_p hook, const char *name0) 54953246Sarchie{ 55090361Sjulian struct thread *td = curthread ? curthread : &thread0; /* XXX broken */ 55170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 552125028Sharti char *s1, *s2, name[NG_HOOKSIZ]; 55353246Sarchie int family, type, protocol, error; 55453246Sarchie 55553246Sarchie /* Check if we're already connected */ 55653246Sarchie if (priv->hook != NULL) 55753246Sarchie return (EISCONN); 55853246Sarchie 55983186Sjulian if (priv->flags & KSF_CLONED) { 56083186Sjulian if (priv->flags & KSF_EMBRYONIC) { 56183186Sjulian /* Remove ourselves from our parent's embryo list */ 56283186Sjulian LIST_REMOVE(priv, siblings); 56383186Sjulian priv->flags &= ~KSF_EMBRYONIC; 56483186Sjulian } 56583186Sjulian } else { 56683186Sjulian /* Extract family, type, and protocol from hook name */ 56783186Sjulian snprintf(name, sizeof(name), "%s", name0); 56883186Sjulian s1 = name; 56983186Sjulian if ((s2 = index(s1, '/')) == NULL) 57083186Sjulian return (EINVAL); 57183186Sjulian *s2++ = '\0'; 57283186Sjulian family = ng_ksocket_parse(ng_ksocket_families, s1, 0); 57383186Sjulian if (family == -1) 57483186Sjulian return (EINVAL); 57583186Sjulian s1 = s2; 57683186Sjulian if ((s2 = index(s1, '/')) == NULL) 57783186Sjulian return (EINVAL); 57883186Sjulian *s2++ = '\0'; 57983186Sjulian type = ng_ksocket_parse(ng_ksocket_types, s1, 0); 58083186Sjulian if (type == -1) 58183186Sjulian return (EINVAL); 58283186Sjulian s1 = s2; 58383186Sjulian protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family); 58483186Sjulian if (protocol == -1) 58583186Sjulian return (EINVAL); 58653246Sarchie 58783186Sjulian /* Create the socket */ 58888739Srwatson error = socreate(family, &priv->so, type, protocol, 58991406Sjhb td->td_ucred, td); 59083186Sjulian if (error != 0) 59183186Sjulian return (error); 59253246Sarchie 59383186Sjulian /* XXX call soreserve() ? */ 59453246Sarchie 59583186Sjulian } 59683186Sjulian 59783186Sjulian /* OK */ 59883186Sjulian priv->hook = hook; 59983186Sjulian return(0); 60083186Sjulian} 60183186Sjulian 60283186Sjulianstatic int 60383186Sjulianng_ksocket_connect(hook_p hook) 60483186Sjulian{ 60583186Sjulian node_p node = NG_HOOK_NODE(hook); 60683186Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 60783186Sjulian struct socket *const so = priv->so; 60883186Sjulian 60983186Sjulian /* Add our hook for incoming data and other events */ 61053246Sarchie priv->so->so_upcallarg = (caddr_t)node; 61153246Sarchie priv->so->so_upcall = ng_ksocket_incoming; 61253246Sarchie priv->so->so_rcv.sb_flags |= SB_UPCALL; 61383186Sjulian priv->so->so_snd.sb_flags |= SB_UPCALL; 61483186Sjulian priv->so->so_state |= SS_NBIO; 61583186Sjulian /* 61683186Sjulian * --Original comment-- 61783186Sjulian * On a cloned socket we may have already received one or more 61883186Sjulian * upcalls which we couldn't handle without a hook. Handle 61983186Sjulian * those now. 62083186Sjulian * We cannot call the upcall function directly 62183186Sjulian * from here, because until this function has returned our 62283186Sjulian * hook isn't connected. 62383186Sjulian * 62483186Sjulian * ---meta comment for -current --- 62583186Sjulian * XXX This is dubius. 62683186Sjulian * Upcalls between the time that the hook was 62783186Sjulian * first created and now (on another processesor) will 62883186Sjulian * be earlier on the queue than the request to finalise the hook. 62983186Sjulian * By the time the hook is finalised, 63083186Sjulian * The queued upcalls will have happenned and the code 63183186Sjulian * will have discarded them because of a lack of a hook. 63283186Sjulian * (socket not open). 63383186Sjulian * 63483186Sjulian * This is a bad byproduct of the complicated way in which hooks 63583186Sjulian * are now created (3 daisy chained async events). 63683186Sjulian * 63783186Sjulian * Since we are a netgraph operation 63883186Sjulian * We know that we hold a lock on this node. This forces the 63983186Sjulian * request we make below to be queued rather than implemented 64083186Sjulian * immediatly which will cause the upcall function to be called a bit 64183186Sjulian * later. 64283186Sjulian * However, as we will run any waiting queued operations immediatly 64383186Sjulian * after doing this one, if we have not finalised the other end 64483186Sjulian * of the hook, those queued operations will fail. 64583186Sjulian */ 64683186Sjulian if (priv->flags & KSF_CLONED) { 64783186Sjulian ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_NOWAIT); 64883186Sjulian } 64953246Sarchie 65053246Sarchie return (0); 65153246Sarchie} 65253246Sarchie 65353246Sarchie/* 65453246Sarchie * Receive a control message 65553246Sarchie */ 65653246Sarchiestatic int 65770700Sjulianng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) 65853246Sarchie{ 65990361Sjulian struct thread *td = curthread ? curthread : &thread0; /* XXX broken */ 66070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 66153913Sarchie struct socket *const so = priv->so; 66253246Sarchie struct ng_mesg *resp = NULL; 66353246Sarchie int error = 0; 66470700Sjulian struct ng_mesg *msg; 66583186Sjulian ng_ID_t raddr; 66653246Sarchie 66770700Sjulian NGI_GET_MSG(item, msg); 66853246Sarchie switch (msg->header.typecookie) { 66953246Sarchie case NGM_KSOCKET_COOKIE: 67053246Sarchie switch (msg->header.cmd) { 67153246Sarchie case NGM_KSOCKET_BIND: 67253246Sarchie { 67353913Sarchie struct sockaddr *const sa 67453913Sarchie = (struct sockaddr *)msg->data; 67553246Sarchie 67653913Sarchie /* Sanity check */ 67753913Sarchie if (msg->header.arglen < SADATA_OFFSET 67853913Sarchie || msg->header.arglen < sa->sa_len) 67953913Sarchie ERROUT(EINVAL); 68053913Sarchie if (so == NULL) 68153913Sarchie ERROUT(ENXIO); 68253246Sarchie 68353913Sarchie /* Bind */ 68483366Sjulian error = sobind(so, sa, td); 68553246Sarchie break; 68653246Sarchie } 68753246Sarchie case NGM_KSOCKET_LISTEN: 68853246Sarchie { 68953913Sarchie /* Sanity check */ 69083186Sjulian if (msg->header.arglen != sizeof(int32_t)) 69153246Sarchie ERROUT(EINVAL); 69253913Sarchie if (so == NULL) 69353913Sarchie ERROUT(ENXIO); 69453246Sarchie 69553913Sarchie /* Listen */ 69683366Sjulian error = solisten(so, *((int32_t *)msg->data), td); 69753246Sarchie break; 69853246Sarchie } 69953246Sarchie 70053246Sarchie case NGM_KSOCKET_ACCEPT: 70153246Sarchie { 70253913Sarchie /* Sanity check */ 70353913Sarchie if (msg->header.arglen != 0) 70453913Sarchie ERROUT(EINVAL); 70553913Sarchie if (so == NULL) 70653913Sarchie ERROUT(ENXIO); 70753913Sarchie 70883186Sjulian /* Make sure the socket is capable of accepting */ 70983186Sjulian if (!(so->so_options & SO_ACCEPTCONN)) 71097658Stanimura ERROUT(EINVAL); 71183186Sjulian if (priv->flags & KSF_ACCEPTING) 71283186Sjulian ERROUT(EALREADY); 71353913Sarchie 71483186Sjulian error = ng_ksocket_check_accept(priv); 71583186Sjulian if (error != 0 && error != EWOULDBLOCK) 71683186Sjulian ERROUT(error); 71783186Sjulian 71883186Sjulian /* 71983186Sjulian * If a connection is already complete, take it. 72083186Sjulian * Otherwise let the upcall function deal with 72183186Sjulian * the connection when it comes in. 72283186Sjulian */ 72383186Sjulian priv->response_token = msg->header.token; 724103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 72583186Sjulian if (error == 0) { 72683186Sjulian ng_ksocket_finish_accept(priv); 72783186Sjulian } else 72883186Sjulian priv->flags |= KSF_ACCEPTING; 72953246Sarchie break; 73053246Sarchie } 73153246Sarchie 73253246Sarchie case NGM_KSOCKET_CONNECT: 73353246Sarchie { 73453913Sarchie struct sockaddr *const sa 73553913Sarchie = (struct sockaddr *)msg->data; 73653246Sarchie 73753913Sarchie /* Sanity check */ 73853913Sarchie if (msg->header.arglen < SADATA_OFFSET 73953913Sarchie || msg->header.arglen < sa->sa_len) 74053913Sarchie ERROUT(EINVAL); 74153913Sarchie if (so == NULL) 74253913Sarchie ERROUT(ENXIO); 74353246Sarchie 74453246Sarchie /* Do connect */ 74553246Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) 74697658Stanimura ERROUT(EALREADY); 74783366Sjulian if ((error = soconnect(so, sa, td)) != 0) { 74853246Sarchie so->so_state &= ~SS_ISCONNECTING; 74997658Stanimura ERROUT(error); 75053246Sarchie } 751114178Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) { 75283186Sjulian /* We will notify the sender when we connect */ 75383186Sjulian priv->response_token = msg->header.token; 754103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 75583186Sjulian priv->flags |= KSF_CONNECTING; 75697658Stanimura ERROUT(EINPROGRESS); 757114178Sarchie } 75853246Sarchie break; 75953246Sarchie } 76053246Sarchie 76153246Sarchie case NGM_KSOCKET_GETNAME: 76253913Sarchie case NGM_KSOCKET_GETPEERNAME: 76353246Sarchie { 76453913Sarchie int (*func)(struct socket *so, struct sockaddr **nam); 76553913Sarchie struct sockaddr *sa = NULL; 76653913Sarchie int len; 76753246Sarchie 76853913Sarchie /* Sanity check */ 76953913Sarchie if (msg->header.arglen != 0) 77053913Sarchie ERROUT(EINVAL); 77153913Sarchie if (so == NULL) 77253913Sarchie ERROUT(ENXIO); 77353913Sarchie 77453913Sarchie /* Get function */ 77553913Sarchie if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) { 77653913Sarchie if ((so->so_state 77753913Sarchie & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) 77897658Stanimura ERROUT(ENOTCONN); 77953913Sarchie func = so->so_proto->pr_usrreqs->pru_peeraddr; 78053913Sarchie } else 78153913Sarchie func = so->so_proto->pr_usrreqs->pru_sockaddr; 78253913Sarchie 78353913Sarchie /* Get local or peer address */ 78453913Sarchie if ((error = (*func)(so, &sa)) != 0) 78553913Sarchie goto bail; 78653913Sarchie len = (sa == NULL) ? 0 : sa->sa_len; 78753913Sarchie 78853913Sarchie /* Send it back in a response */ 78953913Sarchie NG_MKRESPONSE(resp, msg, len, M_NOWAIT); 79053913Sarchie if (resp == NULL) { 79153913Sarchie error = ENOMEM; 79253913Sarchie goto bail; 79353913Sarchie } 79453913Sarchie bcopy(sa, resp->data, len); 79553913Sarchie 79653913Sarchie bail: 79753913Sarchie /* Cleanup */ 79853913Sarchie if (sa != NULL) 79953913Sarchie FREE(sa, M_SONAME); 80053246Sarchie break; 80153246Sarchie } 80253246Sarchie 80353246Sarchie case NGM_KSOCKET_GETOPT: 80453246Sarchie { 80553913Sarchie struct ng_ksocket_sockopt *ksopt = 80653913Sarchie (struct ng_ksocket_sockopt *)msg->data; 80753913Sarchie struct sockopt sopt; 80853913Sarchie 80953913Sarchie /* Sanity check */ 81053913Sarchie if (msg->header.arglen != sizeof(*ksopt)) 81153913Sarchie ERROUT(EINVAL); 81253913Sarchie if (so == NULL) 81353913Sarchie ERROUT(ENXIO); 81453913Sarchie 81553913Sarchie /* Get response with room for option value */ 81653913Sarchie NG_MKRESPONSE(resp, msg, sizeof(*ksopt) 81753913Sarchie + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT); 81853913Sarchie if (resp == NULL) 81953913Sarchie ERROUT(ENOMEM); 82053913Sarchie 82153913Sarchie /* Get socket option, and put value in the response */ 82253913Sarchie sopt.sopt_dir = SOPT_GET; 82353913Sarchie sopt.sopt_level = ksopt->level; 82453913Sarchie sopt.sopt_name = ksopt->name; 82583366Sjulian sopt.sopt_td = NULL; 82653913Sarchie sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN; 82753913Sarchie ksopt = (struct ng_ksocket_sockopt *)resp->data; 82853913Sarchie sopt.sopt_val = ksopt->value; 82953913Sarchie if ((error = sogetopt(so, &sopt)) != 0) { 83070700Sjulian NG_FREE_MSG(resp); 83153913Sarchie break; 83253913Sarchie } 83353913Sarchie 83453913Sarchie /* Set actual value length */ 83553913Sarchie resp->header.arglen = sizeof(*ksopt) 83653913Sarchie + sopt.sopt_valsize; 83753246Sarchie break; 83853246Sarchie } 83953246Sarchie 84053246Sarchie case NGM_KSOCKET_SETOPT: 84153246Sarchie { 84253913Sarchie struct ng_ksocket_sockopt *const ksopt = 84353913Sarchie (struct ng_ksocket_sockopt *)msg->data; 84453913Sarchie const int valsize = msg->header.arglen - sizeof(*ksopt); 84553913Sarchie struct sockopt sopt; 84653913Sarchie 84753913Sarchie /* Sanity check */ 84853913Sarchie if (valsize < 0) 84953913Sarchie ERROUT(EINVAL); 85053913Sarchie if (so == NULL) 85153913Sarchie ERROUT(ENXIO); 85253913Sarchie 85353913Sarchie /* Set socket option */ 85453913Sarchie sopt.sopt_dir = SOPT_SET; 85553913Sarchie sopt.sopt_level = ksopt->level; 85653913Sarchie sopt.sopt_name = ksopt->name; 85753913Sarchie sopt.sopt_val = ksopt->value; 85853913Sarchie sopt.sopt_valsize = valsize; 85983366Sjulian sopt.sopt_td = NULL; 86053913Sarchie error = sosetopt(so, &sopt); 86153246Sarchie break; 86253246Sarchie } 86353246Sarchie 86453246Sarchie default: 86553246Sarchie error = EINVAL; 86653246Sarchie break; 86753246Sarchie } 86853246Sarchie break; 86953246Sarchie default: 87053246Sarchie error = EINVAL; 87153246Sarchie break; 87253246Sarchie } 87353246Sarchiedone: 87470700Sjulian NG_RESPOND_MSG(error, node, item, resp); 87570700Sjulian NG_FREE_MSG(msg); 87653246Sarchie return (error); 87753246Sarchie} 87853246Sarchie 87953246Sarchie/* 88053246Sarchie * Receive incoming data on our hook. Send it out the socket. 88153246Sarchie */ 88253246Sarchiestatic int 88370700Sjulianng_ksocket_rcvdata(hook_p hook, item_p item) 88453246Sarchie{ 88590361Sjulian struct thread *td = curthread ? curthread : &thread0; /* XXX broken */ 88670784Sjulian const node_p node = NG_HOOK_NODE(hook); 88770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 88853246Sarchie struct socket *const so = priv->so; 88987070Sarchie struct sockaddr *sa = NULL; 89087070Sarchie meta_p meta; 89153246Sarchie int error; 89270700Sjulian struct mbuf *m; 89353246Sarchie 89488945Sarchie /* Avoid reentrantly sending on the socket */ 89588945Sarchie if ((priv->flags & KSF_SENDING) != 0) { 89688945Sarchie NG_FREE_ITEM(item); 89788945Sarchie return (EDEADLK); 89888945Sarchie } 89988945Sarchie 90087070Sarchie /* Extract data and meta information */ 90170700Sjulian NGI_GET_M(item, m); 90287070Sarchie NGI_GET_META(item, meta); 90370700Sjulian NG_FREE_ITEM(item); 90487070Sarchie 90587070Sarchie /* If any meta info, look for peer socket address */ 90687070Sarchie if (meta != NULL) { 90787070Sarchie struct meta_field_header *field; 90887070Sarchie 90987070Sarchie /* Look for peer socket address */ 91087070Sarchie for (field = &meta->options[0]; 91187070Sarchie (caddr_t)field < (caddr_t)meta + meta->used_len; 91287070Sarchie field = (struct meta_field_header *) 91387070Sarchie ((caddr_t)field + field->len)) { 91487070Sarchie if (field->cookie != NGM_KSOCKET_COOKIE 91587070Sarchie || field->type != NG_KSOCKET_META_SOCKADDR) 91687070Sarchie continue; 91787070Sarchie sa = (struct sockaddr *)field->data; 91887070Sarchie break; 91987070Sarchie } 92087070Sarchie } 92187070Sarchie 92287070Sarchie /* Send packet */ 92388945Sarchie priv->flags |= KSF_SENDING; 92487070Sarchie error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, sa, 0, m, 0, 0, td); 92588945Sarchie priv->flags &= ~KSF_SENDING; 92687070Sarchie 92787070Sarchie /* Clean up and exit */ 92887070Sarchie NG_FREE_META(meta); 92953246Sarchie return (error); 93053246Sarchie} 93153246Sarchie 93253246Sarchie/* 93353246Sarchie * Destroy node 93453246Sarchie */ 93553246Sarchiestatic int 93670700Sjulianng_ksocket_shutdown(node_p node) 93753246Sarchie{ 93870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 93983186Sjulian priv_p embryo; 94053246Sarchie 94153404Sarchie /* Close our socket (if any) */ 94253404Sarchie if (priv->so != NULL) { 94353913Sarchie priv->so->so_upcall = NULL; 94453913Sarchie priv->so->so_rcv.sb_flags &= ~SB_UPCALL; 94583186Sjulian priv->so->so_snd.sb_flags &= ~SB_UPCALL; 94653404Sarchie soclose(priv->so); 94753404Sarchie priv->so = NULL; 94853404Sarchie } 94953404Sarchie 95083186Sjulian /* If we are an embryo, take ourselves out of the parent's list */ 95183186Sjulian if (priv->flags & KSF_EMBRYONIC) { 95283186Sjulian LIST_REMOVE(priv, siblings); 95383186Sjulian priv->flags &= ~KSF_EMBRYONIC; 95483186Sjulian } 95583186Sjulian 95683186Sjulian /* Remove any embryonic children we have */ 95783186Sjulian while (!LIST_EMPTY(&priv->embryos)) { 95883186Sjulian embryo = LIST_FIRST(&priv->embryos); 95983186Sjulian ng_rmnode_self(embryo->node); 96083186Sjulian } 96183186Sjulian 96253246Sarchie /* Take down netgraph node */ 96353246Sarchie bzero(priv, sizeof(*priv)); 96470870Sjulian FREE(priv, M_NETGRAPH_KSOCKET); 96570784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 96670784Sjulian NG_NODE_UNREF(node); /* let the node escape */ 96753246Sarchie return (0); 96853246Sarchie} 96953246Sarchie 97053246Sarchie/* 97153246Sarchie * Hook disconnection 97253246Sarchie */ 97353246Sarchiestatic int 97453246Sarchieng_ksocket_disconnect(hook_p hook) 97553246Sarchie{ 97670784Sjulian KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0, 97787599Sobrien ("%s: numhooks=%d?", __func__, 97872545Sarchie NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)))); 97970784Sjulian if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) 98070784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 98153246Sarchie return (0); 98253246Sarchie} 98353246Sarchie 98453246Sarchie/************************************************************************ 98553246Sarchie HELPER STUFF 98653246Sarchie ************************************************************************/ 98783186Sjulian/* 98883186Sjulian * You should no-longer "just call" a netgraph node function 98983186Sjulian * from an external asynchronous event. 99083186Sjulian * This is because in doing so you are ignoring the locking on the netgraph 99183186Sjulian * nodes. Instead call your function via 99283186Sjulian * "int ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, 99383186Sjulian * void *arg1, int arg2);" 99483186Sjulian * this will call the function you chose, but will first do all the 99583186Sjulian * locking rigmarole. Your function MAY only be called at some distant future 99683186Sjulian * time (several millisecs away) so don't give it any arguments 99783186Sjulian * that may be revoked soon (e.g. on your stack). 99883186Sjulian * In this case even the 'so' argument is doubtful. 99983186Sjulian * While the function request is being processed the node 100083186Sjulian * has an extra reference and as such will not disappear until 100183186Sjulian * the request has at least been done, but the 'so' may not be so lucky. 100283186Sjulian * handle this by checking the validity of the node in the target function 100383186Sjulian * before dereferencing the socket pointer. 100483186Sjulian */ 100553246Sarchie 100683186Sjulianstatic void 100783186Sjulianng_ksocket_incoming(struct socket *so, void *arg, int waitflag) 100883186Sjulian{ 100983186Sjulian const node_p node = arg; 101083186Sjulian 101183186Sjulian ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, waitflag); 101283186Sjulian} 101383186Sjulian 101483186Sjulian 101553246Sarchie/* 101653246Sarchie * When incoming data is appended to the socket, we get notified here. 101783186Sjulian * This is also called whenever a significant event occurs for the socket. 101883186Sjulian * We know that HOOK is NULL. Because of how we were called we know we have a 101983186Sjulian * lock on this node an are participating inthe netgraph locking. 102083186Sjulian * Our original caller may have queued this even some time ago and 102183186Sjulian * we cannot trust that he even still exists. The node however is being 102283186Sjulian * held with a reference by the queueing code, at least until we finish, 102383186Sjulian * even if it has been zapped, so first check it's validiy 102483186Sjulian * before we trust the socket (which was derived from it). 102553246Sarchie */ 102653246Sarchiestatic void 102783186Sjulianng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int waitflag) 102853246Sarchie{ 102983186Sjulian struct socket *so = arg1; 103070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 103153246Sarchie struct mbuf *m; 103283186Sjulian struct ng_mesg *response; 103353246Sarchie struct uio auio; 103453404Sarchie int s, flags, error; 103553246Sarchie 103653404Sarchie s = splnet(); 103753404Sarchie 103853246Sarchie /* Sanity check */ 103970784Sjulian if (NG_NODE_NOT_VALID(node)) { 104053404Sarchie splx(s); 104153246Sarchie return; 104253404Sarchie } 104383186Sjulian /* so = priv->so; *//* XXX could have derived this like so */ 104487599Sobrien KASSERT(so == priv->so, ("%s: wrong socket", __func__)); 104553246Sarchie 104683186Sjulian /* Check whether a pending connect operation has completed */ 104783186Sjulian if (priv->flags & KSF_CONNECTING) { 104883186Sjulian if ((error = so->so_error) != 0) { 104983186Sjulian so->so_error = 0; 105083186Sjulian so->so_state &= ~SS_ISCONNECTING; 105183186Sjulian } 105283186Sjulian if (!(so->so_state & SS_ISCONNECTING)) { 105383186Sjulian NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE, 105483186Sjulian NGM_KSOCKET_CONNECT, sizeof(int32_t), waitflag); 105583186Sjulian if (response != NULL) { 105683186Sjulian response->header.flags |= NGF_RESP; 105783186Sjulian response->header.token = priv->response_token; 105883186Sjulian *(int32_t *)response->data = error; 105983186Sjulian /* 106083186Sjulian * send an async "response" message 106183186Sjulian * to the node that set us up 106283186Sjulian * (if it still exists) 106383186Sjulian */ 1064102244Sarchie NG_SEND_MSG_ID(error, node, 1065102244Sarchie response, priv->response_addr, 0); 106683186Sjulian } 106783186Sjulian priv->flags &= ~KSF_CONNECTING; 106897658Stanimura } 106983186Sjulian } 107083186Sjulian 107183186Sjulian /* Check whether a pending accept operation has completed */ 107283186Sjulian if (priv->flags & KSF_ACCEPTING) { 107383186Sjulian error = ng_ksocket_check_accept(priv); 107483186Sjulian if (error != EWOULDBLOCK) 107583186Sjulian priv->flags &= ~KSF_ACCEPTING; 107683186Sjulian if (error == 0) 107783186Sjulian ng_ksocket_finish_accept(priv); 107883186Sjulian } 107983186Sjulian 108083186Sjulian /* 108183186Sjulian * If we don't have a hook, we must handle data events later. When 108283186Sjulian * the hook gets created and is connected, this upcall function 108383186Sjulian * will be called again. 108483186Sjulian */ 108583186Sjulian if (priv->hook == NULL) { 108683186Sjulian splx(s); 108783186Sjulian return; 108883186Sjulian } 108983186Sjulian 109053246Sarchie /* Read and forward available mbuf's */ 109183366Sjulian auio.uio_td = NULL; 109253246Sarchie auio.uio_resid = 1000000000; 109353246Sarchie flags = MSG_DONTWAIT; 109487070Sarchie while (1) { 109587070Sarchie struct sockaddr *sa = NULL; 109687070Sarchie meta_p meta = NULL; 109787070Sarchie struct mbuf *n; 109887070Sarchie 109987070Sarchie /* Try to get next packet from socket */ 110053246Sarchie if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive) 110197658Stanimura (so, (so->so_state & SS_ISCONNECTED) ? NULL : &sa, 110287070Sarchie &auio, &m, (struct mbuf **)0, &flags)) != 0) 110387070Sarchie break; 110453913Sarchie 110587070Sarchie /* See if we got anything */ 110687070Sarchie if (m == NULL) { 110787070Sarchie if (sa != NULL) 110887070Sarchie FREE(sa, M_SONAME); 110987070Sarchie break; 111053913Sarchie } 111183186Sjulian 111287070Sarchie /* Don't trust the various socket layers to get the 111387070Sarchie packet header and length correct (eg. kern/15175) */ 111487070Sarchie for (n = m, m->m_pkthdr.len = 0; n != NULL; n = n->m_next) 111587070Sarchie m->m_pkthdr.len += n->m_len; 111687070Sarchie 111787070Sarchie /* Put peer's socket address (if any) into a meta info blob */ 111887070Sarchie if (sa != NULL) { 111987070Sarchie struct meta_field_header *mhead; 112087070Sarchie u_int len; 112187070Sarchie 112287070Sarchie len = sizeof(*meta) + sizeof(*mhead) + sa->sa_len; 1123123599Sru MALLOC(meta, meta_p, len, M_NETGRAPH_META, 1124123599Sru M_NOWAIT | M_ZERO); 112587070Sarchie if (meta == NULL) { 112687070Sarchie FREE(sa, M_SONAME); 112787070Sarchie goto sendit; 112887070Sarchie } 112987070Sarchie mhead = &meta->options[0]; 113087070Sarchie meta->allocated_len = len; 113187070Sarchie meta->used_len = len; 113287070Sarchie mhead->cookie = NGM_KSOCKET_COOKIE; 113387070Sarchie mhead->type = NG_KSOCKET_META_SOCKADDR; 113487070Sarchie mhead->len = sizeof(*mhead) + sa->sa_len; 113587070Sarchie bcopy(sa, mhead->data, sa->sa_len); 113687070Sarchie FREE(sa, M_SONAME); 113787070Sarchie } 113887070Sarchie 113987070Sarchiesendit: /* Forward data with optional peer sockaddr as meta info */ 114087070Sarchie NG_SEND_DATA(error, priv->hook, m, meta); 114187070Sarchie } 114287070Sarchie 114383186Sjulian /* 114483186Sjulian * If the peer has closed the connection, forward a 0-length mbuf 114583186Sjulian * to indicate end-of-file. 114683186Sjulian */ 1147130480Srwatson if (so->so_rcv.sb_state & SBS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) { 114883186Sjulian MGETHDR(m, waitflag, MT_DATA); 114983186Sjulian if (m != NULL) { 115083186Sjulian m->m_len = m->m_pkthdr.len = 0; 115183186Sjulian NG_SEND_DATA_ONLY(error, priv->hook, m); 115283186Sjulian } 115383186Sjulian priv->flags |= KSF_EOFSEEN; 115497658Stanimura } 115553404Sarchie splx(s); 115653246Sarchie} 115753246Sarchie 115853246Sarchie/* 115983186Sjulian * Check for a completed incoming connection and return 0 if one is found. 116083186Sjulian * Otherwise return the appropriate error code. 116183186Sjulian */ 116283186Sjulianstatic int 116383186Sjulianng_ksocket_check_accept(priv_p priv) 116483186Sjulian{ 116583186Sjulian struct socket *const head = priv->so; 116683186Sjulian int error; 116783186Sjulian 116883186Sjulian if ((error = head->so_error) != 0) { 116983186Sjulian head->so_error = 0; 117083186Sjulian return error; 117183186Sjulian } 1172129979Srwatson /* Unlocked read. */ 117383186Sjulian if (TAILQ_EMPTY(&head->so_comp)) { 1174130480Srwatson if (head->so_rcv.sb_state & SBS_CANTRCVMORE) 117583186Sjulian return ECONNABORTED; 117683186Sjulian return EWOULDBLOCK; 117783186Sjulian } 117883186Sjulian return 0; 117983186Sjulian} 118083186Sjulian 118183186Sjulian/* 118283186Sjulian * Handle the first completed incoming connection, assumed to be already 118383186Sjulian * on the socket's so_comp queue. 118483186Sjulian */ 118583186Sjulianstatic void 118683186Sjulianng_ksocket_finish_accept(priv_p priv) 118783186Sjulian{ 118883186Sjulian struct socket *const head = priv->so; 118983186Sjulian struct socket *so; 119083186Sjulian struct sockaddr *sa = NULL; 119183186Sjulian struct ng_mesg *resp; 119283186Sjulian struct ng_ksocket_accept *resp_data; 119383186Sjulian node_p node; 119483186Sjulian priv_p priv2; 119583186Sjulian int len; 119683186Sjulian int error; 119783186Sjulian 1198129979Srwatson ACCEPT_LOCK(); 119983186Sjulian so = TAILQ_FIRST(&head->so_comp); 1200129979Srwatson if (so == NULL) { /* Should never happen */ 1201129979Srwatson ACCEPT_UNLOCK(); 120283186Sjulian return; 1203129979Srwatson } 120483186Sjulian TAILQ_REMOVE(&head->so_comp, so, so_list); 120583186Sjulian head->so_qlen--; 1206129979Srwatson so->so_qstate &= ~SQ_COMP; 1207129979Srwatson so->so_head = NULL; 1208130387Srwatson SOCK_LOCK(so); 1209129979Srwatson soref(so); 1210129979Srwatson so->so_state |= SS_NBIO; 1211130387Srwatson SOCK_UNLOCK(so); 1212129979Srwatson ACCEPT_UNLOCK(); 121383186Sjulian 121483186Sjulian /* XXX KNOTE(&head->so_rcv.sb_sel.si_note, 0); */ 121583186Sjulian 121683186Sjulian soaccept(so, &sa); 121783186Sjulian 121883186Sjulian len = OFFSETOF(struct ng_ksocket_accept, addr); 121983186Sjulian if (sa != NULL) 122083186Sjulian len += sa->sa_len; 122183186Sjulian 122283186Sjulian NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len, 122383186Sjulian M_NOWAIT); 122483186Sjulian if (resp == NULL) { 122583186Sjulian soclose(so); 122683186Sjulian goto out; 122783186Sjulian } 122883186Sjulian resp->header.flags |= NGF_RESP; 122983186Sjulian resp->header.token = priv->response_token; 123083186Sjulian 123183186Sjulian /* Clone a ksocket node to wrap the new socket */ 123283186Sjulian error = ng_make_node_common(&ng_ksocket_typestruct, &node); 123383186Sjulian if (error) { 123483186Sjulian FREE(resp, M_NETGRAPH); 123583186Sjulian soclose(so); 123683186Sjulian goto out; 123783186Sjulian } 123883186Sjulian 123983186Sjulian if (ng_ksocket_constructor(node) != 0) { 124083186Sjulian NG_NODE_UNREF(node); 124183186Sjulian FREE(resp, M_NETGRAPH); 124283186Sjulian soclose(so); 124383186Sjulian goto out; 124483186Sjulian } 124583186Sjulian 124683186Sjulian priv2 = NG_NODE_PRIVATE(node); 124783186Sjulian priv2->so = so; 124883186Sjulian priv2->flags |= KSF_CLONED | KSF_EMBRYONIC; 124983186Sjulian 125083186Sjulian /* 125183186Sjulian * Insert the cloned node into a list of embryonic children 125283186Sjulian * on the parent node. When a hook is created on the cloned 125383186Sjulian * node it will be removed from this list. When the parent 125483186Sjulian * is destroyed it will destroy any embryonic children it has. 125583186Sjulian */ 125683186Sjulian LIST_INSERT_HEAD(&priv->embryos, priv2, siblings); 125783186Sjulian 125883186Sjulian so->so_upcallarg = (caddr_t)node; 125983186Sjulian so->so_upcall = ng_ksocket_incoming; 126083186Sjulian so->so_rcv.sb_flags |= SB_UPCALL; 126183186Sjulian so->so_snd.sb_flags |= SB_UPCALL; 126283186Sjulian 126383186Sjulian /* Fill in the response data and send it or return it to the caller */ 126483186Sjulian resp_data = (struct ng_ksocket_accept *)resp->data; 126583186Sjulian resp_data->nodeid = NG_NODE_ID(node); 126683186Sjulian if (sa != NULL) 126783186Sjulian bcopy(sa, &resp_data->addr, sa->sa_len); 1268102244Sarchie NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0); 126983186Sjulian 127083186Sjulianout: 127183186Sjulian if (sa != NULL) 127283186Sjulian FREE(sa, M_SONAME); 127383186Sjulian} 127483186Sjulian 127583186Sjulian/* 127653246Sarchie * Parse out either an integer value or an alias. 127753246Sarchie */ 127853246Sarchiestatic int 127953246Sarchieng_ksocket_parse(const struct ng_ksocket_alias *aliases, 128053246Sarchie const char *s, int family) 128153246Sarchie{ 128253246Sarchie int k, val; 128353648Sarchie char *eptr; 128453246Sarchie 128553246Sarchie /* Try aliases */ 128653246Sarchie for (k = 0; aliases[k].name != NULL; k++) { 128753246Sarchie if (strcmp(s, aliases[k].name) == 0 128853246Sarchie && aliases[k].family == family) 128953246Sarchie return aliases[k].value; 129053246Sarchie } 129153246Sarchie 129253246Sarchie /* Try parsing as a number */ 129353246Sarchie val = (int)strtoul(s, &eptr, 10); 129453913Sarchie if (val < 0 || *eptr != '\0') 129553246Sarchie return (-1); 129653246Sarchie return (val); 129753246Sarchie} 129853246Sarchie 1299