153246Sarchie/* 253246Sarchie * ng_ksocket.c 3139823Simp */ 4139823Simp 5139823Simp/*- 653246Sarchie * Copyright (c) 1996-1999 Whistle Communications, Inc. 753246Sarchie * All rights reserved. 853246Sarchie * 953246Sarchie * Subject to the following obligations and disclaimer of warranty, use and 1053246Sarchie * redistribution of this software, in source or object code forms, with or 1153246Sarchie * without modifications are expressly permitted by Whistle Communications; 1253246Sarchie * provided, however, that: 1353246Sarchie * 1. Any and all reproductions of the source or object code must include the 1453246Sarchie * copyright notice above and the following disclaimer of warranties; and 1553246Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1653246Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1753246Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1853246Sarchie * such appears in the above copyright notice or in the software. 1953246Sarchie * 2053246Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2153246Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2253246Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2353246Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2453246Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2553246Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2653246Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2753246Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2853246Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2953246Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3053246Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3153246Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3253246Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3353246Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3453246Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3553246Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3653246Sarchie * OF SUCH DAMAGE. 3753246Sarchie * 3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3953246Sarchie * 4053246Sarchie * $FreeBSD$ 4153246Sarchie * $Whistle: ng_ksocket.c,v 1.1 1999/11/16 20:04:40 archie Exp $ 4253246Sarchie */ 4353246Sarchie 4453246Sarchie/* 4553246Sarchie * Kernel socket node type. This node type is basically a kernel-mode 4653246Sarchie * version of a socket... kindof like the reverse of the socket node type. 4753246Sarchie */ 4853246Sarchie 4953246Sarchie#include <sys/param.h> 5053246Sarchie#include <sys/systm.h> 5153246Sarchie#include <sys/kernel.h> 5253246Sarchie#include <sys/mbuf.h> 5353246Sarchie#include <sys/proc.h> 5453246Sarchie#include <sys/malloc.h> 5553913Sarchie#include <sys/ctype.h> 5653246Sarchie#include <sys/protosw.h> 5753246Sarchie#include <sys/errno.h> 5853246Sarchie#include <sys/socket.h> 5953246Sarchie#include <sys/socketvar.h> 6053246Sarchie#include <sys/uio.h> 6153913Sarchie#include <sys/un.h> 6253246Sarchie 6353246Sarchie#include <netgraph/ng_message.h> 6453246Sarchie#include <netgraph/netgraph.h> 6553913Sarchie#include <netgraph/ng_parse.h> 6653246Sarchie#include <netgraph/ng_ksocket.h> 6753246Sarchie 6853246Sarchie#include <netinet/in.h> 6953246Sarchie#include <netatalk/at.h> 7053246Sarchie 7170870Sjulian#ifdef NG_SEPARATE_MALLOC 72249132Smavstatic MALLOC_DEFINE(M_NETGRAPH_KSOCKET, "netgraph_ksock", 73249132Smav "netgraph ksock node"); 7470870Sjulian#else 7570870Sjulian#define M_NETGRAPH_KSOCKET M_NETGRAPH 7670870Sjulian#endif 7770870Sjulian 7853913Sarchie#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) 7953913Sarchie#define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data)) 8053913Sarchie 8153246Sarchie/* Node private data */ 8253404Sarchiestruct ng_ksocket_private { 8383186Sjulian node_p node; 8453246Sarchie hook_p hook; 8553246Sarchie struct socket *so; 86176917Smav int fn_sent; /* FN call on incoming event was sent */ 8783186Sjulian LIST_HEAD(, ng_ksocket_private) embryos; 8883186Sjulian LIST_ENTRY(ng_ksocket_private) siblings; 8983186Sjulian u_int32_t flags; 9083186Sjulian u_int32_t response_token; 9183186Sjulian ng_ID_t response_addr; 9253246Sarchie}; 9353404Sarchietypedef struct ng_ksocket_private *priv_p; 9453246Sarchie 9583186Sjulian/* Flags for priv_p */ 9683186Sjulian#define KSF_CONNECTING 0x00000001 /* Waiting for connection complete */ 9783186Sjulian#define KSF_ACCEPTING 0x00000002 /* Waiting for accept complete */ 9883186Sjulian#define KSF_EOFSEEN 0x00000004 /* Have sent 0-length EOF mbuf */ 9983186Sjulian#define KSF_CLONED 0x00000008 /* Cloned from an accepting socket */ 10083186Sjulian#define KSF_EMBRYONIC 0x00000010 /* Cloned node with no hooks yet */ 10183186Sjulian 10253246Sarchie/* Netgraph node methods */ 10353246Sarchiestatic ng_constructor_t ng_ksocket_constructor; 10453246Sarchiestatic ng_rcvmsg_t ng_ksocket_rcvmsg; 10570700Sjulianstatic ng_shutdown_t ng_ksocket_shutdown; 10653246Sarchiestatic ng_newhook_t ng_ksocket_newhook; 10753246Sarchiestatic ng_rcvdata_t ng_ksocket_rcvdata; 10883186Sjulianstatic ng_connect_t ng_ksocket_connect; 10953246Sarchiestatic ng_disconnect_t ng_ksocket_disconnect; 11053246Sarchie 11153246Sarchie/* Alias structure */ 11253246Sarchiestruct ng_ksocket_alias { 11353246Sarchie const char *name; 11453246Sarchie const int value; 11553246Sarchie const int family; 11653246Sarchie}; 11753246Sarchie 11853246Sarchie/* Protocol family aliases */ 11953246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_families[] = { 12053246Sarchie { "local", PF_LOCAL }, 12153246Sarchie { "inet", PF_INET }, 12253246Sarchie { "inet6", PF_INET6 }, 12353246Sarchie { "atalk", PF_APPLETALK }, 12453246Sarchie { "ipx", PF_IPX }, 12553246Sarchie { "atm", PF_ATM }, 12653246Sarchie { NULL, -1 }, 12753246Sarchie}; 12853246Sarchie 12953246Sarchie/* Socket type aliases */ 13053246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_types[] = { 13153246Sarchie { "stream", SOCK_STREAM }, 13253246Sarchie { "dgram", SOCK_DGRAM }, 13353246Sarchie { "raw", SOCK_RAW }, 13453246Sarchie { "rdm", SOCK_RDM }, 13553246Sarchie { "seqpacket", SOCK_SEQPACKET }, 13653246Sarchie { NULL, -1 }, 13753246Sarchie}; 13853246Sarchie 13953246Sarchie/* Protocol aliases */ 14053246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_protos[] = { 14153246Sarchie { "ip", IPPROTO_IP, PF_INET }, 14284776Sarchie { "raw", IPPROTO_RAW, PF_INET }, 14353246Sarchie { "icmp", IPPROTO_ICMP, PF_INET }, 14453246Sarchie { "igmp", IPPROTO_IGMP, PF_INET }, 14553246Sarchie { "tcp", IPPROTO_TCP, PF_INET }, 14653246Sarchie { "udp", IPPROTO_UDP, PF_INET }, 14753246Sarchie { "gre", IPPROTO_GRE, PF_INET }, 14853246Sarchie { "esp", IPPROTO_ESP, PF_INET }, 14953246Sarchie { "ah", IPPROTO_AH, PF_INET }, 15053246Sarchie { "swipe", IPPROTO_SWIPE, PF_INET }, 15153246Sarchie { "encap", IPPROTO_ENCAP, PF_INET }, 15253246Sarchie { "divert", IPPROTO_DIVERT, PF_INET }, 153119187Shsu { "pim", IPPROTO_PIM, PF_INET }, 15453246Sarchie { "ddp", ATPROTO_DDP, PF_APPLETALK }, 15553246Sarchie { "aarp", ATPROTO_AARP, PF_APPLETALK }, 15653246Sarchie { NULL, -1 }, 15753246Sarchie}; 15853246Sarchie 15953913Sarchie/* Helper functions */ 16083186Sjulianstatic int ng_ksocket_check_accept(priv_p); 16183186Sjulianstatic void ng_ksocket_finish_accept(priv_p); 162193272Sjhbstatic int ng_ksocket_incoming(struct socket *so, void *arg, int waitflag); 16353913Sarchiestatic int ng_ksocket_parse(const struct ng_ksocket_alias *aliases, 16453913Sarchie const char *s, int family); 16583186Sjulianstatic void ng_ksocket_incoming2(node_p node, hook_p hook, 166176917Smav void *arg1, int arg2); 16753913Sarchie 16853913Sarchie/************************************************************************ 16953913Sarchie STRUCT SOCKADDR PARSE TYPE 17053913Sarchie ************************************************************************/ 17153913Sarchie 17253913Sarchie/* Get the length of the data portion of a generic struct sockaddr */ 17353913Sarchiestatic int 17453913Sarchieng_parse_generic_sockdata_getLength(const struct ng_parse_type *type, 17553913Sarchie const u_char *start, const u_char *buf) 17653913Sarchie{ 17753913Sarchie const struct sockaddr *sa; 17853913Sarchie 17953913Sarchie sa = (const struct sockaddr *)(buf - SADATA_OFFSET); 18064470Sarchie return (sa->sa_len < SADATA_OFFSET) ? 0 : sa->sa_len - SADATA_OFFSET; 18153913Sarchie} 18253913Sarchie 18353913Sarchie/* Type for the variable length data portion of a generic struct sockaddr */ 18453913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockdata_type = { 18553913Sarchie &ng_parse_bytearray_type, 18653913Sarchie &ng_parse_generic_sockdata_getLength 18753913Sarchie}; 18853913Sarchie 18953913Sarchie/* Type for a generic struct sockaddr */ 19097685Sarchiestatic const struct ng_parse_struct_field 19197685Sarchie ng_parse_generic_sockaddr_type_fields[] = { 19264508Sarchie { "len", &ng_parse_uint8_type }, 19364508Sarchie { "family", &ng_parse_uint8_type }, 19453913Sarchie { "data", &ng_ksocket_generic_sockdata_type }, 19553913Sarchie { NULL } 19653913Sarchie}; 19753913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockaddr_type = { 19853913Sarchie &ng_parse_struct_type, 19997685Sarchie &ng_parse_generic_sockaddr_type_fields 20053913Sarchie}; 20153913Sarchie 20253913Sarchie/* Convert a struct sockaddr from ASCII to binary. If its a protocol 20353913Sarchie family that we specially handle, do that, otherwise defer to the 20453913Sarchie generic parse type ng_ksocket_generic_sockaddr_type. */ 20553913Sarchiestatic int 20653913Sarchieng_ksocket_sockaddr_parse(const struct ng_parse_type *type, 20753913Sarchie const char *s, int *off, const u_char *const start, 20853913Sarchie u_char *const buf, int *buflen) 20953913Sarchie{ 21053913Sarchie struct sockaddr *const sa = (struct sockaddr *)buf; 21153913Sarchie enum ng_parse_token tok; 21253913Sarchie char fambuf[32]; 21353913Sarchie int family, len; 21453913Sarchie char *t; 21553913Sarchie 21653913Sarchie /* If next token is a left curly brace, use generic parse type */ 21753913Sarchie if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) { 21853913Sarchie return (*ng_ksocket_generic_sockaddr_type.supertype->parse) 21953913Sarchie (&ng_ksocket_generic_sockaddr_type, 22053913Sarchie s, off, start, buf, buflen); 22153913Sarchie } 22253913Sarchie 22353913Sarchie /* Get socket address family followed by a slash */ 22453913Sarchie while (isspace(s[*off])) 22553913Sarchie (*off)++; 22653913Sarchie if ((t = index(s + *off, '/')) == NULL) 22753913Sarchie return (EINVAL); 22853913Sarchie if ((len = t - (s + *off)) > sizeof(fambuf) - 1) 22953913Sarchie return (EINVAL); 23053913Sarchie strncpy(fambuf, s + *off, len); 23153913Sarchie fambuf[len] = '\0'; 23253913Sarchie *off += len + 1; 23353913Sarchie if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1) 23453913Sarchie return (EINVAL); 23553913Sarchie 23653913Sarchie /* Set family */ 23753913Sarchie if (*buflen < SADATA_OFFSET) 23853913Sarchie return (ERANGE); 23953913Sarchie sa->sa_family = family; 24053913Sarchie 24153913Sarchie /* Set family-specific data and length */ 24253913Sarchie switch (sa->sa_family) { 24353913Sarchie case PF_LOCAL: /* Get pathname */ 24453913Sarchie { 24553913Sarchie const int pathoff = OFFSETOF(struct sockaddr_un, sun_path); 24653913Sarchie struct sockaddr_un *const sun = (struct sockaddr_un *)sa; 24753913Sarchie int toklen, pathlen; 24853913Sarchie char *path; 24953913Sarchie 25068845Sbrian if ((path = ng_get_string_token(s, off, &toklen, NULL)) == NULL) 25153913Sarchie return (EINVAL); 25253913Sarchie pathlen = strlen(path); 25353913Sarchie if (pathlen > SOCK_MAXADDRLEN) { 254184205Sdes free(path, M_NETGRAPH_KSOCKET); 25553913Sarchie return (E2BIG); 25653913Sarchie } 25753913Sarchie if (*buflen < pathoff + pathlen) { 258184205Sdes free(path, M_NETGRAPH_KSOCKET); 25953913Sarchie return (ERANGE); 26053913Sarchie } 26153913Sarchie *off += toklen; 26253913Sarchie bcopy(path, sun->sun_path, pathlen); 26353913Sarchie sun->sun_len = pathoff + pathlen; 264184205Sdes free(path, M_NETGRAPH_KSOCKET); 26553913Sarchie break; 26653913Sarchie } 26753913Sarchie 26853913Sarchie case PF_INET: /* Get an IP address with optional port */ 26953913Sarchie { 27053913Sarchie struct sockaddr_in *const sin = (struct sockaddr_in *)sa; 27153913Sarchie int i; 27253913Sarchie 27353913Sarchie /* Parse this: <ipaddress>[:port] */ 27453913Sarchie for (i = 0; i < 4; i++) { 27553913Sarchie u_long val; 27653913Sarchie char *eptr; 27753913Sarchie 27853913Sarchie val = strtoul(s + *off, &eptr, 10); 27953913Sarchie if (val > 0xff || eptr == s + *off) 28053913Sarchie return (EINVAL); 28153913Sarchie *off += (eptr - (s + *off)); 28253913Sarchie ((u_char *)&sin->sin_addr)[i] = (u_char)val; 28353913Sarchie if (i < 3) { 28453913Sarchie if (s[*off] != '.') 28553913Sarchie return (EINVAL); 28653913Sarchie (*off)++; 28753913Sarchie } else if (s[*off] == ':') { 28853913Sarchie (*off)++; 28953913Sarchie val = strtoul(s + *off, &eptr, 10); 29053913Sarchie if (val > 0xffff || eptr == s + *off) 29153913Sarchie return (EINVAL); 29253913Sarchie *off += (eptr - (s + *off)); 29353913Sarchie sin->sin_port = htons(val); 29453913Sarchie } else 29553913Sarchie sin->sin_port = 0; 29653913Sarchie } 29753913Sarchie bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 29853913Sarchie sin->sin_len = sizeof(*sin); 29953913Sarchie break; 30053913Sarchie } 30153913Sarchie 30253913Sarchie#if 0 30353913Sarchie case PF_APPLETALK: /* XXX implement these someday */ 30453913Sarchie case PF_INET6: 30553913Sarchie case PF_IPX: 30653913Sarchie#endif 30753913Sarchie 30853913Sarchie default: 30953913Sarchie return (EINVAL); 31053913Sarchie } 31153913Sarchie 31253913Sarchie /* Done */ 31353913Sarchie *buflen = sa->sa_len; 31453913Sarchie return (0); 31553913Sarchie} 31653913Sarchie 31753913Sarchie/* Convert a struct sockaddr from binary to ASCII */ 31853913Sarchiestatic int 31953913Sarchieng_ksocket_sockaddr_unparse(const struct ng_parse_type *type, 32053913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 32153913Sarchie{ 32253913Sarchie const struct sockaddr *sa = (const struct sockaddr *)(data + *off); 32353913Sarchie int slen = 0; 32453913Sarchie 32553913Sarchie /* Output socket address, either in special or generic format */ 32653913Sarchie switch (sa->sa_family) { 32753913Sarchie case PF_LOCAL: 32853913Sarchie { 32953913Sarchie const int pathoff = OFFSETOF(struct sockaddr_un, sun_path); 33053913Sarchie const struct sockaddr_un *sun = (const struct sockaddr_un *)sa; 33153913Sarchie const int pathlen = sun->sun_len - pathoff; 33253913Sarchie char pathbuf[SOCK_MAXADDRLEN + 1]; 33353913Sarchie char *pathtoken; 33453913Sarchie 33553913Sarchie bcopy(sun->sun_path, pathbuf, pathlen); 33668845Sbrian if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL) 33753913Sarchie return (ENOMEM); 33853913Sarchie slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken); 339184205Sdes free(pathtoken, M_NETGRAPH_KSOCKET); 34053913Sarchie if (slen >= cbuflen) 34153913Sarchie return (ERANGE); 34253913Sarchie *off += sun->sun_len; 34353913Sarchie return (0); 34453913Sarchie } 34553913Sarchie 34653913Sarchie case PF_INET: 34753913Sarchie { 34853913Sarchie const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 34953913Sarchie 35053913Sarchie slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d", 35153913Sarchie ((const u_char *)&sin->sin_addr)[0], 35253913Sarchie ((const u_char *)&sin->sin_addr)[1], 35353913Sarchie ((const u_char *)&sin->sin_addr)[2], 35453913Sarchie ((const u_char *)&sin->sin_addr)[3]); 35553913Sarchie if (sin->sin_port != 0) { 35653913Sarchie slen += snprintf(cbuf + strlen(cbuf), 35753913Sarchie cbuflen - strlen(cbuf), ":%d", 35853913Sarchie (u_int)ntohs(sin->sin_port)); 35953913Sarchie } 36053913Sarchie if (slen >= cbuflen) 36153913Sarchie return (ERANGE); 36253913Sarchie *off += sizeof(*sin); 36353913Sarchie return(0); 36453913Sarchie } 36553913Sarchie 36653913Sarchie#if 0 36753913Sarchie case PF_APPLETALK: /* XXX implement these someday */ 36853913Sarchie case PF_INET6: 36953913Sarchie case PF_IPX: 37053913Sarchie#endif 37153913Sarchie 37253913Sarchie default: 37353913Sarchie return (*ng_ksocket_generic_sockaddr_type.supertype->unparse) 37453913Sarchie (&ng_ksocket_generic_sockaddr_type, 37553913Sarchie data, off, cbuf, cbuflen); 37653913Sarchie } 37753913Sarchie} 37853913Sarchie 37953913Sarchie/* Parse type for struct sockaddr */ 38053913Sarchiestatic const struct ng_parse_type ng_ksocket_sockaddr_type = { 38153913Sarchie NULL, 38253913Sarchie NULL, 38353913Sarchie NULL, 38453913Sarchie &ng_ksocket_sockaddr_parse, 38553913Sarchie &ng_ksocket_sockaddr_unparse, 38653913Sarchie NULL /* no such thing as a default struct sockaddr */ 38753913Sarchie}; 38853913Sarchie 38953913Sarchie/************************************************************************ 39053913Sarchie STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE 39153913Sarchie ************************************************************************/ 39253913Sarchie 39353913Sarchie/* Get length of the struct ng_ksocket_sockopt value field, which is the 39453913Sarchie just the excess of the message argument portion over the length of 39553913Sarchie the struct ng_ksocket_sockopt. */ 39653913Sarchiestatic int 39753913Sarchieng_parse_sockoptval_getLength(const struct ng_parse_type *type, 39853913Sarchie const u_char *start, const u_char *buf) 39953913Sarchie{ 40053913Sarchie static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value); 40153913Sarchie const struct ng_ksocket_sockopt *sopt; 40253913Sarchie const struct ng_mesg *msg; 40353913Sarchie 40453913Sarchie sopt = (const struct ng_ksocket_sockopt *)(buf - offset); 40553913Sarchie msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg)); 40653913Sarchie return msg->header.arglen - sizeof(*sopt); 40753913Sarchie} 40853913Sarchie 40953913Sarchie/* Parse type for the option value part of a struct ng_ksocket_sockopt 41053913Sarchie XXX Eventually, we should handle the different socket options specially. 41153913Sarchie XXX This would avoid byte order problems, eg an integer value of 1 is 41253913Sarchie XXX going to be "[1]" for little endian or "[3=1]" for big endian. */ 41353913Sarchiestatic const struct ng_parse_type ng_ksocket_sockoptval_type = { 41453913Sarchie &ng_parse_bytearray_type, 41553913Sarchie &ng_parse_sockoptval_getLength 41653913Sarchie}; 41753913Sarchie 41853913Sarchie/* Parse type for struct ng_ksocket_sockopt */ 41997685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_sockopt_type_fields[] 42053913Sarchie = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type); 42153913Sarchiestatic const struct ng_parse_type ng_ksocket_sockopt_type = { 42253913Sarchie &ng_parse_struct_type, 42397685Sarchie &ng_ksocket_sockopt_type_fields 42453913Sarchie}; 42553913Sarchie 42683186Sjulian/* Parse type for struct ng_ksocket_accept */ 42797685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_accept_type_fields[] 42883186Sjulian = NGM_KSOCKET_ACCEPT_INFO; 42983186Sjulianstatic const struct ng_parse_type ng_ksocket_accept_type = { 43083186Sjulian &ng_parse_struct_type, 43197685Sarchie &ng_ksocket_accept_type_fields 43283186Sjulian}; 43383186Sjulian 43453913Sarchie/* List of commands and how to convert arguments to/from ASCII */ 43553913Sarchiestatic const struct ng_cmdlist ng_ksocket_cmds[] = { 43653913Sarchie { 43753913Sarchie NGM_KSOCKET_COOKIE, 43853913Sarchie NGM_KSOCKET_BIND, 43953913Sarchie "bind", 44053913Sarchie &ng_ksocket_sockaddr_type, 44153913Sarchie NULL 44253913Sarchie }, 44353913Sarchie { 44453913Sarchie NGM_KSOCKET_COOKIE, 44553913Sarchie NGM_KSOCKET_LISTEN, 44653913Sarchie "listen", 44753913Sarchie &ng_parse_int32_type, 44853913Sarchie NULL 44953913Sarchie }, 45053913Sarchie { 45153913Sarchie NGM_KSOCKET_COOKIE, 45253913Sarchie NGM_KSOCKET_ACCEPT, 45353913Sarchie "accept", 45453913Sarchie NULL, 45583186Sjulian &ng_ksocket_accept_type 45653913Sarchie }, 45753913Sarchie { 45853913Sarchie NGM_KSOCKET_COOKIE, 45953913Sarchie NGM_KSOCKET_CONNECT, 46053913Sarchie "connect", 46153913Sarchie &ng_ksocket_sockaddr_type, 46283186Sjulian &ng_parse_int32_type 46353913Sarchie }, 46453913Sarchie { 46553913Sarchie NGM_KSOCKET_COOKIE, 46653913Sarchie NGM_KSOCKET_GETNAME, 46753913Sarchie "getname", 46853913Sarchie NULL, 46953913Sarchie &ng_ksocket_sockaddr_type 47053913Sarchie }, 47153913Sarchie { 47253913Sarchie NGM_KSOCKET_COOKIE, 47353913Sarchie NGM_KSOCKET_GETPEERNAME, 47453913Sarchie "getpeername", 47553913Sarchie NULL, 47653913Sarchie &ng_ksocket_sockaddr_type 47753913Sarchie }, 47853913Sarchie { 47953913Sarchie NGM_KSOCKET_COOKIE, 48053913Sarchie NGM_KSOCKET_SETOPT, 48153913Sarchie "setopt", 48253913Sarchie &ng_ksocket_sockopt_type, 48353913Sarchie NULL 48453913Sarchie }, 48553913Sarchie { 48653913Sarchie NGM_KSOCKET_COOKIE, 48753913Sarchie NGM_KSOCKET_GETOPT, 48853913Sarchie "getopt", 48953913Sarchie &ng_ksocket_sockopt_type, 49053913Sarchie &ng_ksocket_sockopt_type 49153913Sarchie }, 49253913Sarchie { 0 } 49353913Sarchie}; 49453913Sarchie 49553913Sarchie/* Node type descriptor */ 49653913Sarchiestatic struct ng_type ng_ksocket_typestruct = { 497129823Sjulian .version = NG_ABI_VERSION, 498129823Sjulian .name = NG_KSOCKET_NODE_TYPE, 499129823Sjulian .constructor = ng_ksocket_constructor, 500129823Sjulian .rcvmsg = ng_ksocket_rcvmsg, 501129823Sjulian .shutdown = ng_ksocket_shutdown, 502129823Sjulian .newhook = ng_ksocket_newhook, 503129823Sjulian .connect = ng_ksocket_connect, 504129823Sjulian .rcvdata = ng_ksocket_rcvdata, 505129823Sjulian .disconnect = ng_ksocket_disconnect, 506129823Sjulian .cmdlist = 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 */ 527220768Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_KSOCKET, M_WAITOK | M_ZERO); 52853246Sarchie 52983186Sjulian LIST_INIT(&priv->embryos); 53083186Sjulian /* cross link them */ 53183186Sjulian priv->node = node; 53270784Sjulian NG_NODE_SET_PRIVATE(node, priv); 53353246Sarchie 53453246Sarchie /* Done */ 53553246Sarchie return (0); 53653246Sarchie} 53753246Sarchie 53853246Sarchie/* 53953246Sarchie * Give our OK for a hook to be added. The hook name is of the 54072545Sarchie * form "<family>/<type>/<proto>" where the three components may 54153246Sarchie * be decimal numbers or else aliases from the above lists. 54253246Sarchie * 54353246Sarchie * Connecting a hook amounts to opening the socket. Disconnecting 54453246Sarchie * the hook closes the socket and destroys the node as well. 54553246Sarchie */ 54653246Sarchiestatic int 54753246Sarchieng_ksocket_newhook(node_p node, hook_p hook, const char *name0) 54853246Sarchie{ 549134651Srwatson struct thread *td = curthread; /* XXX broken */ 55070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 551125028Sharti char *s1, *s2, name[NG_HOOKSIZ]; 55253246Sarchie int family, type, protocol, error; 55353246Sarchie 55453246Sarchie /* Check if we're already connected */ 55553246Sarchie if (priv->hook != NULL) 55653246Sarchie return (EISCONN); 55753246Sarchie 55883186Sjulian if (priv->flags & KSF_CLONED) { 55983186Sjulian if (priv->flags & KSF_EMBRYONIC) { 56083186Sjulian /* Remove ourselves from our parent's embryo list */ 56183186Sjulian LIST_REMOVE(priv, siblings); 56283186Sjulian priv->flags &= ~KSF_EMBRYONIC; 56383186Sjulian } 56483186Sjulian } else { 56583186Sjulian /* Extract family, type, and protocol from hook name */ 56683186Sjulian snprintf(name, sizeof(name), "%s", name0); 56783186Sjulian s1 = name; 56883186Sjulian if ((s2 = index(s1, '/')) == NULL) 56983186Sjulian return (EINVAL); 57083186Sjulian *s2++ = '\0'; 57183186Sjulian family = ng_ksocket_parse(ng_ksocket_families, s1, 0); 57283186Sjulian if (family == -1) 57383186Sjulian return (EINVAL); 57483186Sjulian s1 = s2; 57583186Sjulian if ((s2 = index(s1, '/')) == NULL) 57683186Sjulian return (EINVAL); 57783186Sjulian *s2++ = '\0'; 57883186Sjulian type = ng_ksocket_parse(ng_ksocket_types, s1, 0); 57983186Sjulian if (type == -1) 58083186Sjulian return (EINVAL); 58183186Sjulian s1 = s2; 58283186Sjulian protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family); 58383186Sjulian if (protocol == -1) 58483186Sjulian return (EINVAL); 58553246Sarchie 58683186Sjulian /* Create the socket */ 58788739Srwatson error = socreate(family, &priv->so, type, protocol, 58891406Sjhb td->td_ucred, td); 58983186Sjulian if (error != 0) 59083186Sjulian return (error); 59153246Sarchie 59283186Sjulian /* XXX call soreserve() ? */ 59353246Sarchie 59483186Sjulian } 59583186Sjulian 59683186Sjulian /* OK */ 59783186Sjulian priv->hook = hook; 598145229Sglebius 599145229Sglebius /* 600145229Sglebius * In case of misconfigured routing a packet may reenter 601145229Sglebius * ksocket node recursively. Decouple stack to avoid possible 602145229Sglebius * panics about sleeping with locks held. 603145229Sglebius */ 604145229Sglebius NG_HOOK_FORCE_QUEUE(hook); 605145229Sglebius 60683186Sjulian return(0); 60783186Sjulian} 60883186Sjulian 60983186Sjulianstatic int 61083186Sjulianng_ksocket_connect(hook_p hook) 61183186Sjulian{ 61283186Sjulian node_p node = NG_HOOK_NODE(hook); 61383186Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 61483186Sjulian struct socket *const so = priv->so; 61583186Sjulian 61683186Sjulian /* Add our hook for incoming data and other events */ 617130653Srwatson SOCKBUF_LOCK(&priv->so->so_rcv); 618193272Sjhb soupcall_set(priv->so, SO_RCV, ng_ksocket_incoming, node); 619130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_rcv); 620130653Srwatson SOCKBUF_LOCK(&priv->so->so_snd); 621193272Sjhb soupcall_set(priv->so, SO_SND, ng_ksocket_incoming, node); 622130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_snd); 623130653Srwatson SOCK_LOCK(priv->so); 62483186Sjulian priv->so->so_state |= SS_NBIO; 625130653Srwatson SOCK_UNLOCK(priv->so); 62683186Sjulian /* 62783186Sjulian * --Original comment-- 62883186Sjulian * On a cloned socket we may have already received one or more 62983186Sjulian * upcalls which we couldn't handle without a hook. Handle 63083186Sjulian * those now. 63183186Sjulian * We cannot call the upcall function directly 63283186Sjulian * from here, because until this function has returned our 63383186Sjulian * hook isn't connected. 63483186Sjulian * 63583186Sjulian * ---meta comment for -current --- 63683186Sjulian * XXX This is dubius. 63783186Sjulian * Upcalls between the time that the hook was 63883186Sjulian * first created and now (on another processesor) will 63983186Sjulian * be earlier on the queue than the request to finalise the hook. 64083186Sjulian * By the time the hook is finalised, 64183186Sjulian * The queued upcalls will have happenned and the code 64283186Sjulian * will have discarded them because of a lack of a hook. 64383186Sjulian * (socket not open). 64483186Sjulian * 64583186Sjulian * This is a bad byproduct of the complicated way in which hooks 64683186Sjulian * are now created (3 daisy chained async events). 64783186Sjulian * 64883186Sjulian * Since we are a netgraph operation 64983186Sjulian * We know that we hold a lock on this node. This forces the 65083186Sjulian * request we make below to be queued rather than implemented 65183186Sjulian * immediatly which will cause the upcall function to be called a bit 65283186Sjulian * later. 65383186Sjulian * However, as we will run any waiting queued operations immediatly 65483186Sjulian * after doing this one, if we have not finalised the other end 65583186Sjulian * of the hook, those queued operations will fail. 65683186Sjulian */ 65783186Sjulian if (priv->flags & KSF_CLONED) { 65883186Sjulian ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_NOWAIT); 65983186Sjulian } 66053246Sarchie 66153246Sarchie return (0); 66253246Sarchie} 66353246Sarchie 66453246Sarchie/* 66553246Sarchie * Receive a control message 66653246Sarchie */ 66753246Sarchiestatic int 66870700Sjulianng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) 66953246Sarchie{ 670134651Srwatson struct thread *td = curthread; /* XXX broken */ 67170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 67253913Sarchie struct socket *const so = priv->so; 67353246Sarchie struct ng_mesg *resp = NULL; 67453246Sarchie int error = 0; 67570700Sjulian struct ng_mesg *msg; 67683186Sjulian ng_ID_t raddr; 67753246Sarchie 67870700Sjulian NGI_GET_MSG(item, msg); 67953246Sarchie switch (msg->header.typecookie) { 68053246Sarchie case NGM_KSOCKET_COOKIE: 68153246Sarchie switch (msg->header.cmd) { 68253246Sarchie case NGM_KSOCKET_BIND: 68353246Sarchie { 68453913Sarchie struct sockaddr *const sa 68553913Sarchie = (struct sockaddr *)msg->data; 68653246Sarchie 68753913Sarchie /* Sanity check */ 68853913Sarchie if (msg->header.arglen < SADATA_OFFSET 68953913Sarchie || msg->header.arglen < sa->sa_len) 69053913Sarchie ERROUT(EINVAL); 69153913Sarchie if (so == NULL) 69253913Sarchie ERROUT(ENXIO); 69353246Sarchie 69453913Sarchie /* Bind */ 69583366Sjulian error = sobind(so, sa, td); 69653246Sarchie break; 69753246Sarchie } 69853246Sarchie case NGM_KSOCKET_LISTEN: 69953246Sarchie { 70053913Sarchie /* Sanity check */ 70183186Sjulian if (msg->header.arglen != sizeof(int32_t)) 70253246Sarchie ERROUT(EINVAL); 70353913Sarchie if (so == NULL) 70453913Sarchie ERROUT(ENXIO); 70553246Sarchie 70653913Sarchie /* Listen */ 70783366Sjulian error = solisten(so, *((int32_t *)msg->data), td); 70853246Sarchie break; 70953246Sarchie } 71053246Sarchie 71153246Sarchie case NGM_KSOCKET_ACCEPT: 71253246Sarchie { 71353913Sarchie /* Sanity check */ 71453913Sarchie if (msg->header.arglen != 0) 71553913Sarchie ERROUT(EINVAL); 71653913Sarchie if (so == NULL) 71753913Sarchie ERROUT(ENXIO); 71853913Sarchie 71983186Sjulian /* Make sure the socket is capable of accepting */ 72083186Sjulian if (!(so->so_options & SO_ACCEPTCONN)) 72197658Stanimura ERROUT(EINVAL); 72283186Sjulian if (priv->flags & KSF_ACCEPTING) 72383186Sjulian ERROUT(EALREADY); 72453913Sarchie 72583186Sjulian error = ng_ksocket_check_accept(priv); 72683186Sjulian if (error != 0 && error != EWOULDBLOCK) 72783186Sjulian ERROUT(error); 72883186Sjulian 72983186Sjulian /* 73083186Sjulian * If a connection is already complete, take it. 73183186Sjulian * Otherwise let the upcall function deal with 73283186Sjulian * the connection when it comes in. 73383186Sjulian */ 73483186Sjulian priv->response_token = msg->header.token; 735103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 73683186Sjulian if (error == 0) { 73783186Sjulian ng_ksocket_finish_accept(priv); 73883186Sjulian } else 73983186Sjulian priv->flags |= KSF_ACCEPTING; 74053246Sarchie break; 74153246Sarchie } 74253246Sarchie 74353246Sarchie case NGM_KSOCKET_CONNECT: 74453246Sarchie { 74553913Sarchie struct sockaddr *const sa 74653913Sarchie = (struct sockaddr *)msg->data; 74753246Sarchie 74853913Sarchie /* Sanity check */ 74953913Sarchie if (msg->header.arglen < SADATA_OFFSET 75053913Sarchie || msg->header.arglen < sa->sa_len) 75153913Sarchie ERROUT(EINVAL); 75253913Sarchie if (so == NULL) 75353913Sarchie ERROUT(ENXIO); 75453246Sarchie 75553246Sarchie /* Do connect */ 75653246Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) 75797658Stanimura ERROUT(EALREADY); 75883366Sjulian if ((error = soconnect(so, sa, td)) != 0) { 75953246Sarchie so->so_state &= ~SS_ISCONNECTING; 76097658Stanimura ERROUT(error); 76153246Sarchie } 762114178Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) { 76383186Sjulian /* We will notify the sender when we connect */ 76483186Sjulian priv->response_token = msg->header.token; 765103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 76683186Sjulian priv->flags |= KSF_CONNECTING; 76797658Stanimura ERROUT(EINPROGRESS); 768114178Sarchie } 76953246Sarchie break; 77053246Sarchie } 77153246Sarchie 77253246Sarchie case NGM_KSOCKET_GETNAME: 77353913Sarchie case NGM_KSOCKET_GETPEERNAME: 77453246Sarchie { 77553913Sarchie int (*func)(struct socket *so, struct sockaddr **nam); 77653913Sarchie struct sockaddr *sa = NULL; 77753913Sarchie int len; 77853246Sarchie 77953913Sarchie /* Sanity check */ 78053913Sarchie if (msg->header.arglen != 0) 78153913Sarchie ERROUT(EINVAL); 78253913Sarchie if (so == NULL) 78353913Sarchie ERROUT(ENXIO); 78453913Sarchie 78553913Sarchie /* Get function */ 78653913Sarchie if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) { 78753913Sarchie if ((so->so_state 78853913Sarchie & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) 78997658Stanimura ERROUT(ENOTCONN); 79053913Sarchie func = so->so_proto->pr_usrreqs->pru_peeraddr; 79153913Sarchie } else 79253913Sarchie func = so->so_proto->pr_usrreqs->pru_sockaddr; 79353913Sarchie 79453913Sarchie /* Get local or peer address */ 79553913Sarchie if ((error = (*func)(so, &sa)) != 0) 79653913Sarchie goto bail; 79753913Sarchie len = (sa == NULL) ? 0 : sa->sa_len; 79853913Sarchie 79953913Sarchie /* Send it back in a response */ 80053913Sarchie NG_MKRESPONSE(resp, msg, len, M_NOWAIT); 80153913Sarchie if (resp == NULL) { 80253913Sarchie error = ENOMEM; 80353913Sarchie goto bail; 80453913Sarchie } 80553913Sarchie bcopy(sa, resp->data, len); 80653913Sarchie 80753913Sarchie bail: 80853913Sarchie /* Cleanup */ 80953913Sarchie if (sa != NULL) 810184205Sdes free(sa, M_SONAME); 81153246Sarchie break; 81253246Sarchie } 81353246Sarchie 81453246Sarchie case NGM_KSOCKET_GETOPT: 81553246Sarchie { 81653913Sarchie struct ng_ksocket_sockopt *ksopt = 81753913Sarchie (struct ng_ksocket_sockopt *)msg->data; 81853913Sarchie struct sockopt sopt; 81953913Sarchie 82053913Sarchie /* Sanity check */ 82153913Sarchie if (msg->header.arglen != sizeof(*ksopt)) 82253913Sarchie ERROUT(EINVAL); 82353913Sarchie if (so == NULL) 82453913Sarchie ERROUT(ENXIO); 82553913Sarchie 82653913Sarchie /* Get response with room for option value */ 82753913Sarchie NG_MKRESPONSE(resp, msg, sizeof(*ksopt) 82853913Sarchie + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT); 82953913Sarchie if (resp == NULL) 83053913Sarchie ERROUT(ENOMEM); 83153913Sarchie 83253913Sarchie /* Get socket option, and put value in the response */ 83353913Sarchie sopt.sopt_dir = SOPT_GET; 83453913Sarchie sopt.sopt_level = ksopt->level; 83553913Sarchie sopt.sopt_name = ksopt->name; 83683366Sjulian sopt.sopt_td = NULL; 83753913Sarchie sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN; 83853913Sarchie ksopt = (struct ng_ksocket_sockopt *)resp->data; 83953913Sarchie sopt.sopt_val = ksopt->value; 84053913Sarchie if ((error = sogetopt(so, &sopt)) != 0) { 84170700Sjulian NG_FREE_MSG(resp); 84253913Sarchie break; 84353913Sarchie } 84453913Sarchie 84553913Sarchie /* Set actual value length */ 84653913Sarchie resp->header.arglen = sizeof(*ksopt) 84753913Sarchie + sopt.sopt_valsize; 84853246Sarchie break; 84953246Sarchie } 85053246Sarchie 85153246Sarchie case NGM_KSOCKET_SETOPT: 85253246Sarchie { 85353913Sarchie struct ng_ksocket_sockopt *const ksopt = 85453913Sarchie (struct ng_ksocket_sockopt *)msg->data; 85553913Sarchie const int valsize = msg->header.arglen - sizeof(*ksopt); 85653913Sarchie struct sockopt sopt; 85753913Sarchie 85853913Sarchie /* Sanity check */ 85953913Sarchie if (valsize < 0) 86053913Sarchie ERROUT(EINVAL); 86153913Sarchie if (so == NULL) 86253913Sarchie ERROUT(ENXIO); 86353913Sarchie 86453913Sarchie /* Set socket option */ 86553913Sarchie sopt.sopt_dir = SOPT_SET; 86653913Sarchie sopt.sopt_level = ksopt->level; 86753913Sarchie sopt.sopt_name = ksopt->name; 86853913Sarchie sopt.sopt_val = ksopt->value; 86953913Sarchie sopt.sopt_valsize = valsize; 87083366Sjulian sopt.sopt_td = NULL; 87153913Sarchie error = sosetopt(so, &sopt); 87253246Sarchie break; 87353246Sarchie } 87453246Sarchie 87553246Sarchie default: 87653246Sarchie error = EINVAL; 87753246Sarchie break; 87853246Sarchie } 87953246Sarchie break; 88053246Sarchie default: 88153246Sarchie error = EINVAL; 88253246Sarchie break; 88353246Sarchie } 88453246Sarchiedone: 88570700Sjulian NG_RESPOND_MSG(error, node, item, resp); 88670700Sjulian NG_FREE_MSG(msg); 88753246Sarchie return (error); 88853246Sarchie} 88953246Sarchie 89053246Sarchie/* 89153246Sarchie * Receive incoming data on our hook. Send it out the socket. 89253246Sarchie */ 89353246Sarchiestatic int 89470700Sjulianng_ksocket_rcvdata(hook_p hook, item_p item) 89553246Sarchie{ 896134651Srwatson struct thread *td = curthread; /* XXX broken */ 89770784Sjulian const node_p node = NG_HOOK_NODE(hook); 89870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 89953246Sarchie struct socket *const so = priv->so; 90087070Sarchie struct sockaddr *sa = NULL; 90153246Sarchie int error; 90270700Sjulian struct mbuf *m; 903206017Smav#ifdef ALIGNED_POINTER 904206017Smav struct mbuf *n; 905206017Smav#endif /* ALIGNED_POINTER */ 906131108Sjulian struct sa_tag *stag; 90753246Sarchie 908131108Sjulian /* Extract data */ 90970700Sjulian NGI_GET_M(item, m); 91070700Sjulian NG_FREE_ITEM(item); 911206017Smav#ifdef ALIGNED_POINTER 912206017Smav if (!ALIGNED_POINTER(mtod(m, caddr_t), uint32_t)) { 913206017Smav n = m_defrag(m, M_NOWAIT); 914206017Smav if (n == NULL) { 915206017Smav m_freem(m); 916206017Smav return (ENOBUFS); 917206017Smav } 918206017Smav m = n; 919206017Smav } 920206017Smav#endif /* ALIGNED_POINTER */ 921141728Sglebius /* 922141728Sglebius * Look if socket address is stored in packet tags. 923141728Sglebius * If sockaddr is ours, or provided by a third party (zero id), 924141728Sglebius * then we accept it. 925141728Sglebius */ 926141728Sglebius if (((stag = (struct sa_tag *)m_tag_locate(m, NGM_KSOCKET_COOKIE, 927141728Sglebius NG_KSOCKET_TAG_SOCKADDR, NULL)) != NULL) && 928141728Sglebius (stag->id == NG_NODE_ID(node) || stag->id == 0)) 929131108Sjulian sa = &stag->sa; 93087070Sarchie 931166585Sbms /* Reset specific mbuf flags to prevent addressing problems. */ 932166585Sbms m->m_flags &= ~(M_BCAST|M_MCAST); 933166585Sbms 93487070Sarchie /* Send packet */ 935160619Srwatson error = sosend(so, sa, 0, m, 0, 0, td); 93687070Sarchie 93753246Sarchie return (error); 93853246Sarchie} 93953246Sarchie 94053246Sarchie/* 94153246Sarchie * Destroy node 94253246Sarchie */ 94353246Sarchiestatic int 94470700Sjulianng_ksocket_shutdown(node_p node) 94553246Sarchie{ 94670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 94783186Sjulian priv_p embryo; 94853246Sarchie 94953404Sarchie /* Close our socket (if any) */ 95053404Sarchie if (priv->so != NULL) { 951130653Srwatson SOCKBUF_LOCK(&priv->so->so_rcv); 952193272Sjhb soupcall_clear(priv->so, SO_RCV); 953130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_rcv); 954130653Srwatson SOCKBUF_LOCK(&priv->so->so_snd); 955193272Sjhb soupcall_clear(priv->so, SO_SND); 956130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_snd); 95753404Sarchie soclose(priv->so); 95853404Sarchie priv->so = NULL; 95953404Sarchie } 96053404Sarchie 96183186Sjulian /* If we are an embryo, take ourselves out of the parent's list */ 96283186Sjulian if (priv->flags & KSF_EMBRYONIC) { 96383186Sjulian LIST_REMOVE(priv, siblings); 96483186Sjulian priv->flags &= ~KSF_EMBRYONIC; 96583186Sjulian } 96683186Sjulian 96783186Sjulian /* Remove any embryonic children we have */ 96883186Sjulian while (!LIST_EMPTY(&priv->embryos)) { 96983186Sjulian embryo = LIST_FIRST(&priv->embryos); 97083186Sjulian ng_rmnode_self(embryo->node); 97183186Sjulian } 97283186Sjulian 97353246Sarchie /* Take down netgraph node */ 97453246Sarchie bzero(priv, sizeof(*priv)); 975184205Sdes free(priv, M_NETGRAPH_KSOCKET); 97670784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 97770784Sjulian NG_NODE_UNREF(node); /* let the node escape */ 97853246Sarchie return (0); 97953246Sarchie} 98053246Sarchie 98153246Sarchie/* 98253246Sarchie * Hook disconnection 98353246Sarchie */ 98453246Sarchiestatic int 98553246Sarchieng_ksocket_disconnect(hook_p hook) 98653246Sarchie{ 98770784Sjulian KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0, 98887599Sobrien ("%s: numhooks=%d?", __func__, 98972545Sarchie NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)))); 99070784Sjulian if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) 99170784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 99253246Sarchie return (0); 99353246Sarchie} 99453246Sarchie 99553246Sarchie/************************************************************************ 99653246Sarchie HELPER STUFF 99753246Sarchie ************************************************************************/ 99883186Sjulian/* 999176917Smav * You should not "just call" a netgraph node function from an external 1000176917Smav * asynchronous event. This is because in doing so you are ignoring the 1001176917Smav * locking on the netgraph nodes. Instead call your function via ng_send_fn(). 1002176917Smav * This will call the function you chose, but will first do all the 100383186Sjulian * locking rigmarole. Your function MAY only be called at some distant future 100483186Sjulian * time (several millisecs away) so don't give it any arguments 100583186Sjulian * that may be revoked soon (e.g. on your stack). 1006149820Sglebius * 1007149820Sglebius * To decouple stack, we use queue version of ng_send_fn(). 100883186Sjulian */ 100953246Sarchie 1010193272Sjhbstatic int 101183186Sjulianng_ksocket_incoming(struct socket *so, void *arg, int waitflag) 101283186Sjulian{ 101383186Sjulian const node_p node = arg; 1014176917Smav const priv_p priv = NG_NODE_PRIVATE(node); 1015176917Smav int wait = ((waitflag & M_WAITOK) ? NG_WAITOK : 0) | NG_QUEUE; 101683186Sjulian 1017176917Smav /* 1018176917Smav * Even if node is not locked, as soon as we are called, we assume 1019176917Smav * it exist and it's private area is valid. With some care we can 1020176917Smav * access it. Mark node that incoming event for it was sent to 1021176917Smav * avoid unneded queue trashing. 1022176917Smav */ 1023176917Smav if (atomic_cmpset_int(&priv->fn_sent, 0, 1) && 1024176917Smav ng_send_fn1(node, NULL, &ng_ksocket_incoming2, so, 0, wait)) { 1025176917Smav atomic_store_rel_int(&priv->fn_sent, 0); 1026176917Smav } 1027193272Sjhb return (SU_OK); 102883186Sjulian} 102983186Sjulian 103083186Sjulian 103153246Sarchie/* 103253246Sarchie * When incoming data is appended to the socket, we get notified here. 103383186Sjulian * This is also called whenever a significant event occurs for the socket. 103483186Sjulian * Our original caller may have queued this even some time ago and 103583186Sjulian * we cannot trust that he even still exists. The node however is being 1036176917Smav * held with a reference by the queueing code and guarantied to be valid. 103753246Sarchie */ 103853246Sarchiestatic void 1039176917Smavng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2) 104053246Sarchie{ 104183186Sjulian struct socket *so = arg1; 104270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 104353246Sarchie struct mbuf *m; 104483186Sjulian struct ng_mesg *response; 104553246Sarchie struct uio auio; 104653404Sarchie int s, flags, error; 104753246Sarchie 104853404Sarchie s = splnet(); 104953404Sarchie 105083186Sjulian /* so = priv->so; *//* XXX could have derived this like so */ 105187599Sobrien KASSERT(so == priv->so, ("%s: wrong socket", __func__)); 1052176917Smav 1053176917Smav /* Allow next incoming event to be queued. */ 1054176917Smav atomic_store_rel_int(&priv->fn_sent, 0); 105553246Sarchie 105683186Sjulian /* Check whether a pending connect operation has completed */ 105783186Sjulian if (priv->flags & KSF_CONNECTING) { 105883186Sjulian if ((error = so->so_error) != 0) { 105983186Sjulian so->so_error = 0; 106083186Sjulian so->so_state &= ~SS_ISCONNECTING; 106183186Sjulian } 106283186Sjulian if (!(so->so_state & SS_ISCONNECTING)) { 106383186Sjulian NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE, 1064176917Smav NGM_KSOCKET_CONNECT, sizeof(int32_t), M_NOWAIT); 106583186Sjulian if (response != NULL) { 106683186Sjulian response->header.flags |= NGF_RESP; 106783186Sjulian response->header.token = priv->response_token; 106883186Sjulian *(int32_t *)response->data = error; 106983186Sjulian /* 107083186Sjulian * send an async "response" message 107183186Sjulian * to the node that set us up 107283186Sjulian * (if it still exists) 107383186Sjulian */ 1074102244Sarchie NG_SEND_MSG_ID(error, node, 1075102244Sarchie response, priv->response_addr, 0); 107683186Sjulian } 107783186Sjulian priv->flags &= ~KSF_CONNECTING; 107897658Stanimura } 107983186Sjulian } 108083186Sjulian 108183186Sjulian /* Check whether a pending accept operation has completed */ 108283186Sjulian if (priv->flags & KSF_ACCEPTING) { 108383186Sjulian error = ng_ksocket_check_accept(priv); 108483186Sjulian if (error != EWOULDBLOCK) 108583186Sjulian priv->flags &= ~KSF_ACCEPTING; 108683186Sjulian if (error == 0) 108783186Sjulian ng_ksocket_finish_accept(priv); 108883186Sjulian } 108983186Sjulian 109083186Sjulian /* 109183186Sjulian * If we don't have a hook, we must handle data events later. When 109283186Sjulian * the hook gets created and is connected, this upcall function 109383186Sjulian * will be called again. 109483186Sjulian */ 109583186Sjulian if (priv->hook == NULL) { 109683186Sjulian splx(s); 109783186Sjulian return; 109883186Sjulian } 109983186Sjulian 110053246Sarchie /* Read and forward available mbuf's */ 110183366Sjulian auio.uio_td = NULL; 110253246Sarchie auio.uio_resid = 1000000000; 110353246Sarchie flags = MSG_DONTWAIT; 110487070Sarchie while (1) { 110587070Sarchie struct sockaddr *sa = NULL; 110687070Sarchie struct mbuf *n; 110787070Sarchie 110887070Sarchie /* Try to get next packet from socket */ 1109160619Srwatson if ((error = soreceive(so, (so->so_state & SS_ISCONNECTED) ? 1110160619Srwatson NULL : &sa, &auio, &m, (struct mbuf **)0, &flags)) != 0) 111187070Sarchie break; 111253913Sarchie 111387070Sarchie /* See if we got anything */ 111487070Sarchie if (m == NULL) { 111587070Sarchie if (sa != NULL) 1116184205Sdes free(sa, M_SONAME); 111787070Sarchie break; 111853913Sarchie } 111983186Sjulian 1120149820Sglebius /* 1121149820Sglebius * Don't trust the various socket layers to get the 1122149820Sglebius * packet header and length correct (e.g. kern/15175). 1123149820Sglebius * 1124149820Sglebius * Also, do not trust that soreceive() will clear m_nextpkt 1125149820Sglebius * for us (e.g. kern/84952, kern/82413). 1126149820Sglebius */ 1127155877Sru m->m_pkthdr.csum_flags = 0; 1128149820Sglebius for (n = m, m->m_pkthdr.len = 0; n != NULL; n = n->m_next) { 112987070Sarchie m->m_pkthdr.len += n->m_len; 1130149820Sglebius n->m_nextpkt = NULL; 1131149820Sglebius } 113287070Sarchie 1133131108Sjulian /* Put peer's socket address (if any) into a tag */ 113487070Sarchie if (sa != NULL) { 1135131108Sjulian struct sa_tag *stag; 113687070Sarchie 1137131108Sjulian stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE, 1138141743Sglebius NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) + 1139141743Sglebius sa->sa_len, M_NOWAIT); 1140131108Sjulian if (stag == NULL) { 1141184205Sdes free(sa, M_SONAME); 114287070Sarchie goto sendit; 114387070Sarchie } 1144131108Sjulian bcopy(sa, &stag->sa, sa->sa_len); 1145184205Sdes free(sa, M_SONAME); 1146141728Sglebius stag->id = NG_NODE_ID(node); 1147131108Sjulian m_tag_prepend(m, &stag->tag); 114887070Sarchie } 114987070Sarchie 1150131108Sjuliansendit: /* Forward data with optional peer sockaddr as packet tag */ 1151131108Sjulian NG_SEND_DATA_ONLY(error, priv->hook, m); 115287070Sarchie } 115387070Sarchie 115483186Sjulian /* 115583186Sjulian * If the peer has closed the connection, forward a 0-length mbuf 115683186Sjulian * to indicate end-of-file. 115783186Sjulian */ 1158130480Srwatson if (so->so_rcv.sb_state & SBS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) { 1159176917Smav MGETHDR(m, M_NOWAIT, MT_DATA); 116083186Sjulian if (m != NULL) { 116183186Sjulian m->m_len = m->m_pkthdr.len = 0; 116283186Sjulian NG_SEND_DATA_ONLY(error, priv->hook, m); 116383186Sjulian } 116483186Sjulian priv->flags |= KSF_EOFSEEN; 116597658Stanimura } 116653404Sarchie splx(s); 116753246Sarchie} 116853246Sarchie 116953246Sarchie/* 117083186Sjulian * Check for a completed incoming connection and return 0 if one is found. 117183186Sjulian * Otherwise return the appropriate error code. 117283186Sjulian */ 117383186Sjulianstatic int 117483186Sjulianng_ksocket_check_accept(priv_p priv) 117583186Sjulian{ 117683186Sjulian struct socket *const head = priv->so; 117783186Sjulian int error; 117883186Sjulian 117983186Sjulian if ((error = head->so_error) != 0) { 118083186Sjulian head->so_error = 0; 118183186Sjulian return error; 118283186Sjulian } 1183129979Srwatson /* Unlocked read. */ 118483186Sjulian if (TAILQ_EMPTY(&head->so_comp)) { 1185130480Srwatson if (head->so_rcv.sb_state & SBS_CANTRCVMORE) 118683186Sjulian return ECONNABORTED; 118783186Sjulian return EWOULDBLOCK; 118883186Sjulian } 118983186Sjulian return 0; 119083186Sjulian} 119183186Sjulian 119283186Sjulian/* 119383186Sjulian * Handle the first completed incoming connection, assumed to be already 119483186Sjulian * on the socket's so_comp queue. 119583186Sjulian */ 119683186Sjulianstatic void 119783186Sjulianng_ksocket_finish_accept(priv_p priv) 119883186Sjulian{ 119983186Sjulian struct socket *const head = priv->so; 120083186Sjulian struct socket *so; 120183186Sjulian struct sockaddr *sa = NULL; 120283186Sjulian struct ng_mesg *resp; 120383186Sjulian struct ng_ksocket_accept *resp_data; 120483186Sjulian node_p node; 120583186Sjulian priv_p priv2; 120683186Sjulian int len; 120783186Sjulian int error; 120883186Sjulian 1209129979Srwatson ACCEPT_LOCK(); 121083186Sjulian so = TAILQ_FIRST(&head->so_comp); 1211129979Srwatson if (so == NULL) { /* Should never happen */ 1212129979Srwatson ACCEPT_UNLOCK(); 121383186Sjulian return; 1214129979Srwatson } 121583186Sjulian TAILQ_REMOVE(&head->so_comp, so, so_list); 121683186Sjulian head->so_qlen--; 1217129979Srwatson so->so_qstate &= ~SQ_COMP; 1218129979Srwatson so->so_head = NULL; 1219130387Srwatson SOCK_LOCK(so); 1220129979Srwatson soref(so); 1221129979Srwatson so->so_state |= SS_NBIO; 1222130387Srwatson SOCK_UNLOCK(so); 1223129979Srwatson ACCEPT_UNLOCK(); 122483186Sjulian 1225195148Sstas /* XXX KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); */ 122683186Sjulian 122783186Sjulian soaccept(so, &sa); 122883186Sjulian 122983186Sjulian len = OFFSETOF(struct ng_ksocket_accept, addr); 123083186Sjulian if (sa != NULL) 123183186Sjulian len += sa->sa_len; 123283186Sjulian 123383186Sjulian NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len, 123483186Sjulian M_NOWAIT); 123583186Sjulian if (resp == NULL) { 123683186Sjulian soclose(so); 123783186Sjulian goto out; 123883186Sjulian } 123983186Sjulian resp->header.flags |= NGF_RESP; 124083186Sjulian resp->header.token = priv->response_token; 124183186Sjulian 124283186Sjulian /* Clone a ksocket node to wrap the new socket */ 124383186Sjulian error = ng_make_node_common(&ng_ksocket_typestruct, &node); 124483186Sjulian if (error) { 1245184205Sdes free(resp, M_NETGRAPH); 124683186Sjulian soclose(so); 124783186Sjulian goto out; 124883186Sjulian } 124983186Sjulian 125083186Sjulian if (ng_ksocket_constructor(node) != 0) { 125183186Sjulian NG_NODE_UNREF(node); 1252184205Sdes free(resp, M_NETGRAPH); 125383186Sjulian soclose(so); 125483186Sjulian goto out; 125583186Sjulian } 125683186Sjulian 125783186Sjulian priv2 = NG_NODE_PRIVATE(node); 125883186Sjulian priv2->so = so; 125983186Sjulian priv2->flags |= KSF_CLONED | KSF_EMBRYONIC; 126083186Sjulian 126183186Sjulian /* 126283186Sjulian * Insert the cloned node into a list of embryonic children 126383186Sjulian * on the parent node. When a hook is created on the cloned 126483186Sjulian * node it will be removed from this list. When the parent 126583186Sjulian * is destroyed it will destroy any embryonic children it has. 126683186Sjulian */ 126783186Sjulian LIST_INSERT_HEAD(&priv->embryos, priv2, siblings); 126883186Sjulian 1269130653Srwatson SOCKBUF_LOCK(&so->so_rcv); 1270193272Sjhb soupcall_set(so, SO_RCV, ng_ksocket_incoming, node); 1271130653Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 1272130653Srwatson SOCKBUF_LOCK(&so->so_snd); 1273207732Sfabient soupcall_set(so, SO_SND, ng_ksocket_incoming, node); 1274130653Srwatson SOCKBUF_UNLOCK(&so->so_snd); 127583186Sjulian 127683186Sjulian /* Fill in the response data and send it or return it to the caller */ 127783186Sjulian resp_data = (struct ng_ksocket_accept *)resp->data; 127883186Sjulian resp_data->nodeid = NG_NODE_ID(node); 127983186Sjulian if (sa != NULL) 128083186Sjulian bcopy(sa, &resp_data->addr, sa->sa_len); 1281102244Sarchie NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0); 128283186Sjulian 128383186Sjulianout: 128483186Sjulian if (sa != NULL) 1285184205Sdes free(sa, M_SONAME); 128683186Sjulian} 128783186Sjulian 128883186Sjulian/* 128953246Sarchie * Parse out either an integer value or an alias. 129053246Sarchie */ 129153246Sarchiestatic int 129253246Sarchieng_ksocket_parse(const struct ng_ksocket_alias *aliases, 129353246Sarchie const char *s, int family) 129453246Sarchie{ 129553246Sarchie int k, val; 129653648Sarchie char *eptr; 129753246Sarchie 129853246Sarchie /* Try aliases */ 129953246Sarchie for (k = 0; aliases[k].name != NULL; k++) { 130053246Sarchie if (strcmp(s, aliases[k].name) == 0 130153246Sarchie && aliases[k].family == family) 130253246Sarchie return aliases[k].value; 130353246Sarchie } 130453246Sarchie 130553246Sarchie /* Try parsing as a number */ 130653246Sarchie val = (int)strtoul(s, &eptr, 10); 130753913Sarchie if (val < 0 || *eptr != '\0') 130853246Sarchie return (-1); 130953246Sarchie return (val); 131053246Sarchie} 131153246Sarchie 1312