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> 69260226Sglebius#include <netinet/ip.h> 7053246Sarchie#include <netatalk/at.h> 7153246Sarchie 7270870Sjulian#ifdef NG_SEPARATE_MALLOC 73227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_KSOCKET, "netgraph_ksock", 74227293Sed "netgraph ksock node"); 7570870Sjulian#else 7670870Sjulian#define M_NETGRAPH_KSOCKET M_NETGRAPH 7770870Sjulian#endif 7870870Sjulian 7953913Sarchie#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) 8053913Sarchie#define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data)) 8153913Sarchie 8253246Sarchie/* Node private data */ 8353404Sarchiestruct ng_ksocket_private { 8483186Sjulian node_p node; 8553246Sarchie hook_p hook; 8653246Sarchie struct socket *so; 87176917Smav int fn_sent; /* FN call on incoming event was sent */ 8883186Sjulian LIST_HEAD(, ng_ksocket_private) embryos; 8983186Sjulian LIST_ENTRY(ng_ksocket_private) siblings; 9083186Sjulian u_int32_t flags; 9183186Sjulian u_int32_t response_token; 9283186Sjulian ng_ID_t response_addr; 9353246Sarchie}; 9453404Sarchietypedef struct ng_ksocket_private *priv_p; 9553246Sarchie 9683186Sjulian/* Flags for priv_p */ 9783186Sjulian#define KSF_CONNECTING 0x00000001 /* Waiting for connection complete */ 9883186Sjulian#define KSF_ACCEPTING 0x00000002 /* Waiting for accept complete */ 9983186Sjulian#define KSF_EOFSEEN 0x00000004 /* Have sent 0-length EOF mbuf */ 10083186Sjulian#define KSF_CLONED 0x00000008 /* Cloned from an accepting socket */ 10183186Sjulian#define KSF_EMBRYONIC 0x00000010 /* Cloned node with no hooks yet */ 10283186Sjulian 10353246Sarchie/* Netgraph node methods */ 10453246Sarchiestatic ng_constructor_t ng_ksocket_constructor; 10553246Sarchiestatic ng_rcvmsg_t ng_ksocket_rcvmsg; 10670700Sjulianstatic ng_shutdown_t ng_ksocket_shutdown; 10753246Sarchiestatic ng_newhook_t ng_ksocket_newhook; 10853246Sarchiestatic ng_rcvdata_t ng_ksocket_rcvdata; 10983186Sjulianstatic ng_connect_t ng_ksocket_connect; 11053246Sarchiestatic ng_disconnect_t ng_ksocket_disconnect; 11153246Sarchie 11253246Sarchie/* Alias structure */ 11353246Sarchiestruct ng_ksocket_alias { 11453246Sarchie const char *name; 11553246Sarchie const int value; 11653246Sarchie const int family; 11753246Sarchie}; 11853246Sarchie 11953246Sarchie/* Protocol family aliases */ 12053246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_families[] = { 12153246Sarchie { "local", PF_LOCAL }, 12253246Sarchie { "inet", PF_INET }, 12353246Sarchie { "inet6", PF_INET6 }, 12453246Sarchie { "atalk", PF_APPLETALK }, 12553246Sarchie { "ipx", PF_IPX }, 12653246Sarchie { "atm", PF_ATM }, 12753246Sarchie { NULL, -1 }, 12853246Sarchie}; 12953246Sarchie 13053246Sarchie/* Socket type aliases */ 13153246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_types[] = { 13253246Sarchie { "stream", SOCK_STREAM }, 13353246Sarchie { "dgram", SOCK_DGRAM }, 13453246Sarchie { "raw", SOCK_RAW }, 13553246Sarchie { "rdm", SOCK_RDM }, 13653246Sarchie { "seqpacket", SOCK_SEQPACKET }, 13753246Sarchie { NULL, -1 }, 13853246Sarchie}; 13953246Sarchie 14053246Sarchie/* Protocol aliases */ 14153246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_protos[] = { 14253246Sarchie { "ip", IPPROTO_IP, PF_INET }, 14384776Sarchie { "raw", IPPROTO_RAW, PF_INET }, 14453246Sarchie { "icmp", IPPROTO_ICMP, PF_INET }, 14553246Sarchie { "igmp", IPPROTO_IGMP, PF_INET }, 14653246Sarchie { "tcp", IPPROTO_TCP, PF_INET }, 14753246Sarchie { "udp", IPPROTO_UDP, PF_INET }, 14853246Sarchie { "gre", IPPROTO_GRE, PF_INET }, 14953246Sarchie { "esp", IPPROTO_ESP, PF_INET }, 15053246Sarchie { "ah", IPPROTO_AH, PF_INET }, 15153246Sarchie { "swipe", IPPROTO_SWIPE, PF_INET }, 15253246Sarchie { "encap", IPPROTO_ENCAP, PF_INET }, 15353246Sarchie { "divert", IPPROTO_DIVERT, PF_INET }, 154119187Shsu { "pim", IPPROTO_PIM, PF_INET }, 15553246Sarchie { "ddp", ATPROTO_DDP, PF_APPLETALK }, 15653246Sarchie { "aarp", ATPROTO_AARP, PF_APPLETALK }, 15753246Sarchie { NULL, -1 }, 15853246Sarchie}; 15953246Sarchie 16053913Sarchie/* Helper functions */ 16183186Sjulianstatic int ng_ksocket_check_accept(priv_p); 16283186Sjulianstatic void ng_ksocket_finish_accept(priv_p); 163193272Sjhbstatic int ng_ksocket_incoming(struct socket *so, void *arg, int waitflag); 16453913Sarchiestatic int ng_ksocket_parse(const struct ng_ksocket_alias *aliases, 16553913Sarchie const char *s, int family); 16683186Sjulianstatic void ng_ksocket_incoming2(node_p node, hook_p hook, 167176917Smav void *arg1, int arg2); 16853913Sarchie 16953913Sarchie/************************************************************************ 17053913Sarchie STRUCT SOCKADDR PARSE TYPE 17153913Sarchie ************************************************************************/ 17253913Sarchie 17353913Sarchie/* Get the length of the data portion of a generic struct sockaddr */ 17453913Sarchiestatic int 17553913Sarchieng_parse_generic_sockdata_getLength(const struct ng_parse_type *type, 17653913Sarchie const u_char *start, const u_char *buf) 17753913Sarchie{ 17853913Sarchie const struct sockaddr *sa; 17953913Sarchie 18053913Sarchie sa = (const struct sockaddr *)(buf - SADATA_OFFSET); 18164470Sarchie return (sa->sa_len < SADATA_OFFSET) ? 0 : sa->sa_len - SADATA_OFFSET; 18253913Sarchie} 18353913Sarchie 18453913Sarchie/* Type for the variable length data portion of a generic struct sockaddr */ 18553913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockdata_type = { 18653913Sarchie &ng_parse_bytearray_type, 18753913Sarchie &ng_parse_generic_sockdata_getLength 18853913Sarchie}; 18953913Sarchie 19053913Sarchie/* Type for a generic struct sockaddr */ 19197685Sarchiestatic const struct ng_parse_struct_field 19297685Sarchie ng_parse_generic_sockaddr_type_fields[] = { 19364508Sarchie { "len", &ng_parse_uint8_type }, 19464508Sarchie { "family", &ng_parse_uint8_type }, 19553913Sarchie { "data", &ng_ksocket_generic_sockdata_type }, 19653913Sarchie { NULL } 19753913Sarchie}; 19853913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockaddr_type = { 19953913Sarchie &ng_parse_struct_type, 20097685Sarchie &ng_parse_generic_sockaddr_type_fields 20153913Sarchie}; 20253913Sarchie 20353913Sarchie/* Convert a struct sockaddr from ASCII to binary. If its a protocol 20453913Sarchie family that we specially handle, do that, otherwise defer to the 20553913Sarchie generic parse type ng_ksocket_generic_sockaddr_type. */ 20653913Sarchiestatic int 20753913Sarchieng_ksocket_sockaddr_parse(const struct ng_parse_type *type, 20853913Sarchie const char *s, int *off, const u_char *const start, 20953913Sarchie u_char *const buf, int *buflen) 21053913Sarchie{ 21153913Sarchie struct sockaddr *const sa = (struct sockaddr *)buf; 21253913Sarchie enum ng_parse_token tok; 21353913Sarchie char fambuf[32]; 21453913Sarchie int family, len; 21553913Sarchie char *t; 21653913Sarchie 21753913Sarchie /* If next token is a left curly brace, use generic parse type */ 21853913Sarchie if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) { 21953913Sarchie return (*ng_ksocket_generic_sockaddr_type.supertype->parse) 22053913Sarchie (&ng_ksocket_generic_sockaddr_type, 22153913Sarchie s, off, start, buf, buflen); 22253913Sarchie } 22353913Sarchie 22453913Sarchie /* Get socket address family followed by a slash */ 22553913Sarchie while (isspace(s[*off])) 22653913Sarchie (*off)++; 227229272Sed if ((t = strchr(s + *off, '/')) == NULL) 22853913Sarchie return (EINVAL); 22953913Sarchie if ((len = t - (s + *off)) > sizeof(fambuf) - 1) 23053913Sarchie return (EINVAL); 23153913Sarchie strncpy(fambuf, s + *off, len); 23253913Sarchie fambuf[len] = '\0'; 23353913Sarchie *off += len + 1; 23453913Sarchie if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1) 23553913Sarchie return (EINVAL); 23653913Sarchie 23753913Sarchie /* Set family */ 23853913Sarchie if (*buflen < SADATA_OFFSET) 23953913Sarchie return (ERANGE); 24053913Sarchie sa->sa_family = family; 24153913Sarchie 24253913Sarchie /* Set family-specific data and length */ 24353913Sarchie switch (sa->sa_family) { 24453913Sarchie case PF_LOCAL: /* Get pathname */ 24553913Sarchie { 24653913Sarchie const int pathoff = OFFSETOF(struct sockaddr_un, sun_path); 24753913Sarchie struct sockaddr_un *const sun = (struct sockaddr_un *)sa; 24853913Sarchie int toklen, pathlen; 24953913Sarchie char *path; 25053913Sarchie 25168845Sbrian if ((path = ng_get_string_token(s, off, &toklen, NULL)) == NULL) 25253913Sarchie return (EINVAL); 25353913Sarchie pathlen = strlen(path); 25453913Sarchie if (pathlen > SOCK_MAXADDRLEN) { 255184205Sdes free(path, M_NETGRAPH_KSOCKET); 25653913Sarchie return (E2BIG); 25753913Sarchie } 25853913Sarchie if (*buflen < pathoff + pathlen) { 259184205Sdes free(path, M_NETGRAPH_KSOCKET); 26053913Sarchie return (ERANGE); 26153913Sarchie } 26253913Sarchie *off += toklen; 26353913Sarchie bcopy(path, sun->sun_path, pathlen); 26453913Sarchie sun->sun_len = pathoff + pathlen; 265184205Sdes free(path, M_NETGRAPH_KSOCKET); 26653913Sarchie break; 26753913Sarchie } 26853913Sarchie 26953913Sarchie case PF_INET: /* Get an IP address with optional port */ 27053913Sarchie { 27153913Sarchie struct sockaddr_in *const sin = (struct sockaddr_in *)sa; 27253913Sarchie int i; 27353913Sarchie 27453913Sarchie /* Parse this: <ipaddress>[:port] */ 27553913Sarchie for (i = 0; i < 4; i++) { 27653913Sarchie u_long val; 27753913Sarchie char *eptr; 27853913Sarchie 27953913Sarchie val = strtoul(s + *off, &eptr, 10); 28053913Sarchie if (val > 0xff || eptr == s + *off) 28153913Sarchie return (EINVAL); 28253913Sarchie *off += (eptr - (s + *off)); 28353913Sarchie ((u_char *)&sin->sin_addr)[i] = (u_char)val; 28453913Sarchie if (i < 3) { 28553913Sarchie if (s[*off] != '.') 28653913Sarchie return (EINVAL); 28753913Sarchie (*off)++; 28853913Sarchie } else if (s[*off] == ':') { 28953913Sarchie (*off)++; 29053913Sarchie val = strtoul(s + *off, &eptr, 10); 29153913Sarchie if (val > 0xffff || eptr == s + *off) 29253913Sarchie return (EINVAL); 29353913Sarchie *off += (eptr - (s + *off)); 29453913Sarchie sin->sin_port = htons(val); 29553913Sarchie } else 29653913Sarchie sin->sin_port = 0; 29753913Sarchie } 29853913Sarchie bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 29953913Sarchie sin->sin_len = sizeof(*sin); 30053913Sarchie break; 30153913Sarchie } 30253913Sarchie 30353913Sarchie#if 0 30453913Sarchie case PF_APPLETALK: /* XXX implement these someday */ 30553913Sarchie case PF_INET6: 30653913Sarchie case PF_IPX: 30753913Sarchie#endif 30853913Sarchie 30953913Sarchie default: 31053913Sarchie return (EINVAL); 31153913Sarchie } 31253913Sarchie 31353913Sarchie /* Done */ 31453913Sarchie *buflen = sa->sa_len; 31553913Sarchie return (0); 31653913Sarchie} 31753913Sarchie 31853913Sarchie/* Convert a struct sockaddr from binary to ASCII */ 31953913Sarchiestatic int 32053913Sarchieng_ksocket_sockaddr_unparse(const struct ng_parse_type *type, 32153913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 32253913Sarchie{ 32353913Sarchie const struct sockaddr *sa = (const struct sockaddr *)(data + *off); 32453913Sarchie int slen = 0; 32553913Sarchie 32653913Sarchie /* Output socket address, either in special or generic format */ 32753913Sarchie switch (sa->sa_family) { 32853913Sarchie case PF_LOCAL: 32953913Sarchie { 33053913Sarchie const int pathoff = OFFSETOF(struct sockaddr_un, sun_path); 33153913Sarchie const struct sockaddr_un *sun = (const struct sockaddr_un *)sa; 33253913Sarchie const int pathlen = sun->sun_len - pathoff; 33353913Sarchie char pathbuf[SOCK_MAXADDRLEN + 1]; 33453913Sarchie char *pathtoken; 33553913Sarchie 33653913Sarchie bcopy(sun->sun_path, pathbuf, pathlen); 33768845Sbrian if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL) 33853913Sarchie return (ENOMEM); 33953913Sarchie slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken); 340184205Sdes free(pathtoken, M_NETGRAPH_KSOCKET); 34153913Sarchie if (slen >= cbuflen) 34253913Sarchie return (ERANGE); 34353913Sarchie *off += sun->sun_len; 34453913Sarchie return (0); 34553913Sarchie } 34653913Sarchie 34753913Sarchie case PF_INET: 34853913Sarchie { 34953913Sarchie const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 35053913Sarchie 35153913Sarchie slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d", 35253913Sarchie ((const u_char *)&sin->sin_addr)[0], 35353913Sarchie ((const u_char *)&sin->sin_addr)[1], 35453913Sarchie ((const u_char *)&sin->sin_addr)[2], 35553913Sarchie ((const u_char *)&sin->sin_addr)[3]); 35653913Sarchie if (sin->sin_port != 0) { 35753913Sarchie slen += snprintf(cbuf + strlen(cbuf), 35853913Sarchie cbuflen - strlen(cbuf), ":%d", 35953913Sarchie (u_int)ntohs(sin->sin_port)); 36053913Sarchie } 36153913Sarchie if (slen >= cbuflen) 36253913Sarchie return (ERANGE); 36353913Sarchie *off += sizeof(*sin); 36453913Sarchie return(0); 36553913Sarchie } 36653913Sarchie 36753913Sarchie#if 0 36853913Sarchie case PF_APPLETALK: /* XXX implement these someday */ 36953913Sarchie case PF_INET6: 37053913Sarchie case PF_IPX: 37153913Sarchie#endif 37253913Sarchie 37353913Sarchie default: 37453913Sarchie return (*ng_ksocket_generic_sockaddr_type.supertype->unparse) 37553913Sarchie (&ng_ksocket_generic_sockaddr_type, 37653913Sarchie data, off, cbuf, cbuflen); 37753913Sarchie } 37853913Sarchie} 37953913Sarchie 38053913Sarchie/* Parse type for struct sockaddr */ 38153913Sarchiestatic const struct ng_parse_type ng_ksocket_sockaddr_type = { 38253913Sarchie NULL, 38353913Sarchie NULL, 38453913Sarchie NULL, 38553913Sarchie &ng_ksocket_sockaddr_parse, 38653913Sarchie &ng_ksocket_sockaddr_unparse, 38753913Sarchie NULL /* no such thing as a default struct sockaddr */ 38853913Sarchie}; 38953913Sarchie 39053913Sarchie/************************************************************************ 39153913Sarchie STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE 39253913Sarchie ************************************************************************/ 39353913Sarchie 39453913Sarchie/* Get length of the struct ng_ksocket_sockopt value field, which is the 39553913Sarchie just the excess of the message argument portion over the length of 39653913Sarchie the struct ng_ksocket_sockopt. */ 39753913Sarchiestatic int 39853913Sarchieng_parse_sockoptval_getLength(const struct ng_parse_type *type, 39953913Sarchie const u_char *start, const u_char *buf) 40053913Sarchie{ 40153913Sarchie static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value); 40253913Sarchie const struct ng_ksocket_sockopt *sopt; 40353913Sarchie const struct ng_mesg *msg; 40453913Sarchie 40553913Sarchie sopt = (const struct ng_ksocket_sockopt *)(buf - offset); 40653913Sarchie msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg)); 40753913Sarchie return msg->header.arglen - sizeof(*sopt); 40853913Sarchie} 40953913Sarchie 41053913Sarchie/* Parse type for the option value part of a struct ng_ksocket_sockopt 41153913Sarchie XXX Eventually, we should handle the different socket options specially. 41253913Sarchie XXX This would avoid byte order problems, eg an integer value of 1 is 41353913Sarchie XXX going to be "[1]" for little endian or "[3=1]" for big endian. */ 41453913Sarchiestatic const struct ng_parse_type ng_ksocket_sockoptval_type = { 41553913Sarchie &ng_parse_bytearray_type, 41653913Sarchie &ng_parse_sockoptval_getLength 41753913Sarchie}; 41853913Sarchie 41953913Sarchie/* Parse type for struct ng_ksocket_sockopt */ 42097685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_sockopt_type_fields[] 42153913Sarchie = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type); 42253913Sarchiestatic const struct ng_parse_type ng_ksocket_sockopt_type = { 42353913Sarchie &ng_parse_struct_type, 42497685Sarchie &ng_ksocket_sockopt_type_fields 42553913Sarchie}; 42653913Sarchie 42783186Sjulian/* Parse type for struct ng_ksocket_accept */ 42897685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_accept_type_fields[] 42983186Sjulian = NGM_KSOCKET_ACCEPT_INFO; 43083186Sjulianstatic const struct ng_parse_type ng_ksocket_accept_type = { 43183186Sjulian &ng_parse_struct_type, 43297685Sarchie &ng_ksocket_accept_type_fields 43383186Sjulian}; 43483186Sjulian 43553913Sarchie/* List of commands and how to convert arguments to/from ASCII */ 43653913Sarchiestatic const struct ng_cmdlist ng_ksocket_cmds[] = { 43753913Sarchie { 43853913Sarchie NGM_KSOCKET_COOKIE, 43953913Sarchie NGM_KSOCKET_BIND, 44053913Sarchie "bind", 44153913Sarchie &ng_ksocket_sockaddr_type, 44253913Sarchie NULL 44353913Sarchie }, 44453913Sarchie { 44553913Sarchie NGM_KSOCKET_COOKIE, 44653913Sarchie NGM_KSOCKET_LISTEN, 44753913Sarchie "listen", 44853913Sarchie &ng_parse_int32_type, 44953913Sarchie NULL 45053913Sarchie }, 45153913Sarchie { 45253913Sarchie NGM_KSOCKET_COOKIE, 45353913Sarchie NGM_KSOCKET_ACCEPT, 45453913Sarchie "accept", 45553913Sarchie NULL, 45683186Sjulian &ng_ksocket_accept_type 45753913Sarchie }, 45853913Sarchie { 45953913Sarchie NGM_KSOCKET_COOKIE, 46053913Sarchie NGM_KSOCKET_CONNECT, 46153913Sarchie "connect", 46253913Sarchie &ng_ksocket_sockaddr_type, 46383186Sjulian &ng_parse_int32_type 46453913Sarchie }, 46553913Sarchie { 46653913Sarchie NGM_KSOCKET_COOKIE, 46753913Sarchie NGM_KSOCKET_GETNAME, 46853913Sarchie "getname", 46953913Sarchie NULL, 47053913Sarchie &ng_ksocket_sockaddr_type 47153913Sarchie }, 47253913Sarchie { 47353913Sarchie NGM_KSOCKET_COOKIE, 47453913Sarchie NGM_KSOCKET_GETPEERNAME, 47553913Sarchie "getpeername", 47653913Sarchie NULL, 47753913Sarchie &ng_ksocket_sockaddr_type 47853913Sarchie }, 47953913Sarchie { 48053913Sarchie NGM_KSOCKET_COOKIE, 48153913Sarchie NGM_KSOCKET_SETOPT, 48253913Sarchie "setopt", 48353913Sarchie &ng_ksocket_sockopt_type, 48453913Sarchie NULL 48553913Sarchie }, 48653913Sarchie { 48753913Sarchie NGM_KSOCKET_COOKIE, 48853913Sarchie NGM_KSOCKET_GETOPT, 48953913Sarchie "getopt", 49053913Sarchie &ng_ksocket_sockopt_type, 49153913Sarchie &ng_ksocket_sockopt_type 49253913Sarchie }, 49353913Sarchie { 0 } 49453913Sarchie}; 49553913Sarchie 49653913Sarchie/* Node type descriptor */ 49753913Sarchiestatic struct ng_type ng_ksocket_typestruct = { 498129823Sjulian .version = NG_ABI_VERSION, 499129823Sjulian .name = NG_KSOCKET_NODE_TYPE, 500129823Sjulian .constructor = ng_ksocket_constructor, 501129823Sjulian .rcvmsg = ng_ksocket_rcvmsg, 502129823Sjulian .shutdown = ng_ksocket_shutdown, 503129823Sjulian .newhook = ng_ksocket_newhook, 504129823Sjulian .connect = ng_ksocket_connect, 505129823Sjulian .rcvdata = ng_ksocket_rcvdata, 506129823Sjulian .disconnect = ng_ksocket_disconnect, 507129823Sjulian .cmdlist = ng_ksocket_cmds, 50853913Sarchie}; 50953913SarchieNETGRAPH_INIT(ksocket, &ng_ksocket_typestruct); 51053913Sarchie 51197658Stanimura#define ERROUT(x) do { error = (x); goto done; } while (0) 51253246Sarchie 51353246Sarchie/************************************************************************ 51453246Sarchie NETGRAPH NODE STUFF 51553246Sarchie ************************************************************************/ 51653246Sarchie 51753246Sarchie/* 51853246Sarchie * Node type constructor 51983186Sjulian * The NODE part is assumed to be all set up. 52083186Sjulian * There is already a reference to the node for us. 52153246Sarchie */ 52253246Sarchiestatic int 52370700Sjulianng_ksocket_constructor(node_p node) 52453246Sarchie{ 52553246Sarchie priv_p priv; 52653246Sarchie 52753246Sarchie /* Allocate private structure */ 528235923Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_KSOCKET, M_NOWAIT | M_ZERO); 529235923Sglebius if (priv == NULL) 530235923Sglebius 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{ 552134651Srwatson struct thread *td = curthread; /* XXX broken */ 55370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 554125028Sharti char *s1, *s2, name[NG_HOOKSIZ]; 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; 571229272Sed if ((s2 = strchr(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; 578229272Sed if ((s2 = strchr(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; 601145229Sglebius 602145229Sglebius /* 603145229Sglebius * In case of misconfigured routing a packet may reenter 604145229Sglebius * ksocket node recursively. Decouple stack to avoid possible 605145229Sglebius * panics about sleeping with locks held. 606145229Sglebius */ 607145229Sglebius NG_HOOK_FORCE_QUEUE(hook); 608145229Sglebius 60983186Sjulian return(0); 61083186Sjulian} 61183186Sjulian 61283186Sjulianstatic int 61383186Sjulianng_ksocket_connect(hook_p hook) 61483186Sjulian{ 61583186Sjulian node_p node = NG_HOOK_NODE(hook); 61683186Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 61783186Sjulian struct socket *const so = priv->so; 61883186Sjulian 61983186Sjulian /* Add our hook for incoming data and other events */ 620130653Srwatson SOCKBUF_LOCK(&priv->so->so_rcv); 621193272Sjhb soupcall_set(priv->so, SO_RCV, ng_ksocket_incoming, node); 622130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_rcv); 623130653Srwatson SOCKBUF_LOCK(&priv->so->so_snd); 624193272Sjhb soupcall_set(priv->so, SO_SND, ng_ksocket_incoming, node); 625130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_snd); 626130653Srwatson SOCK_LOCK(priv->so); 62783186Sjulian priv->so->so_state |= SS_NBIO; 628130653Srwatson SOCK_UNLOCK(priv->so); 62983186Sjulian /* 63083186Sjulian * --Original comment-- 63183186Sjulian * On a cloned socket we may have already received one or more 63283186Sjulian * upcalls which we couldn't handle without a hook. Handle 63383186Sjulian * those now. 63483186Sjulian * We cannot call the upcall function directly 63583186Sjulian * from here, because until this function has returned our 63683186Sjulian * hook isn't connected. 63783186Sjulian * 63883186Sjulian * ---meta comment for -current --- 63983186Sjulian * XXX This is dubius. 64083186Sjulian * Upcalls between the time that the hook was 64183186Sjulian * first created and now (on another processesor) will 64283186Sjulian * be earlier on the queue than the request to finalise the hook. 64383186Sjulian * By the time the hook is finalised, 64483186Sjulian * The queued upcalls will have happenned and the code 64583186Sjulian * will have discarded them because of a lack of a hook. 64683186Sjulian * (socket not open). 64783186Sjulian * 64883186Sjulian * This is a bad byproduct of the complicated way in which hooks 64983186Sjulian * are now created (3 daisy chained async events). 65083186Sjulian * 651248883Sglebius * Since we are a netgraph operation 65283186Sjulian * We know that we hold a lock on this node. This forces the 65383186Sjulian * request we make below to be queued rather than implemented 65483186Sjulian * immediatly which will cause the upcall function to be called a bit 65583186Sjulian * later. 65683186Sjulian * However, as we will run any waiting queued operations immediatly 65783186Sjulian * after doing this one, if we have not finalised the other end 65883186Sjulian * of the hook, those queued operations will fail. 65983186Sjulian */ 66083186Sjulian if (priv->flags & KSF_CLONED) { 66183186Sjulian ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_NOWAIT); 66283186Sjulian } 66353246Sarchie 66453246Sarchie return (0); 66553246Sarchie} 66653246Sarchie 66753246Sarchie/* 66853246Sarchie * Receive a control message 66953246Sarchie */ 67053246Sarchiestatic int 67170700Sjulianng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) 67253246Sarchie{ 673134651Srwatson struct thread *td = curthread; /* XXX broken */ 67470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 67553913Sarchie struct socket *const so = priv->so; 67653246Sarchie struct ng_mesg *resp = NULL; 67753246Sarchie int error = 0; 67870700Sjulian struct ng_mesg *msg; 67983186Sjulian ng_ID_t raddr; 68053246Sarchie 68170700Sjulian NGI_GET_MSG(item, msg); 68253246Sarchie switch (msg->header.typecookie) { 68353246Sarchie case NGM_KSOCKET_COOKIE: 68453246Sarchie switch (msg->header.cmd) { 68553246Sarchie case NGM_KSOCKET_BIND: 68653246Sarchie { 68753913Sarchie struct sockaddr *const sa 68853913Sarchie = (struct sockaddr *)msg->data; 68953246Sarchie 69053913Sarchie /* Sanity check */ 69153913Sarchie if (msg->header.arglen < SADATA_OFFSET 69253913Sarchie || msg->header.arglen < sa->sa_len) 69353913Sarchie ERROUT(EINVAL); 69453913Sarchie if (so == NULL) 69553913Sarchie ERROUT(ENXIO); 69653246Sarchie 69753913Sarchie /* Bind */ 69883366Sjulian error = sobind(so, sa, td); 69953246Sarchie break; 70053246Sarchie } 70153246Sarchie case NGM_KSOCKET_LISTEN: 70253246Sarchie { 70353913Sarchie /* Sanity check */ 70483186Sjulian if (msg->header.arglen != sizeof(int32_t)) 70553246Sarchie ERROUT(EINVAL); 70653913Sarchie if (so == NULL) 70753913Sarchie ERROUT(ENXIO); 70853246Sarchie 70953913Sarchie /* Listen */ 71083366Sjulian error = solisten(so, *((int32_t *)msg->data), td); 71153246Sarchie break; 71253246Sarchie } 71353246Sarchie 71453246Sarchie case NGM_KSOCKET_ACCEPT: 71553246Sarchie { 71653913Sarchie /* Sanity check */ 71753913Sarchie if (msg->header.arglen != 0) 71853913Sarchie ERROUT(EINVAL); 71953913Sarchie if (so == NULL) 72053913Sarchie ERROUT(ENXIO); 72153913Sarchie 72283186Sjulian /* Make sure the socket is capable of accepting */ 72383186Sjulian if (!(so->so_options & SO_ACCEPTCONN)) 72497658Stanimura ERROUT(EINVAL); 72583186Sjulian if (priv->flags & KSF_ACCEPTING) 72683186Sjulian ERROUT(EALREADY); 72753913Sarchie 72883186Sjulian error = ng_ksocket_check_accept(priv); 72983186Sjulian if (error != 0 && error != EWOULDBLOCK) 73083186Sjulian ERROUT(error); 73183186Sjulian 73283186Sjulian /* 73383186Sjulian * If a connection is already complete, take it. 73483186Sjulian * Otherwise let the upcall function deal with 73583186Sjulian * the connection when it comes in. 73683186Sjulian */ 73783186Sjulian priv->response_token = msg->header.token; 738103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 73983186Sjulian if (error == 0) { 74083186Sjulian ng_ksocket_finish_accept(priv); 74183186Sjulian } else 74283186Sjulian priv->flags |= KSF_ACCEPTING; 74353246Sarchie break; 74453246Sarchie } 74553246Sarchie 74653246Sarchie case NGM_KSOCKET_CONNECT: 74753246Sarchie { 74853913Sarchie struct sockaddr *const sa 74953913Sarchie = (struct sockaddr *)msg->data; 75053246Sarchie 75153913Sarchie /* Sanity check */ 75253913Sarchie if (msg->header.arglen < SADATA_OFFSET 75353913Sarchie || msg->header.arglen < sa->sa_len) 75453913Sarchie ERROUT(EINVAL); 75553913Sarchie if (so == NULL) 75653913Sarchie ERROUT(ENXIO); 75753246Sarchie 75853246Sarchie /* Do connect */ 75953246Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) 76097658Stanimura ERROUT(EALREADY); 76183366Sjulian if ((error = soconnect(so, sa, td)) != 0) { 76253246Sarchie so->so_state &= ~SS_ISCONNECTING; 76397658Stanimura ERROUT(error); 76453246Sarchie } 765114178Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) { 76683186Sjulian /* We will notify the sender when we connect */ 76783186Sjulian priv->response_token = msg->header.token; 768103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 76983186Sjulian priv->flags |= KSF_CONNECTING; 77097658Stanimura ERROUT(EINPROGRESS); 771114178Sarchie } 77253246Sarchie break; 77353246Sarchie } 77453246Sarchie 77553246Sarchie case NGM_KSOCKET_GETNAME: 77653913Sarchie case NGM_KSOCKET_GETPEERNAME: 77753246Sarchie { 77853913Sarchie int (*func)(struct socket *so, struct sockaddr **nam); 77953913Sarchie struct sockaddr *sa = NULL; 78053913Sarchie int len; 78153246Sarchie 78253913Sarchie /* Sanity check */ 78353913Sarchie if (msg->header.arglen != 0) 78453913Sarchie ERROUT(EINVAL); 78553913Sarchie if (so == NULL) 78653913Sarchie ERROUT(ENXIO); 78753913Sarchie 78853913Sarchie /* Get function */ 78953913Sarchie if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) { 79053913Sarchie if ((so->so_state 791248883Sglebius & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) 79297658Stanimura ERROUT(ENOTCONN); 79353913Sarchie func = so->so_proto->pr_usrreqs->pru_peeraddr; 79453913Sarchie } else 79553913Sarchie func = so->so_proto->pr_usrreqs->pru_sockaddr; 79653913Sarchie 79753913Sarchie /* Get local or peer address */ 79853913Sarchie if ((error = (*func)(so, &sa)) != 0) 79953913Sarchie goto bail; 80053913Sarchie len = (sa == NULL) ? 0 : sa->sa_len; 80153913Sarchie 80253913Sarchie /* Send it back in a response */ 80353913Sarchie NG_MKRESPONSE(resp, msg, len, M_NOWAIT); 80453913Sarchie if (resp == NULL) { 80553913Sarchie error = ENOMEM; 80653913Sarchie goto bail; 80753913Sarchie } 80853913Sarchie bcopy(sa, resp->data, len); 80953913Sarchie 81053913Sarchie bail: 81153913Sarchie /* Cleanup */ 81253913Sarchie if (sa != NULL) 813184205Sdes free(sa, M_SONAME); 81453246Sarchie break; 81553246Sarchie } 81653246Sarchie 81753246Sarchie case NGM_KSOCKET_GETOPT: 81853246Sarchie { 819248883Sglebius struct ng_ksocket_sockopt *ksopt = 82053913Sarchie (struct ng_ksocket_sockopt *)msg->data; 82153913Sarchie struct sockopt sopt; 82253913Sarchie 82353913Sarchie /* Sanity check */ 82453913Sarchie if (msg->header.arglen != sizeof(*ksopt)) 82553913Sarchie ERROUT(EINVAL); 82653913Sarchie if (so == NULL) 82753913Sarchie ERROUT(ENXIO); 82853913Sarchie 82953913Sarchie /* Get response with room for option value */ 83053913Sarchie NG_MKRESPONSE(resp, msg, sizeof(*ksopt) 83153913Sarchie + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT); 83253913Sarchie if (resp == NULL) 83353913Sarchie ERROUT(ENOMEM); 83453913Sarchie 83553913Sarchie /* Get socket option, and put value in the response */ 83653913Sarchie sopt.sopt_dir = SOPT_GET; 83753913Sarchie sopt.sopt_level = ksopt->level; 83853913Sarchie sopt.sopt_name = ksopt->name; 83983366Sjulian sopt.sopt_td = NULL; 84053913Sarchie sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN; 84153913Sarchie ksopt = (struct ng_ksocket_sockopt *)resp->data; 84253913Sarchie sopt.sopt_val = ksopt->value; 84353913Sarchie if ((error = sogetopt(so, &sopt)) != 0) { 84470700Sjulian NG_FREE_MSG(resp); 84553913Sarchie break; 84653913Sarchie } 84753913Sarchie 84853913Sarchie /* Set actual value length */ 84953913Sarchie resp->header.arglen = sizeof(*ksopt) 85053913Sarchie + sopt.sopt_valsize; 85153246Sarchie break; 85253246Sarchie } 85353246Sarchie 85453246Sarchie case NGM_KSOCKET_SETOPT: 85553246Sarchie { 856248883Sglebius struct ng_ksocket_sockopt *const ksopt = 85753913Sarchie (struct ng_ksocket_sockopt *)msg->data; 85853913Sarchie const int valsize = msg->header.arglen - sizeof(*ksopt); 85953913Sarchie struct sockopt sopt; 86053913Sarchie 86153913Sarchie /* Sanity check */ 86253913Sarchie if (valsize < 0) 86353913Sarchie ERROUT(EINVAL); 86453913Sarchie if (so == NULL) 86553913Sarchie ERROUT(ENXIO); 86653913Sarchie 86753913Sarchie /* Set socket option */ 86853913Sarchie sopt.sopt_dir = SOPT_SET; 86953913Sarchie sopt.sopt_level = ksopt->level; 87053913Sarchie sopt.sopt_name = ksopt->name; 87153913Sarchie sopt.sopt_val = ksopt->value; 87253913Sarchie sopt.sopt_valsize = valsize; 87383366Sjulian sopt.sopt_td = NULL; 87453913Sarchie error = sosetopt(so, &sopt); 87553246Sarchie break; 87653246Sarchie } 87753246Sarchie 87853246Sarchie default: 87953246Sarchie error = EINVAL; 88053246Sarchie break; 88153246Sarchie } 88253246Sarchie break; 88353246Sarchie default: 88453246Sarchie error = EINVAL; 88553246Sarchie break; 88653246Sarchie } 88753246Sarchiedone: 88870700Sjulian NG_RESPOND_MSG(error, node, item, resp); 88970700Sjulian NG_FREE_MSG(msg); 89053246Sarchie return (error); 89153246Sarchie} 89253246Sarchie 89353246Sarchie/* 89453246Sarchie * Receive incoming data on our hook. Send it out the socket. 89553246Sarchie */ 89653246Sarchiestatic int 89770700Sjulianng_ksocket_rcvdata(hook_p hook, item_p item) 89853246Sarchie{ 899134651Srwatson struct thread *td = curthread; /* XXX broken */ 90070784Sjulian const node_p node = NG_HOOK_NODE(hook); 90170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 90253246Sarchie struct socket *const so = priv->so; 90387070Sarchie struct sockaddr *sa = NULL; 90453246Sarchie int error; 90570700Sjulian struct mbuf *m; 906206017Smav#ifdef ALIGNED_POINTER 907206017Smav struct mbuf *n; 908206017Smav#endif /* ALIGNED_POINTER */ 909131108Sjulian struct sa_tag *stag; 91053246Sarchie 911131108Sjulian /* Extract data */ 91270700Sjulian NGI_GET_M(item, m); 91370700Sjulian NG_FREE_ITEM(item); 914206017Smav#ifdef ALIGNED_POINTER 915206017Smav if (!ALIGNED_POINTER(mtod(m, caddr_t), uint32_t)) { 916206017Smav n = m_defrag(m, M_NOWAIT); 917206017Smav if (n == NULL) { 918206017Smav m_freem(m); 919206017Smav return (ENOBUFS); 920206017Smav } 921206017Smav m = n; 922206017Smav } 923206017Smav#endif /* ALIGNED_POINTER */ 924141728Sglebius /* 925141728Sglebius * Look if socket address is stored in packet tags. 926141728Sglebius * If sockaddr is ours, or provided by a third party (zero id), 927141728Sglebius * then we accept it. 928141728Sglebius */ 929141728Sglebius if (((stag = (struct sa_tag *)m_tag_locate(m, NGM_KSOCKET_COOKIE, 930141728Sglebius NG_KSOCKET_TAG_SOCKADDR, NULL)) != NULL) && 931141728Sglebius (stag->id == NG_NODE_ID(node) || stag->id == 0)) 932131108Sjulian sa = &stag->sa; 93387070Sarchie 934166585Sbms /* Reset specific mbuf flags to prevent addressing problems. */ 935166585Sbms m->m_flags &= ~(M_BCAST|M_MCAST); 936166585Sbms 93787070Sarchie /* Send packet */ 938160619Srwatson error = sosend(so, sa, 0, m, 0, 0, td); 93987070Sarchie 94053246Sarchie return (error); 94153246Sarchie} 94253246Sarchie 94353246Sarchie/* 94453246Sarchie * Destroy node 94553246Sarchie */ 94653246Sarchiestatic int 94770700Sjulianng_ksocket_shutdown(node_p node) 94853246Sarchie{ 94970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 95083186Sjulian priv_p embryo; 95153246Sarchie 95253404Sarchie /* Close our socket (if any) */ 95353404Sarchie if (priv->so != NULL) { 954130653Srwatson SOCKBUF_LOCK(&priv->so->so_rcv); 955193272Sjhb soupcall_clear(priv->so, SO_RCV); 956130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_rcv); 957130653Srwatson SOCKBUF_LOCK(&priv->so->so_snd); 958193272Sjhb soupcall_clear(priv->so, SO_SND); 959130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_snd); 96053404Sarchie soclose(priv->so); 96153404Sarchie priv->so = NULL; 96253404Sarchie } 96353404Sarchie 96483186Sjulian /* If we are an embryo, take ourselves out of the parent's list */ 96583186Sjulian if (priv->flags & KSF_EMBRYONIC) { 96683186Sjulian LIST_REMOVE(priv, siblings); 96783186Sjulian priv->flags &= ~KSF_EMBRYONIC; 96883186Sjulian } 96983186Sjulian 97083186Sjulian /* Remove any embryonic children we have */ 97183186Sjulian while (!LIST_EMPTY(&priv->embryos)) { 97283186Sjulian embryo = LIST_FIRST(&priv->embryos); 97383186Sjulian ng_rmnode_self(embryo->node); 97483186Sjulian } 97583186Sjulian 97653246Sarchie /* Take down netgraph node */ 97753246Sarchie bzero(priv, sizeof(*priv)); 978184205Sdes free(priv, M_NETGRAPH_KSOCKET); 97970784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 98070784Sjulian NG_NODE_UNREF(node); /* let the node escape */ 98153246Sarchie return (0); 98253246Sarchie} 98353246Sarchie 98453246Sarchie/* 98553246Sarchie * Hook disconnection 98653246Sarchie */ 98753246Sarchiestatic int 98853246Sarchieng_ksocket_disconnect(hook_p hook) 98953246Sarchie{ 99070784Sjulian KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0, 99187599Sobrien ("%s: numhooks=%d?", __func__, 99272545Sarchie NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)))); 99370784Sjulian if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) 99470784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 99553246Sarchie return (0); 99653246Sarchie} 99753246Sarchie 99853246Sarchie/************************************************************************ 99953246Sarchie HELPER STUFF 100053246Sarchie ************************************************************************/ 1001248883Sglebius/* 1002176917Smav * You should not "just call" a netgraph node function from an external 1003176917Smav * asynchronous event. This is because in doing so you are ignoring the 1004176917Smav * locking on the netgraph nodes. Instead call your function via ng_send_fn(). 1005248883Sglebius * This will call the function you chose, but will first do all the 100683186Sjulian * locking rigmarole. Your function MAY only be called at some distant future 100783186Sjulian * time (several millisecs away) so don't give it any arguments 100883186Sjulian * that may be revoked soon (e.g. on your stack). 1009149820Sglebius * 1010149820Sglebius * To decouple stack, we use queue version of ng_send_fn(). 101183186Sjulian */ 101253246Sarchie 1013193272Sjhbstatic int 101483186Sjulianng_ksocket_incoming(struct socket *so, void *arg, int waitflag) 101583186Sjulian{ 101683186Sjulian const node_p node = arg; 1017176917Smav const priv_p priv = NG_NODE_PRIVATE(node); 1018176917Smav int wait = ((waitflag & M_WAITOK) ? NG_WAITOK : 0) | NG_QUEUE; 101983186Sjulian 1020176917Smav /* 1021176917Smav * Even if node is not locked, as soon as we are called, we assume 1022176917Smav * it exist and it's private area is valid. With some care we can 1023176917Smav * access it. Mark node that incoming event for it was sent to 1024176917Smav * avoid unneded queue trashing. 1025176917Smav */ 1026176917Smav if (atomic_cmpset_int(&priv->fn_sent, 0, 1) && 1027176917Smav ng_send_fn1(node, NULL, &ng_ksocket_incoming2, so, 0, wait)) { 1028176917Smav atomic_store_rel_int(&priv->fn_sent, 0); 1029176917Smav } 1030193272Sjhb return (SU_OK); 103183186Sjulian} 103283186Sjulian 103383186Sjulian 103453246Sarchie/* 103553246Sarchie * When incoming data is appended to the socket, we get notified here. 103683186Sjulian * This is also called whenever a significant event occurs for the socket. 1037248883Sglebius * Our original caller may have queued this even some time ago and 103883186Sjulian * we cannot trust that he even still exists. The node however is being 1039176917Smav * held with a reference by the queueing code and guarantied to be valid. 104053246Sarchie */ 104153246Sarchiestatic void 1042176917Smavng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2) 104353246Sarchie{ 104483186Sjulian struct socket *so = arg1; 104570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 104683186Sjulian struct ng_mesg *response; 1047260226Sglebius int error; 104853246Sarchie 104987599Sobrien KASSERT(so == priv->so, ("%s: wrong socket", __func__)); 1050248882Sglebius 1051176917Smav /* Allow next incoming event to be queued. */ 1052176917Smav atomic_store_rel_int(&priv->fn_sent, 0); 105353246Sarchie 105483186Sjulian /* Check whether a pending connect operation has completed */ 105583186Sjulian if (priv->flags & KSF_CONNECTING) { 105683186Sjulian if ((error = so->so_error) != 0) { 105783186Sjulian so->so_error = 0; 105883186Sjulian so->so_state &= ~SS_ISCONNECTING; 105983186Sjulian } 106083186Sjulian if (!(so->so_state & SS_ISCONNECTING)) { 106183186Sjulian NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE, 1062176917Smav NGM_KSOCKET_CONNECT, sizeof(int32_t), M_NOWAIT); 106383186Sjulian if (response != NULL) { 106483186Sjulian response->header.flags |= NGF_RESP; 106583186Sjulian response->header.token = priv->response_token; 106683186Sjulian *(int32_t *)response->data = error; 1067248883Sglebius /* 106883186Sjulian * send an async "response" message 106983186Sjulian * to the node that set us up 107083186Sjulian * (if it still exists) 107183186Sjulian */ 1072102244Sarchie NG_SEND_MSG_ID(error, node, 1073102244Sarchie response, priv->response_addr, 0); 107483186Sjulian } 107583186Sjulian priv->flags &= ~KSF_CONNECTING; 107697658Stanimura } 107783186Sjulian } 107883186Sjulian 107983186Sjulian /* Check whether a pending accept operation has completed */ 108083186Sjulian if (priv->flags & KSF_ACCEPTING) { 108183186Sjulian error = ng_ksocket_check_accept(priv); 108283186Sjulian if (error != EWOULDBLOCK) 108383186Sjulian priv->flags &= ~KSF_ACCEPTING; 108483186Sjulian if (error == 0) 108583186Sjulian ng_ksocket_finish_accept(priv); 108683186Sjulian } 108783186Sjulian 108883186Sjulian /* 108983186Sjulian * If we don't have a hook, we must handle data events later. When 109083186Sjulian * the hook gets created and is connected, this upcall function 109183186Sjulian * will be called again. 109283186Sjulian */ 1093241686Sandre if (priv->hook == NULL) 109483186Sjulian return; 109583186Sjulian 1096260226Sglebius /* Read and forward available mbufs. */ 109787070Sarchie while (1) { 1098260226Sglebius struct uio uio; 1099260226Sglebius struct sockaddr *sa; 1100248885Sglebius struct mbuf *m; 1101260226Sglebius int flags; 110287070Sarchie 1103260226Sglebius /* Try to get next packet from socket. */ 1104260226Sglebius uio.uio_td = NULL; 1105260226Sglebius uio.uio_resid = IP_MAXPACKET; 1106260226Sglebius flags = MSG_DONTWAIT; 1107260226Sglebius sa = NULL; 1108160619Srwatson if ((error = soreceive(so, (so->so_state & SS_ISCONNECTED) ? 1109260226Sglebius NULL : &sa, &uio, &m, NULL, &flags)) != 0) 111087070Sarchie break; 111153913Sarchie 1112260226Sglebius /* See if we got anything. */ 1113260226Sglebius if (flags & MSG_TRUNC) { 1114260226Sglebius m_freem(m); 1115260226Sglebius m = NULL; 1116260226Sglebius } 111787070Sarchie if (m == NULL) { 111887070Sarchie if (sa != NULL) 1119184205Sdes free(sa, M_SONAME); 112087070Sarchie break; 112153913Sarchie } 112283186Sjulian 1123248885Sglebius KASSERT(m->m_nextpkt == NULL, ("%s: nextpkt", __func__)); 1124248885Sglebius 1125149820Sglebius /* 1126248885Sglebius * Stream sockets do not have packet boundaries, so 1127248885Sglebius * we have to allocate a header mbuf and attach the 1128248885Sglebius * stream of data to it. 1129149820Sglebius */ 1130248885Sglebius if (so->so_type == SOCK_STREAM) { 1131248885Sglebius struct mbuf *mh; 1132248885Sglebius 1133248885Sglebius mh = m_gethdr(M_NOWAIT, MT_DATA); 1134248885Sglebius if (mh == NULL) { 1135248885Sglebius m_freem(m); 1136248885Sglebius if (sa != NULL) 1137248885Sglebius free(sa, M_SONAME); 1138248885Sglebius break; 1139248885Sglebius } 1140248885Sglebius 1141248885Sglebius mh->m_next = m; 1142248885Sglebius for (; m; m = m->m_next) 1143248885Sglebius mh->m_pkthdr.len += m->m_len; 1144248885Sglebius m = mh; 1145149820Sglebius } 114687070Sarchie 1147131108Sjulian /* Put peer's socket address (if any) into a tag */ 114887070Sarchie if (sa != NULL) { 1149131108Sjulian struct sa_tag *stag; 115087070Sarchie 1151131108Sjulian stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE, 1152141743Sglebius NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) + 1153141743Sglebius sa->sa_len, M_NOWAIT); 1154131108Sjulian if (stag == NULL) { 1155184205Sdes free(sa, M_SONAME); 115687070Sarchie goto sendit; 115787070Sarchie } 1158131108Sjulian bcopy(sa, &stag->sa, sa->sa_len); 1159184205Sdes free(sa, M_SONAME); 1160141728Sglebius stag->id = NG_NODE_ID(node); 1161131108Sjulian m_tag_prepend(m, &stag->tag); 116287070Sarchie } 116387070Sarchie 1164131108Sjuliansendit: /* Forward data with optional peer sockaddr as packet tag */ 1165131108Sjulian NG_SEND_DATA_ONLY(error, priv->hook, m); 116687070Sarchie } 116787070Sarchie 116883186Sjulian /* 116983186Sjulian * If the peer has closed the connection, forward a 0-length mbuf 117083186Sjulian * to indicate end-of-file. 117183186Sjulian */ 1172248882Sglebius if (so->so_rcv.sb_state & SBS_CANTRCVMORE && 1173248882Sglebius !(priv->flags & KSF_EOFSEEN)) { 1174248882Sglebius struct mbuf *m; 1175248882Sglebius 1176248882Sglebius m = m_gethdr(M_NOWAIT, MT_DATA); 1177248882Sglebius if (m != NULL) 117883186Sjulian NG_SEND_DATA_ONLY(error, priv->hook, m); 117983186Sjulian priv->flags |= KSF_EOFSEEN; 118097658Stanimura } 118153246Sarchie} 118253246Sarchie 118353246Sarchie/* 118483186Sjulian * Check for a completed incoming connection and return 0 if one is found. 118583186Sjulian * Otherwise return the appropriate error code. 118683186Sjulian */ 118783186Sjulianstatic int 118883186Sjulianng_ksocket_check_accept(priv_p priv) 118983186Sjulian{ 119083186Sjulian struct socket *const head = priv->so; 119183186Sjulian int error; 119283186Sjulian 119383186Sjulian if ((error = head->so_error) != 0) { 119483186Sjulian head->so_error = 0; 119583186Sjulian return error; 119683186Sjulian } 1197129979Srwatson /* Unlocked read. */ 119883186Sjulian if (TAILQ_EMPTY(&head->so_comp)) { 1199130480Srwatson if (head->so_rcv.sb_state & SBS_CANTRCVMORE) 120083186Sjulian return ECONNABORTED; 120183186Sjulian return EWOULDBLOCK; 120283186Sjulian } 120383186Sjulian return 0; 120483186Sjulian} 120583186Sjulian 120683186Sjulian/* 120783186Sjulian * Handle the first completed incoming connection, assumed to be already 120883186Sjulian * on the socket's so_comp queue. 120983186Sjulian */ 121083186Sjulianstatic void 121183186Sjulianng_ksocket_finish_accept(priv_p priv) 121283186Sjulian{ 121383186Sjulian struct socket *const head = priv->so; 121483186Sjulian struct socket *so; 121583186Sjulian struct sockaddr *sa = NULL; 121683186Sjulian struct ng_mesg *resp; 121783186Sjulian struct ng_ksocket_accept *resp_data; 121883186Sjulian node_p node; 121983186Sjulian priv_p priv2; 122083186Sjulian int len; 122183186Sjulian int error; 122283186Sjulian 1223129979Srwatson ACCEPT_LOCK(); 122483186Sjulian so = TAILQ_FIRST(&head->so_comp); 1225129979Srwatson if (so == NULL) { /* Should never happen */ 1226129979Srwatson ACCEPT_UNLOCK(); 122783186Sjulian return; 1228129979Srwatson } 122983186Sjulian TAILQ_REMOVE(&head->so_comp, so, so_list); 123083186Sjulian head->so_qlen--; 1231129979Srwatson so->so_qstate &= ~SQ_COMP; 1232129979Srwatson so->so_head = NULL; 1233130387Srwatson SOCK_LOCK(so); 1234129979Srwatson soref(so); 1235129979Srwatson so->so_state |= SS_NBIO; 1236130387Srwatson SOCK_UNLOCK(so); 1237129979Srwatson ACCEPT_UNLOCK(); 123883186Sjulian 1239195148Sstas /* XXX KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); */ 124083186Sjulian 124183186Sjulian soaccept(so, &sa); 124283186Sjulian 124383186Sjulian len = OFFSETOF(struct ng_ksocket_accept, addr); 124483186Sjulian if (sa != NULL) 124583186Sjulian len += sa->sa_len; 124683186Sjulian 124783186Sjulian NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len, 124883186Sjulian M_NOWAIT); 124983186Sjulian if (resp == NULL) { 125083186Sjulian soclose(so); 125183186Sjulian goto out; 125283186Sjulian } 125383186Sjulian resp->header.flags |= NGF_RESP; 125483186Sjulian resp->header.token = priv->response_token; 125583186Sjulian 125683186Sjulian /* Clone a ksocket node to wrap the new socket */ 1257248883Sglebius error = ng_make_node_common(&ng_ksocket_typestruct, &node); 1258248883Sglebius if (error) { 1259184205Sdes free(resp, M_NETGRAPH); 126083186Sjulian soclose(so); 126183186Sjulian goto out; 126283186Sjulian } 126383186Sjulian 126483186Sjulian if (ng_ksocket_constructor(node) != 0) { 126583186Sjulian NG_NODE_UNREF(node); 1266184205Sdes free(resp, M_NETGRAPH); 126783186Sjulian soclose(so); 126883186Sjulian goto out; 126983186Sjulian } 127083186Sjulian 127183186Sjulian priv2 = NG_NODE_PRIVATE(node); 127283186Sjulian priv2->so = so; 127383186Sjulian priv2->flags |= KSF_CLONED | KSF_EMBRYONIC; 127483186Sjulian 127583186Sjulian /* 127683186Sjulian * Insert the cloned node into a list of embryonic children 127783186Sjulian * on the parent node. When a hook is created on the cloned 127883186Sjulian * node it will be removed from this list. When the parent 127983186Sjulian * is destroyed it will destroy any embryonic children it has. 128083186Sjulian */ 128183186Sjulian LIST_INSERT_HEAD(&priv->embryos, priv2, siblings); 128283186Sjulian 1283130653Srwatson SOCKBUF_LOCK(&so->so_rcv); 1284193272Sjhb soupcall_set(so, SO_RCV, ng_ksocket_incoming, node); 1285130653Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 1286130653Srwatson SOCKBUF_LOCK(&so->so_snd); 1287207732Sfabient soupcall_set(so, SO_SND, ng_ksocket_incoming, node); 1288130653Srwatson SOCKBUF_UNLOCK(&so->so_snd); 128983186Sjulian 129083186Sjulian /* Fill in the response data and send it or return it to the caller */ 129183186Sjulian resp_data = (struct ng_ksocket_accept *)resp->data; 129283186Sjulian resp_data->nodeid = NG_NODE_ID(node); 129383186Sjulian if (sa != NULL) 129483186Sjulian bcopy(sa, &resp_data->addr, sa->sa_len); 1295102244Sarchie NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0); 129683186Sjulian 129783186Sjulianout: 129883186Sjulian if (sa != NULL) 1299184205Sdes free(sa, M_SONAME); 130083186Sjulian} 130183186Sjulian 130283186Sjulian/* 130353246Sarchie * Parse out either an integer value or an alias. 130453246Sarchie */ 130553246Sarchiestatic int 130653246Sarchieng_ksocket_parse(const struct ng_ksocket_alias *aliases, 130753246Sarchie const char *s, int family) 130853246Sarchie{ 130953246Sarchie int k, val; 131053648Sarchie char *eptr; 131153246Sarchie 131253246Sarchie /* Try aliases */ 131353246Sarchie for (k = 0; aliases[k].name != NULL; k++) { 131453246Sarchie if (strcmp(s, aliases[k].name) == 0 131553246Sarchie && aliases[k].family == family) 131653246Sarchie return aliases[k].value; 131753246Sarchie } 131853246Sarchie 131953246Sarchie /* Try parsing as a number */ 132053246Sarchie val = (int)strtoul(s, &eptr, 10); 132153913Sarchie if (val < 0 || *eptr != '\0') 132253246Sarchie return (-1); 132353246Sarchie return (val); 132453246Sarchie} 132553246Sarchie 1326