ng_ksocket.c revision 119187
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 119187 2003-08-20 22:11:58Z hsu $ 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 = { 49570159Sjulian NG_ABI_VERSION, 49653913Sarchie NG_KSOCKET_NODE_TYPE, 49753913Sarchie NULL, 49853913Sarchie ng_ksocket_constructor, 49953913Sarchie ng_ksocket_rcvmsg, 50070700Sjulian ng_ksocket_shutdown, 50153913Sarchie ng_ksocket_newhook, 50253913Sarchie NULL, 50383186Sjulian ng_ksocket_connect, 50453913Sarchie ng_ksocket_rcvdata, 50553913Sarchie ng_ksocket_disconnect, 50653913Sarchie ng_ksocket_cmds 50753913Sarchie}; 50853913SarchieNETGRAPH_INIT(ksocket, &ng_ksocket_typestruct); 50953913Sarchie 51097658Stanimura#define ERROUT(x) do { error = (x); goto done; } while (0) 51153246Sarchie 51253246Sarchie/************************************************************************ 51353246Sarchie NETGRAPH NODE STUFF 51453246Sarchie ************************************************************************/ 51553246Sarchie 51653246Sarchie/* 51753246Sarchie * Node type constructor 51883186Sjulian * The NODE part is assumed to be all set up. 51983186Sjulian * There is already a reference to the node for us. 52053246Sarchie */ 52153246Sarchiestatic int 52270700Sjulianng_ksocket_constructor(node_p node) 52353246Sarchie{ 52453246Sarchie priv_p priv; 52553246Sarchie 52653246Sarchie /* Allocate private structure */ 52772545Sarchie MALLOC(priv, priv_p, sizeof(*priv), 52872545Sarchie M_NETGRAPH_KSOCKET, M_NOWAIT | M_ZERO); 52953246Sarchie if (priv == NULL) 53053246Sarchie return (ENOMEM); 53153246Sarchie 53283186Sjulian LIST_INIT(&priv->embryos); 53383186Sjulian /* cross link them */ 53483186Sjulian priv->node = node; 53570784Sjulian NG_NODE_SET_PRIVATE(node, priv); 53653246Sarchie 53753246Sarchie /* Done */ 53853246Sarchie return (0); 53953246Sarchie} 54053246Sarchie 54153246Sarchie/* 54253246Sarchie * Give our OK for a hook to be added. The hook name is of the 54372545Sarchie * form "<family>/<type>/<proto>" where the three components may 54453246Sarchie * be decimal numbers or else aliases from the above lists. 54553246Sarchie * 54653246Sarchie * Connecting a hook amounts to opening the socket. Disconnecting 54753246Sarchie * the hook closes the socket and destroys the node as well. 54853246Sarchie */ 54953246Sarchiestatic int 55053246Sarchieng_ksocket_newhook(node_p node, hook_p hook, const char *name0) 55153246Sarchie{ 55290361Sjulian struct thread *td = curthread ? curthread : &thread0; /* XXX broken */ 55370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 55453246Sarchie char *s1, *s2, name[NG_HOOKLEN+1]; 55553246Sarchie int family, type, protocol, error; 55653246Sarchie 55753246Sarchie /* Check if we're already connected */ 55853246Sarchie if (priv->hook != NULL) 55953246Sarchie return (EISCONN); 56053246Sarchie 56183186Sjulian if (priv->flags & KSF_CLONED) { 56283186Sjulian if (priv->flags & KSF_EMBRYONIC) { 56383186Sjulian /* Remove ourselves from our parent's embryo list */ 56483186Sjulian LIST_REMOVE(priv, siblings); 56583186Sjulian priv->flags &= ~KSF_EMBRYONIC; 56683186Sjulian } 56783186Sjulian } else { 56883186Sjulian /* Extract family, type, and protocol from hook name */ 56983186Sjulian snprintf(name, sizeof(name), "%s", name0); 57083186Sjulian s1 = name; 57183186Sjulian if ((s2 = index(s1, '/')) == NULL) 57283186Sjulian return (EINVAL); 57383186Sjulian *s2++ = '\0'; 57483186Sjulian family = ng_ksocket_parse(ng_ksocket_families, s1, 0); 57583186Sjulian if (family == -1) 57683186Sjulian return (EINVAL); 57783186Sjulian s1 = s2; 57883186Sjulian if ((s2 = index(s1, '/')) == NULL) 57983186Sjulian return (EINVAL); 58083186Sjulian *s2++ = '\0'; 58183186Sjulian type = ng_ksocket_parse(ng_ksocket_types, s1, 0); 58283186Sjulian if (type == -1) 58383186Sjulian return (EINVAL); 58483186Sjulian s1 = s2; 58583186Sjulian protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family); 58683186Sjulian if (protocol == -1) 58783186Sjulian return (EINVAL); 58853246Sarchie 58983186Sjulian /* Create the socket */ 59088739Srwatson error = socreate(family, &priv->so, type, protocol, 59191406Sjhb td->td_ucred, td); 59283186Sjulian if (error != 0) 59383186Sjulian return (error); 59453246Sarchie 59583186Sjulian /* XXX call soreserve() ? */ 59653246Sarchie 59783186Sjulian } 59883186Sjulian 59983186Sjulian /* OK */ 60083186Sjulian priv->hook = hook; 60183186Sjulian return(0); 60283186Sjulian} 60383186Sjulian 60483186Sjulianstatic int 60583186Sjulianng_ksocket_connect(hook_p hook) 60683186Sjulian{ 60783186Sjulian node_p node = NG_HOOK_NODE(hook); 60883186Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 60983186Sjulian struct socket *const so = priv->so; 61083186Sjulian 61183186Sjulian /* Add our hook for incoming data and other events */ 61253246Sarchie priv->so->so_upcallarg = (caddr_t)node; 61353246Sarchie priv->so->so_upcall = ng_ksocket_incoming; 61453246Sarchie priv->so->so_rcv.sb_flags |= SB_UPCALL; 61583186Sjulian priv->so->so_snd.sb_flags |= SB_UPCALL; 61683186Sjulian priv->so->so_state |= SS_NBIO; 61783186Sjulian /* 61883186Sjulian * --Original comment-- 61983186Sjulian * On a cloned socket we may have already received one or more 62083186Sjulian * upcalls which we couldn't handle without a hook. Handle 62183186Sjulian * those now. 62283186Sjulian * We cannot call the upcall function directly 62383186Sjulian * from here, because until this function has returned our 62483186Sjulian * hook isn't connected. 62583186Sjulian * 62683186Sjulian * ---meta comment for -current --- 62783186Sjulian * XXX This is dubius. 62883186Sjulian * Upcalls between the time that the hook was 62983186Sjulian * first created and now (on another processesor) will 63083186Sjulian * be earlier on the queue than the request to finalise the hook. 63183186Sjulian * By the time the hook is finalised, 63283186Sjulian * The queued upcalls will have happenned and the code 63383186Sjulian * will have discarded them because of a lack of a hook. 63483186Sjulian * (socket not open). 63583186Sjulian * 63683186Sjulian * This is a bad byproduct of the complicated way in which hooks 63783186Sjulian * are now created (3 daisy chained async events). 63883186Sjulian * 63983186Sjulian * Since we are a netgraph operation 64083186Sjulian * We know that we hold a lock on this node. This forces the 64183186Sjulian * request we make below to be queued rather than implemented 64283186Sjulian * immediatly which will cause the upcall function to be called a bit 64383186Sjulian * later. 64483186Sjulian * However, as we will run any waiting queued operations immediatly 64583186Sjulian * after doing this one, if we have not finalised the other end 64683186Sjulian * of the hook, those queued operations will fail. 64783186Sjulian */ 64883186Sjulian if (priv->flags & KSF_CLONED) { 64983186Sjulian ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_NOWAIT); 65083186Sjulian } 65153246Sarchie 65253246Sarchie return (0); 65353246Sarchie} 65453246Sarchie 65553246Sarchie/* 65653246Sarchie * Receive a control message 65753246Sarchie */ 65853246Sarchiestatic int 65970700Sjulianng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) 66053246Sarchie{ 66190361Sjulian struct thread *td = curthread ? curthread : &thread0; /* XXX broken */ 66270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 66353913Sarchie struct socket *const so = priv->so; 66453246Sarchie struct ng_mesg *resp = NULL; 66553246Sarchie int error = 0; 66670700Sjulian struct ng_mesg *msg; 66783186Sjulian ng_ID_t raddr; 66853246Sarchie 66970700Sjulian NGI_GET_MSG(item, msg); 67053246Sarchie switch (msg->header.typecookie) { 67153246Sarchie case NGM_KSOCKET_COOKIE: 67253246Sarchie switch (msg->header.cmd) { 67353246Sarchie case NGM_KSOCKET_BIND: 67453246Sarchie { 67553913Sarchie struct sockaddr *const sa 67653913Sarchie = (struct sockaddr *)msg->data; 67753246Sarchie 67853913Sarchie /* Sanity check */ 67953913Sarchie if (msg->header.arglen < SADATA_OFFSET 68053913Sarchie || msg->header.arglen < sa->sa_len) 68153913Sarchie ERROUT(EINVAL); 68253913Sarchie if (so == NULL) 68353913Sarchie ERROUT(ENXIO); 68453246Sarchie 68553913Sarchie /* Bind */ 68683366Sjulian error = sobind(so, sa, td); 68753246Sarchie break; 68853246Sarchie } 68953246Sarchie case NGM_KSOCKET_LISTEN: 69053246Sarchie { 69153913Sarchie /* Sanity check */ 69283186Sjulian if (msg->header.arglen != sizeof(int32_t)) 69353246Sarchie ERROUT(EINVAL); 69453913Sarchie if (so == NULL) 69553913Sarchie ERROUT(ENXIO); 69653246Sarchie 69753913Sarchie /* Listen */ 69883366Sjulian error = solisten(so, *((int32_t *)msg->data), td); 69953246Sarchie break; 70053246Sarchie } 70153246Sarchie 70253246Sarchie case NGM_KSOCKET_ACCEPT: 70353246Sarchie { 70453913Sarchie /* Sanity check */ 70553913Sarchie if (msg->header.arglen != 0) 70653913Sarchie ERROUT(EINVAL); 70753913Sarchie if (so == NULL) 70853913Sarchie ERROUT(ENXIO); 70953913Sarchie 71083186Sjulian /* Make sure the socket is capable of accepting */ 71183186Sjulian if (!(so->so_options & SO_ACCEPTCONN)) 71297658Stanimura ERROUT(EINVAL); 71383186Sjulian if (priv->flags & KSF_ACCEPTING) 71483186Sjulian ERROUT(EALREADY); 71553913Sarchie 71683186Sjulian error = ng_ksocket_check_accept(priv); 71783186Sjulian if (error != 0 && error != EWOULDBLOCK) 71883186Sjulian ERROUT(error); 71983186Sjulian 72083186Sjulian /* 72183186Sjulian * If a connection is already complete, take it. 72283186Sjulian * Otherwise let the upcall function deal with 72383186Sjulian * the connection when it comes in. 72483186Sjulian */ 72583186Sjulian priv->response_token = msg->header.token; 726103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 72783186Sjulian if (error == 0) { 72883186Sjulian ng_ksocket_finish_accept(priv); 72983186Sjulian } else 73083186Sjulian priv->flags |= KSF_ACCEPTING; 73153246Sarchie break; 73253246Sarchie } 73353246Sarchie 73453246Sarchie case NGM_KSOCKET_CONNECT: 73553246Sarchie { 73653913Sarchie struct sockaddr *const sa 73753913Sarchie = (struct sockaddr *)msg->data; 73853246Sarchie 73953913Sarchie /* Sanity check */ 74053913Sarchie if (msg->header.arglen < SADATA_OFFSET 74153913Sarchie || msg->header.arglen < sa->sa_len) 74253913Sarchie ERROUT(EINVAL); 74353913Sarchie if (so == NULL) 74453913Sarchie ERROUT(ENXIO); 74553246Sarchie 74653246Sarchie /* Do connect */ 74753246Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) 74897658Stanimura ERROUT(EALREADY); 74983366Sjulian if ((error = soconnect(so, sa, td)) != 0) { 75053246Sarchie so->so_state &= ~SS_ISCONNECTING; 75197658Stanimura ERROUT(error); 75253246Sarchie } 753114178Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) { 75483186Sjulian /* We will notify the sender when we connect */ 75583186Sjulian priv->response_token = msg->header.token; 756103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 75783186Sjulian priv->flags |= KSF_CONNECTING; 75897658Stanimura ERROUT(EINPROGRESS); 759114178Sarchie } 76053246Sarchie break; 76153246Sarchie } 76253246Sarchie 76353246Sarchie case NGM_KSOCKET_GETNAME: 76453913Sarchie case NGM_KSOCKET_GETPEERNAME: 76553246Sarchie { 76653913Sarchie int (*func)(struct socket *so, struct sockaddr **nam); 76753913Sarchie struct sockaddr *sa = NULL; 76853913Sarchie int len; 76953246Sarchie 77053913Sarchie /* Sanity check */ 77153913Sarchie if (msg->header.arglen != 0) 77253913Sarchie ERROUT(EINVAL); 77353913Sarchie if (so == NULL) 77453913Sarchie ERROUT(ENXIO); 77553913Sarchie 77653913Sarchie /* Get function */ 77753913Sarchie if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) { 77853913Sarchie if ((so->so_state 77953913Sarchie & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) 78097658Stanimura ERROUT(ENOTCONN); 78153913Sarchie func = so->so_proto->pr_usrreqs->pru_peeraddr; 78253913Sarchie } else 78353913Sarchie func = so->so_proto->pr_usrreqs->pru_sockaddr; 78453913Sarchie 78553913Sarchie /* Get local or peer address */ 78653913Sarchie if ((error = (*func)(so, &sa)) != 0) 78753913Sarchie goto bail; 78853913Sarchie len = (sa == NULL) ? 0 : sa->sa_len; 78953913Sarchie 79053913Sarchie /* Send it back in a response */ 79153913Sarchie NG_MKRESPONSE(resp, msg, len, M_NOWAIT); 79253913Sarchie if (resp == NULL) { 79353913Sarchie error = ENOMEM; 79453913Sarchie goto bail; 79553913Sarchie } 79653913Sarchie bcopy(sa, resp->data, len); 79753913Sarchie 79853913Sarchie bail: 79953913Sarchie /* Cleanup */ 80053913Sarchie if (sa != NULL) 80153913Sarchie FREE(sa, M_SONAME); 80253246Sarchie break; 80353246Sarchie } 80453246Sarchie 80553246Sarchie case NGM_KSOCKET_GETOPT: 80653246Sarchie { 80753913Sarchie struct ng_ksocket_sockopt *ksopt = 80853913Sarchie (struct ng_ksocket_sockopt *)msg->data; 80953913Sarchie struct sockopt sopt; 81053913Sarchie 81153913Sarchie /* Sanity check */ 81253913Sarchie if (msg->header.arglen != sizeof(*ksopt)) 81353913Sarchie ERROUT(EINVAL); 81453913Sarchie if (so == NULL) 81553913Sarchie ERROUT(ENXIO); 81653913Sarchie 81753913Sarchie /* Get response with room for option value */ 81853913Sarchie NG_MKRESPONSE(resp, msg, sizeof(*ksopt) 81953913Sarchie + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT); 82053913Sarchie if (resp == NULL) 82153913Sarchie ERROUT(ENOMEM); 82253913Sarchie 82353913Sarchie /* Get socket option, and put value in the response */ 82453913Sarchie sopt.sopt_dir = SOPT_GET; 82553913Sarchie sopt.sopt_level = ksopt->level; 82653913Sarchie sopt.sopt_name = ksopt->name; 82783366Sjulian sopt.sopt_td = NULL; 82853913Sarchie sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN; 82953913Sarchie ksopt = (struct ng_ksocket_sockopt *)resp->data; 83053913Sarchie sopt.sopt_val = ksopt->value; 83153913Sarchie if ((error = sogetopt(so, &sopt)) != 0) { 83270700Sjulian NG_FREE_MSG(resp); 83353913Sarchie break; 83453913Sarchie } 83553913Sarchie 83653913Sarchie /* Set actual value length */ 83753913Sarchie resp->header.arglen = sizeof(*ksopt) 83853913Sarchie + sopt.sopt_valsize; 83953246Sarchie break; 84053246Sarchie } 84153246Sarchie 84253246Sarchie case NGM_KSOCKET_SETOPT: 84353246Sarchie { 84453913Sarchie struct ng_ksocket_sockopt *const ksopt = 84553913Sarchie (struct ng_ksocket_sockopt *)msg->data; 84653913Sarchie const int valsize = msg->header.arglen - sizeof(*ksopt); 84753913Sarchie struct sockopt sopt; 84853913Sarchie 84953913Sarchie /* Sanity check */ 85053913Sarchie if (valsize < 0) 85153913Sarchie ERROUT(EINVAL); 85253913Sarchie if (so == NULL) 85353913Sarchie ERROUT(ENXIO); 85453913Sarchie 85553913Sarchie /* Set socket option */ 85653913Sarchie sopt.sopt_dir = SOPT_SET; 85753913Sarchie sopt.sopt_level = ksopt->level; 85853913Sarchie sopt.sopt_name = ksopt->name; 85953913Sarchie sopt.sopt_val = ksopt->value; 86053913Sarchie sopt.sopt_valsize = valsize; 86183366Sjulian sopt.sopt_td = NULL; 86253913Sarchie error = sosetopt(so, &sopt); 86353246Sarchie break; 86453246Sarchie } 86553246Sarchie 86653246Sarchie default: 86753246Sarchie error = EINVAL; 86853246Sarchie break; 86953246Sarchie } 87053246Sarchie break; 87153246Sarchie default: 87253246Sarchie error = EINVAL; 87353246Sarchie break; 87453246Sarchie } 87553246Sarchiedone: 87670700Sjulian NG_RESPOND_MSG(error, node, item, resp); 87770700Sjulian NG_FREE_MSG(msg); 87853246Sarchie return (error); 87953246Sarchie} 88053246Sarchie 88153246Sarchie/* 88253246Sarchie * Receive incoming data on our hook. Send it out the socket. 88353246Sarchie */ 88453246Sarchiestatic int 88570700Sjulianng_ksocket_rcvdata(hook_p hook, item_p item) 88653246Sarchie{ 88790361Sjulian struct thread *td = curthread ? curthread : &thread0; /* XXX broken */ 88870784Sjulian const node_p node = NG_HOOK_NODE(hook); 88970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 89053246Sarchie struct socket *const so = priv->so; 89187070Sarchie struct sockaddr *sa = NULL; 89287070Sarchie meta_p meta; 89353246Sarchie int error; 89470700Sjulian struct mbuf *m; 89553246Sarchie 89688945Sarchie /* Avoid reentrantly sending on the socket */ 89788945Sarchie if ((priv->flags & KSF_SENDING) != 0) { 89888945Sarchie NG_FREE_ITEM(item); 89988945Sarchie return (EDEADLK); 90088945Sarchie } 90188945Sarchie 90287070Sarchie /* Extract data and meta information */ 90370700Sjulian NGI_GET_M(item, m); 90487070Sarchie NGI_GET_META(item, meta); 90570700Sjulian NG_FREE_ITEM(item); 90687070Sarchie 90787070Sarchie /* If any meta info, look for peer socket address */ 90887070Sarchie if (meta != NULL) { 90987070Sarchie struct meta_field_header *field; 91087070Sarchie 91187070Sarchie /* Look for peer socket address */ 91287070Sarchie for (field = &meta->options[0]; 91387070Sarchie (caddr_t)field < (caddr_t)meta + meta->used_len; 91487070Sarchie field = (struct meta_field_header *) 91587070Sarchie ((caddr_t)field + field->len)) { 91687070Sarchie if (field->cookie != NGM_KSOCKET_COOKIE 91787070Sarchie || field->type != NG_KSOCKET_META_SOCKADDR) 91887070Sarchie continue; 91987070Sarchie sa = (struct sockaddr *)field->data; 92087070Sarchie break; 92187070Sarchie } 92287070Sarchie } 92387070Sarchie 92487070Sarchie /* Send packet */ 92588945Sarchie priv->flags |= KSF_SENDING; 92687070Sarchie error = (*so->so_proto->pr_usrreqs->pru_sosend)(so, sa, 0, m, 0, 0, td); 92788945Sarchie priv->flags &= ~KSF_SENDING; 92887070Sarchie 92987070Sarchie /* Clean up and exit */ 93087070Sarchie NG_FREE_META(meta); 93153246Sarchie return (error); 93253246Sarchie} 93353246Sarchie 93453246Sarchie/* 93553246Sarchie * Destroy node 93653246Sarchie */ 93753246Sarchiestatic int 93870700Sjulianng_ksocket_shutdown(node_p node) 93953246Sarchie{ 94070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 94183186Sjulian priv_p embryo; 94253246Sarchie 94353404Sarchie /* Close our socket (if any) */ 94453404Sarchie if (priv->so != NULL) { 94553913Sarchie priv->so->so_upcall = NULL; 94653913Sarchie priv->so->so_rcv.sb_flags &= ~SB_UPCALL; 94783186Sjulian priv->so->so_snd.sb_flags &= ~SB_UPCALL; 94853404Sarchie soclose(priv->so); 94953404Sarchie priv->so = NULL; 95053404Sarchie } 95153404Sarchie 95283186Sjulian /* If we are an embryo, take ourselves out of the parent's list */ 95383186Sjulian if (priv->flags & KSF_EMBRYONIC) { 95483186Sjulian LIST_REMOVE(priv, siblings); 95583186Sjulian priv->flags &= ~KSF_EMBRYONIC; 95683186Sjulian } 95783186Sjulian 95883186Sjulian /* Remove any embryonic children we have */ 95983186Sjulian while (!LIST_EMPTY(&priv->embryos)) { 96083186Sjulian embryo = LIST_FIRST(&priv->embryos); 96183186Sjulian ng_rmnode_self(embryo->node); 96283186Sjulian } 96383186Sjulian 96453246Sarchie /* Take down netgraph node */ 96553246Sarchie bzero(priv, sizeof(*priv)); 96670870Sjulian FREE(priv, M_NETGRAPH_KSOCKET); 96770784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 96870784Sjulian NG_NODE_UNREF(node); /* let the node escape */ 96953246Sarchie return (0); 97053246Sarchie} 97153246Sarchie 97253246Sarchie/* 97353246Sarchie * Hook disconnection 97453246Sarchie */ 97553246Sarchiestatic int 97653246Sarchieng_ksocket_disconnect(hook_p hook) 97753246Sarchie{ 97870784Sjulian KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0, 97987599Sobrien ("%s: numhooks=%d?", __func__, 98072545Sarchie NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)))); 98170784Sjulian if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) 98270784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 98353246Sarchie return (0); 98453246Sarchie} 98553246Sarchie 98653246Sarchie/************************************************************************ 98753246Sarchie HELPER STUFF 98853246Sarchie ************************************************************************/ 98983186Sjulian/* 99083186Sjulian * You should no-longer "just call" a netgraph node function 99183186Sjulian * from an external asynchronous event. 99283186Sjulian * This is because in doing so you are ignoring the locking on the netgraph 99383186Sjulian * nodes. Instead call your function via 99483186Sjulian * "int ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, 99583186Sjulian * void *arg1, int arg2);" 99683186Sjulian * this will call the function you chose, but will first do all the 99783186Sjulian * locking rigmarole. Your function MAY only be called at some distant future 99883186Sjulian * time (several millisecs away) so don't give it any arguments 99983186Sjulian * that may be revoked soon (e.g. on your stack). 100083186Sjulian * In this case even the 'so' argument is doubtful. 100183186Sjulian * While the function request is being processed the node 100283186Sjulian * has an extra reference and as such will not disappear until 100383186Sjulian * the request has at least been done, but the 'so' may not be so lucky. 100483186Sjulian * handle this by checking the validity of the node in the target function 100583186Sjulian * before dereferencing the socket pointer. 100683186Sjulian */ 100753246Sarchie 100883186Sjulianstatic void 100983186Sjulianng_ksocket_incoming(struct socket *so, void *arg, int waitflag) 101083186Sjulian{ 101183186Sjulian const node_p node = arg; 101283186Sjulian 101383186Sjulian ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, waitflag); 101483186Sjulian} 101583186Sjulian 101683186Sjulian 101753246Sarchie/* 101853246Sarchie * When incoming data is appended to the socket, we get notified here. 101983186Sjulian * This is also called whenever a significant event occurs for the socket. 102083186Sjulian * We know that HOOK is NULL. Because of how we were called we know we have a 102183186Sjulian * lock on this node an are participating inthe netgraph locking. 102283186Sjulian * Our original caller may have queued this even some time ago and 102383186Sjulian * we cannot trust that he even still exists. The node however is being 102483186Sjulian * held with a reference by the queueing code, at least until we finish, 102583186Sjulian * even if it has been zapped, so first check it's validiy 102683186Sjulian * before we trust the socket (which was derived from it). 102753246Sarchie */ 102853246Sarchiestatic void 102983186Sjulianng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int waitflag) 103053246Sarchie{ 103183186Sjulian struct socket *so = arg1; 103270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 103353246Sarchie struct mbuf *m; 103483186Sjulian struct ng_mesg *response; 103553246Sarchie struct uio auio; 103653404Sarchie int s, flags, error; 103753246Sarchie 103853404Sarchie s = splnet(); 103953404Sarchie 104053246Sarchie /* Sanity check */ 104170784Sjulian if (NG_NODE_NOT_VALID(node)) { 104253404Sarchie splx(s); 104353246Sarchie return; 104453404Sarchie } 104583186Sjulian /* so = priv->so; *//* XXX could have derived this like so */ 104687599Sobrien KASSERT(so == priv->so, ("%s: wrong socket", __func__)); 104753246Sarchie 104883186Sjulian /* Check whether a pending connect operation has completed */ 104983186Sjulian if (priv->flags & KSF_CONNECTING) { 105083186Sjulian if ((error = so->so_error) != 0) { 105183186Sjulian so->so_error = 0; 105283186Sjulian so->so_state &= ~SS_ISCONNECTING; 105383186Sjulian } 105483186Sjulian if (!(so->so_state & SS_ISCONNECTING)) { 105583186Sjulian NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE, 105683186Sjulian NGM_KSOCKET_CONNECT, sizeof(int32_t), waitflag); 105783186Sjulian if (response != NULL) { 105883186Sjulian response->header.flags |= NGF_RESP; 105983186Sjulian response->header.token = priv->response_token; 106083186Sjulian *(int32_t *)response->data = error; 106183186Sjulian /* 106283186Sjulian * send an async "response" message 106383186Sjulian * to the node that set us up 106483186Sjulian * (if it still exists) 106583186Sjulian */ 1066102244Sarchie NG_SEND_MSG_ID(error, node, 1067102244Sarchie response, priv->response_addr, 0); 106883186Sjulian } 106983186Sjulian priv->flags &= ~KSF_CONNECTING; 107097658Stanimura } 107183186Sjulian } 107283186Sjulian 107383186Sjulian /* Check whether a pending accept operation has completed */ 107483186Sjulian if (priv->flags & KSF_ACCEPTING) { 107583186Sjulian error = ng_ksocket_check_accept(priv); 107683186Sjulian if (error != EWOULDBLOCK) 107783186Sjulian priv->flags &= ~KSF_ACCEPTING; 107883186Sjulian if (error == 0) 107983186Sjulian ng_ksocket_finish_accept(priv); 108083186Sjulian } 108183186Sjulian 108283186Sjulian /* 108383186Sjulian * If we don't have a hook, we must handle data events later. When 108483186Sjulian * the hook gets created and is connected, this upcall function 108583186Sjulian * will be called again. 108683186Sjulian */ 108783186Sjulian if (priv->hook == NULL) { 108883186Sjulian splx(s); 108983186Sjulian return; 109083186Sjulian } 109183186Sjulian 109253246Sarchie /* Read and forward available mbuf's */ 109383366Sjulian auio.uio_td = NULL; 109453246Sarchie auio.uio_resid = 1000000000; 109553246Sarchie flags = MSG_DONTWAIT; 109687070Sarchie while (1) { 109787070Sarchie struct sockaddr *sa = NULL; 109887070Sarchie meta_p meta = NULL; 109987070Sarchie struct mbuf *n; 110087070Sarchie 110187070Sarchie /* Try to get next packet from socket */ 110253246Sarchie if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive) 110397658Stanimura (so, (so->so_state & SS_ISCONNECTED) ? NULL : &sa, 110487070Sarchie &auio, &m, (struct mbuf **)0, &flags)) != 0) 110587070Sarchie break; 110653913Sarchie 110787070Sarchie /* See if we got anything */ 110887070Sarchie if (m == NULL) { 110987070Sarchie if (sa != NULL) 111087070Sarchie FREE(sa, M_SONAME); 111187070Sarchie break; 111253913Sarchie } 111383186Sjulian 111487070Sarchie /* Don't trust the various socket layers to get the 111587070Sarchie packet header and length correct (eg. kern/15175) */ 111687070Sarchie for (n = m, m->m_pkthdr.len = 0; n != NULL; n = n->m_next) 111787070Sarchie m->m_pkthdr.len += n->m_len; 111887070Sarchie 111987070Sarchie /* Put peer's socket address (if any) into a meta info blob */ 112087070Sarchie if (sa != NULL) { 112187070Sarchie struct meta_field_header *mhead; 112287070Sarchie u_int len; 112387070Sarchie 112487070Sarchie len = sizeof(*meta) + sizeof(*mhead) + sa->sa_len; 112587070Sarchie MALLOC(meta, meta_p, len, M_NETGRAPH_META, M_NOWAIT); 112687070Sarchie if (meta == NULL) { 112787070Sarchie FREE(sa, M_SONAME); 112887070Sarchie goto sendit; 112987070Sarchie } 113087070Sarchie mhead = &meta->options[0]; 113187070Sarchie bzero(meta, sizeof(*meta)); 113287070Sarchie bzero(mhead, sizeof(*mhead)); 113387070Sarchie meta->allocated_len = len; 113487070Sarchie meta->used_len = len; 113587070Sarchie mhead->cookie = NGM_KSOCKET_COOKIE; 113687070Sarchie mhead->type = NG_KSOCKET_META_SOCKADDR; 113787070Sarchie mhead->len = sizeof(*mhead) + sa->sa_len; 113887070Sarchie bcopy(sa, mhead->data, sa->sa_len); 113987070Sarchie FREE(sa, M_SONAME); 114087070Sarchie } 114187070Sarchie 114287070Sarchiesendit: /* Forward data with optional peer sockaddr as meta info */ 114387070Sarchie NG_SEND_DATA(error, priv->hook, m, meta); 114487070Sarchie } 114587070Sarchie 114683186Sjulian /* 114783186Sjulian * If the peer has closed the connection, forward a 0-length mbuf 114883186Sjulian * to indicate end-of-file. 114983186Sjulian */ 115083186Sjulian if (so->so_state & SS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) { 115183186Sjulian MGETHDR(m, waitflag, MT_DATA); 115283186Sjulian if (m != NULL) { 115383186Sjulian m->m_len = m->m_pkthdr.len = 0; 115483186Sjulian NG_SEND_DATA_ONLY(error, priv->hook, m); 115583186Sjulian } 115683186Sjulian priv->flags |= KSF_EOFSEEN; 115797658Stanimura } 115853404Sarchie splx(s); 115953246Sarchie} 116053246Sarchie 116153246Sarchie/* 116283186Sjulian * Check for a completed incoming connection and return 0 if one is found. 116383186Sjulian * Otherwise return the appropriate error code. 116483186Sjulian */ 116583186Sjulianstatic int 116683186Sjulianng_ksocket_check_accept(priv_p priv) 116783186Sjulian{ 116883186Sjulian struct socket *const head = priv->so; 116983186Sjulian int error; 117083186Sjulian 117183186Sjulian if ((error = head->so_error) != 0) { 117283186Sjulian head->so_error = 0; 117383186Sjulian return error; 117483186Sjulian } 117583186Sjulian if (TAILQ_EMPTY(&head->so_comp)) { 117697658Stanimura if (head->so_state & SS_CANTRCVMORE) 117783186Sjulian return ECONNABORTED; 117883186Sjulian return EWOULDBLOCK; 117983186Sjulian } 118083186Sjulian return 0; 118183186Sjulian} 118283186Sjulian 118383186Sjulian/* 118483186Sjulian * Handle the first completed incoming connection, assumed to be already 118583186Sjulian * on the socket's so_comp queue. 118683186Sjulian */ 118783186Sjulianstatic void 118883186Sjulianng_ksocket_finish_accept(priv_p priv) 118983186Sjulian{ 119083186Sjulian struct socket *const head = priv->so; 119183186Sjulian struct socket *so; 119283186Sjulian struct sockaddr *sa = NULL; 119383186Sjulian struct ng_mesg *resp; 119483186Sjulian struct ng_ksocket_accept *resp_data; 119583186Sjulian node_p node; 119683186Sjulian priv_p priv2; 119783186Sjulian int len; 119883186Sjulian int error; 119983186Sjulian 120083186Sjulian so = TAILQ_FIRST(&head->so_comp); 120183186Sjulian if (so == NULL) /* Should never happen */ 120283186Sjulian return; 120383186Sjulian TAILQ_REMOVE(&head->so_comp, so, so_list); 120483186Sjulian head->so_qlen--; 120583186Sjulian 120683186Sjulian /* XXX KNOTE(&head->so_rcv.sb_sel.si_note, 0); */ 120783186Sjulian 1208103313Sbenno soref(so); 1209103313Sbenno 121083186Sjulian so->so_state &= ~SS_COMP; 121183186Sjulian so->so_state |= SS_NBIO; 121283186Sjulian so->so_head = NULL; 121383186Sjulian 121483186Sjulian soaccept(so, &sa); 121583186Sjulian 121683186Sjulian len = OFFSETOF(struct ng_ksocket_accept, addr); 121783186Sjulian if (sa != NULL) 121883186Sjulian len += sa->sa_len; 121983186Sjulian 122083186Sjulian NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len, 122183186Sjulian M_NOWAIT); 122283186Sjulian if (resp == NULL) { 122383186Sjulian soclose(so); 122483186Sjulian goto out; 122583186Sjulian } 122683186Sjulian resp->header.flags |= NGF_RESP; 122783186Sjulian resp->header.token = priv->response_token; 122883186Sjulian 122983186Sjulian /* Clone a ksocket node to wrap the new socket */ 123083186Sjulian error = ng_make_node_common(&ng_ksocket_typestruct, &node); 123183186Sjulian if (error) { 123283186Sjulian FREE(resp, M_NETGRAPH); 123383186Sjulian soclose(so); 123483186Sjulian goto out; 123583186Sjulian } 123683186Sjulian 123783186Sjulian if (ng_ksocket_constructor(node) != 0) { 123883186Sjulian NG_NODE_UNREF(node); 123983186Sjulian FREE(resp, M_NETGRAPH); 124083186Sjulian soclose(so); 124183186Sjulian goto out; 124283186Sjulian } 124383186Sjulian 124483186Sjulian priv2 = NG_NODE_PRIVATE(node); 124583186Sjulian priv2->so = so; 124683186Sjulian priv2->flags |= KSF_CLONED | KSF_EMBRYONIC; 124783186Sjulian 124883186Sjulian /* 124983186Sjulian * Insert the cloned node into a list of embryonic children 125083186Sjulian * on the parent node. When a hook is created on the cloned 125183186Sjulian * node it will be removed from this list. When the parent 125283186Sjulian * is destroyed it will destroy any embryonic children it has. 125383186Sjulian */ 125483186Sjulian LIST_INSERT_HEAD(&priv->embryos, priv2, siblings); 125583186Sjulian 125683186Sjulian so->so_upcallarg = (caddr_t)node; 125783186Sjulian so->so_upcall = ng_ksocket_incoming; 125883186Sjulian so->so_rcv.sb_flags |= SB_UPCALL; 125983186Sjulian so->so_snd.sb_flags |= SB_UPCALL; 126083186Sjulian 126183186Sjulian /* Fill in the response data and send it or return it to the caller */ 126283186Sjulian resp_data = (struct ng_ksocket_accept *)resp->data; 126383186Sjulian resp_data->nodeid = NG_NODE_ID(node); 126483186Sjulian if (sa != NULL) 126583186Sjulian bcopy(sa, &resp_data->addr, sa->sa_len); 1266102244Sarchie NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0); 126783186Sjulian 126883186Sjulianout: 126983186Sjulian if (sa != NULL) 127083186Sjulian FREE(sa, M_SONAME); 127183186Sjulian} 127283186Sjulian 127383186Sjulian/* 127453246Sarchie * Parse out either an integer value or an alias. 127553246Sarchie */ 127653246Sarchiestatic int 127753246Sarchieng_ksocket_parse(const struct ng_ksocket_alias *aliases, 127853246Sarchie const char *s, int family) 127953246Sarchie{ 128053246Sarchie int k, val; 128153648Sarchie char *eptr; 128253246Sarchie 128353246Sarchie /* Try aliases */ 128453246Sarchie for (k = 0; aliases[k].name != NULL; k++) { 128553246Sarchie if (strcmp(s, aliases[k].name) == 0 128653246Sarchie && aliases[k].family == family) 128753246Sarchie return aliases[k].value; 128853246Sarchie } 128953246Sarchie 129053246Sarchie /* Try parsing as a number */ 129153246Sarchie val = (int)strtoul(s, &eptr, 10); 129253913Sarchie if (val < 0 || *eptr != '\0') 129353246Sarchie return (-1); 129453246Sarchie return (val); 129553246Sarchie} 129653246Sarchie 1297