ng_ksocket.c revision 207732
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: head/sys/netgraph/ng_ksocket.c 207732 2010-05-06 20:58:23Z fabient $ 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 7270870SjulianMALLOC_DEFINE(M_NETGRAPH_KSOCKET, "netgraph_ksock", "netgraph ksock node "); 7370870Sjulian#else 7470870Sjulian#define M_NETGRAPH_KSOCKET M_NETGRAPH 7570870Sjulian#endif 7670870Sjulian 7753913Sarchie#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) 7853913Sarchie#define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data)) 7953913Sarchie 8053246Sarchie/* Node private data */ 8153404Sarchiestruct ng_ksocket_private { 8283186Sjulian node_p node; 8353246Sarchie hook_p hook; 8453246Sarchie struct socket *so; 85176917Smav int fn_sent; /* FN call on incoming event was sent */ 8683186Sjulian LIST_HEAD(, ng_ksocket_private) embryos; 8783186Sjulian LIST_ENTRY(ng_ksocket_private) siblings; 8883186Sjulian u_int32_t flags; 8983186Sjulian u_int32_t response_token; 9083186Sjulian ng_ID_t response_addr; 9153246Sarchie}; 9253404Sarchietypedef struct ng_ksocket_private *priv_p; 9353246Sarchie 9483186Sjulian/* Flags for priv_p */ 9583186Sjulian#define KSF_CONNECTING 0x00000001 /* Waiting for connection complete */ 9683186Sjulian#define KSF_ACCEPTING 0x00000002 /* Waiting for accept complete */ 9783186Sjulian#define KSF_EOFSEEN 0x00000004 /* Have sent 0-length EOF mbuf */ 9883186Sjulian#define KSF_CLONED 0x00000008 /* Cloned from an accepting socket */ 9983186Sjulian#define KSF_EMBRYONIC 0x00000010 /* Cloned node with no hooks yet */ 10083186Sjulian 10153246Sarchie/* Netgraph node methods */ 10253246Sarchiestatic ng_constructor_t ng_ksocket_constructor; 10353246Sarchiestatic ng_rcvmsg_t ng_ksocket_rcvmsg; 10470700Sjulianstatic ng_shutdown_t ng_ksocket_shutdown; 10553246Sarchiestatic ng_newhook_t ng_ksocket_newhook; 10653246Sarchiestatic ng_rcvdata_t ng_ksocket_rcvdata; 10783186Sjulianstatic ng_connect_t ng_ksocket_connect; 10853246Sarchiestatic ng_disconnect_t ng_ksocket_disconnect; 10953246Sarchie 11053246Sarchie/* Alias structure */ 11153246Sarchiestruct ng_ksocket_alias { 11253246Sarchie const char *name; 11353246Sarchie const int value; 11453246Sarchie const int family; 11553246Sarchie}; 11653246Sarchie 11753246Sarchie/* Protocol family aliases */ 11853246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_families[] = { 11953246Sarchie { "local", PF_LOCAL }, 12053246Sarchie { "inet", PF_INET }, 12153246Sarchie { "inet6", PF_INET6 }, 12253246Sarchie { "atalk", PF_APPLETALK }, 12353246Sarchie { "ipx", PF_IPX }, 12453246Sarchie { "atm", PF_ATM }, 12553246Sarchie { NULL, -1 }, 12653246Sarchie}; 12753246Sarchie 12853246Sarchie/* Socket type aliases */ 12953246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_types[] = { 13053246Sarchie { "stream", SOCK_STREAM }, 13153246Sarchie { "dgram", SOCK_DGRAM }, 13253246Sarchie { "raw", SOCK_RAW }, 13353246Sarchie { "rdm", SOCK_RDM }, 13453246Sarchie { "seqpacket", SOCK_SEQPACKET }, 13553246Sarchie { NULL, -1 }, 13653246Sarchie}; 13753246Sarchie 13853246Sarchie/* Protocol aliases */ 13953246Sarchiestatic const struct ng_ksocket_alias ng_ksocket_protos[] = { 14053246Sarchie { "ip", IPPROTO_IP, PF_INET }, 14184776Sarchie { "raw", IPPROTO_RAW, PF_INET }, 14253246Sarchie { "icmp", IPPROTO_ICMP, PF_INET }, 14353246Sarchie { "igmp", IPPROTO_IGMP, PF_INET }, 14453246Sarchie { "tcp", IPPROTO_TCP, PF_INET }, 14553246Sarchie { "udp", IPPROTO_UDP, PF_INET }, 14653246Sarchie { "gre", IPPROTO_GRE, PF_INET }, 14753246Sarchie { "esp", IPPROTO_ESP, PF_INET }, 14853246Sarchie { "ah", IPPROTO_AH, PF_INET }, 14953246Sarchie { "swipe", IPPROTO_SWIPE, PF_INET }, 15053246Sarchie { "encap", IPPROTO_ENCAP, PF_INET }, 15153246Sarchie { "divert", IPPROTO_DIVERT, PF_INET }, 152119187Shsu { "pim", IPPROTO_PIM, PF_INET }, 15353246Sarchie { "ddp", ATPROTO_DDP, PF_APPLETALK }, 15453246Sarchie { "aarp", ATPROTO_AARP, PF_APPLETALK }, 15553246Sarchie { NULL, -1 }, 15653246Sarchie}; 15753246Sarchie 15853913Sarchie/* Helper functions */ 15983186Sjulianstatic int ng_ksocket_check_accept(priv_p); 16083186Sjulianstatic void ng_ksocket_finish_accept(priv_p); 161193272Sjhbstatic int ng_ksocket_incoming(struct socket *so, void *arg, int waitflag); 16253913Sarchiestatic int ng_ksocket_parse(const struct ng_ksocket_alias *aliases, 16353913Sarchie const char *s, int family); 16483186Sjulianstatic void ng_ksocket_incoming2(node_p node, hook_p hook, 165176917Smav void *arg1, int arg2); 16653913Sarchie 16753913Sarchie/************************************************************************ 16853913Sarchie STRUCT SOCKADDR PARSE TYPE 16953913Sarchie ************************************************************************/ 17053913Sarchie 17153913Sarchie/* Get the length of the data portion of a generic struct sockaddr */ 17253913Sarchiestatic int 17353913Sarchieng_parse_generic_sockdata_getLength(const struct ng_parse_type *type, 17453913Sarchie const u_char *start, const u_char *buf) 17553913Sarchie{ 17653913Sarchie const struct sockaddr *sa; 17753913Sarchie 17853913Sarchie sa = (const struct sockaddr *)(buf - SADATA_OFFSET); 17964470Sarchie return (sa->sa_len < SADATA_OFFSET) ? 0 : sa->sa_len - SADATA_OFFSET; 18053913Sarchie} 18153913Sarchie 18253913Sarchie/* Type for the variable length data portion of a generic struct sockaddr */ 18353913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockdata_type = { 18453913Sarchie &ng_parse_bytearray_type, 18553913Sarchie &ng_parse_generic_sockdata_getLength 18653913Sarchie}; 18753913Sarchie 18853913Sarchie/* Type for a generic struct sockaddr */ 18997685Sarchiestatic const struct ng_parse_struct_field 19097685Sarchie ng_parse_generic_sockaddr_type_fields[] = { 19164508Sarchie { "len", &ng_parse_uint8_type }, 19264508Sarchie { "family", &ng_parse_uint8_type }, 19353913Sarchie { "data", &ng_ksocket_generic_sockdata_type }, 19453913Sarchie { NULL } 19553913Sarchie}; 19653913Sarchiestatic const struct ng_parse_type ng_ksocket_generic_sockaddr_type = { 19753913Sarchie &ng_parse_struct_type, 19897685Sarchie &ng_parse_generic_sockaddr_type_fields 19953913Sarchie}; 20053913Sarchie 20153913Sarchie/* Convert a struct sockaddr from ASCII to binary. If its a protocol 20253913Sarchie family that we specially handle, do that, otherwise defer to the 20353913Sarchie generic parse type ng_ksocket_generic_sockaddr_type. */ 20453913Sarchiestatic int 20553913Sarchieng_ksocket_sockaddr_parse(const struct ng_parse_type *type, 20653913Sarchie const char *s, int *off, const u_char *const start, 20753913Sarchie u_char *const buf, int *buflen) 20853913Sarchie{ 20953913Sarchie struct sockaddr *const sa = (struct sockaddr *)buf; 21053913Sarchie enum ng_parse_token tok; 21153913Sarchie char fambuf[32]; 21253913Sarchie int family, len; 21353913Sarchie char *t; 21453913Sarchie 21553913Sarchie /* If next token is a left curly brace, use generic parse type */ 21653913Sarchie if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) { 21753913Sarchie return (*ng_ksocket_generic_sockaddr_type.supertype->parse) 21853913Sarchie (&ng_ksocket_generic_sockaddr_type, 21953913Sarchie s, off, start, buf, buflen); 22053913Sarchie } 22153913Sarchie 22253913Sarchie /* Get socket address family followed by a slash */ 22353913Sarchie while (isspace(s[*off])) 22453913Sarchie (*off)++; 22553913Sarchie if ((t = index(s + *off, '/')) == NULL) 22653913Sarchie return (EINVAL); 22753913Sarchie if ((len = t - (s + *off)) > sizeof(fambuf) - 1) 22853913Sarchie return (EINVAL); 22953913Sarchie strncpy(fambuf, s + *off, len); 23053913Sarchie fambuf[len] = '\0'; 23153913Sarchie *off += len + 1; 23253913Sarchie if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1) 23353913Sarchie return (EINVAL); 23453913Sarchie 23553913Sarchie /* Set family */ 23653913Sarchie if (*buflen < SADATA_OFFSET) 23753913Sarchie return (ERANGE); 23853913Sarchie sa->sa_family = family; 23953913Sarchie 24053913Sarchie /* Set family-specific data and length */ 24153913Sarchie switch (sa->sa_family) { 24253913Sarchie case PF_LOCAL: /* Get pathname */ 24353913Sarchie { 24453913Sarchie const int pathoff = OFFSETOF(struct sockaddr_un, sun_path); 24553913Sarchie struct sockaddr_un *const sun = (struct sockaddr_un *)sa; 24653913Sarchie int toklen, pathlen; 24753913Sarchie char *path; 24853913Sarchie 24968845Sbrian if ((path = ng_get_string_token(s, off, &toklen, NULL)) == NULL) 25053913Sarchie return (EINVAL); 25153913Sarchie pathlen = strlen(path); 25253913Sarchie if (pathlen > SOCK_MAXADDRLEN) { 253184205Sdes free(path, M_NETGRAPH_KSOCKET); 25453913Sarchie return (E2BIG); 25553913Sarchie } 25653913Sarchie if (*buflen < pathoff + pathlen) { 257184205Sdes free(path, M_NETGRAPH_KSOCKET); 25853913Sarchie return (ERANGE); 25953913Sarchie } 26053913Sarchie *off += toklen; 26153913Sarchie bcopy(path, sun->sun_path, pathlen); 26253913Sarchie sun->sun_len = pathoff + pathlen; 263184205Sdes free(path, M_NETGRAPH_KSOCKET); 26453913Sarchie break; 26553913Sarchie } 26653913Sarchie 26753913Sarchie case PF_INET: /* Get an IP address with optional port */ 26853913Sarchie { 26953913Sarchie struct sockaddr_in *const sin = (struct sockaddr_in *)sa; 27053913Sarchie int i; 27153913Sarchie 27253913Sarchie /* Parse this: <ipaddress>[:port] */ 27353913Sarchie for (i = 0; i < 4; i++) { 27453913Sarchie u_long val; 27553913Sarchie char *eptr; 27653913Sarchie 27753913Sarchie val = strtoul(s + *off, &eptr, 10); 27853913Sarchie if (val > 0xff || eptr == s + *off) 27953913Sarchie return (EINVAL); 28053913Sarchie *off += (eptr - (s + *off)); 28153913Sarchie ((u_char *)&sin->sin_addr)[i] = (u_char)val; 28253913Sarchie if (i < 3) { 28353913Sarchie if (s[*off] != '.') 28453913Sarchie return (EINVAL); 28553913Sarchie (*off)++; 28653913Sarchie } else if (s[*off] == ':') { 28753913Sarchie (*off)++; 28853913Sarchie val = strtoul(s + *off, &eptr, 10); 28953913Sarchie if (val > 0xffff || eptr == s + *off) 29053913Sarchie return (EINVAL); 29153913Sarchie *off += (eptr - (s + *off)); 29253913Sarchie sin->sin_port = htons(val); 29353913Sarchie } else 29453913Sarchie sin->sin_port = 0; 29553913Sarchie } 29653913Sarchie bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 29753913Sarchie sin->sin_len = sizeof(*sin); 29853913Sarchie break; 29953913Sarchie } 30053913Sarchie 30153913Sarchie#if 0 30253913Sarchie case PF_APPLETALK: /* XXX implement these someday */ 30353913Sarchie case PF_INET6: 30453913Sarchie case PF_IPX: 30553913Sarchie#endif 30653913Sarchie 30753913Sarchie default: 30853913Sarchie return (EINVAL); 30953913Sarchie } 31053913Sarchie 31153913Sarchie /* Done */ 31253913Sarchie *buflen = sa->sa_len; 31353913Sarchie return (0); 31453913Sarchie} 31553913Sarchie 31653913Sarchie/* Convert a struct sockaddr from binary to ASCII */ 31753913Sarchiestatic int 31853913Sarchieng_ksocket_sockaddr_unparse(const struct ng_parse_type *type, 31953913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 32053913Sarchie{ 32153913Sarchie const struct sockaddr *sa = (const struct sockaddr *)(data + *off); 32253913Sarchie int slen = 0; 32353913Sarchie 32453913Sarchie /* Output socket address, either in special or generic format */ 32553913Sarchie switch (sa->sa_family) { 32653913Sarchie case PF_LOCAL: 32753913Sarchie { 32853913Sarchie const int pathoff = OFFSETOF(struct sockaddr_un, sun_path); 32953913Sarchie const struct sockaddr_un *sun = (const struct sockaddr_un *)sa; 33053913Sarchie const int pathlen = sun->sun_len - pathoff; 33153913Sarchie char pathbuf[SOCK_MAXADDRLEN + 1]; 33253913Sarchie char *pathtoken; 33353913Sarchie 33453913Sarchie bcopy(sun->sun_path, pathbuf, pathlen); 33568845Sbrian if ((pathtoken = ng_encode_string(pathbuf, pathlen)) == NULL) 33653913Sarchie return (ENOMEM); 33753913Sarchie slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken); 338184205Sdes free(pathtoken, M_NETGRAPH_KSOCKET); 33953913Sarchie if (slen >= cbuflen) 34053913Sarchie return (ERANGE); 34153913Sarchie *off += sun->sun_len; 34253913Sarchie return (0); 34353913Sarchie } 34453913Sarchie 34553913Sarchie case PF_INET: 34653913Sarchie { 34753913Sarchie const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 34853913Sarchie 34953913Sarchie slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d", 35053913Sarchie ((const u_char *)&sin->sin_addr)[0], 35153913Sarchie ((const u_char *)&sin->sin_addr)[1], 35253913Sarchie ((const u_char *)&sin->sin_addr)[2], 35353913Sarchie ((const u_char *)&sin->sin_addr)[3]); 35453913Sarchie if (sin->sin_port != 0) { 35553913Sarchie slen += snprintf(cbuf + strlen(cbuf), 35653913Sarchie cbuflen - strlen(cbuf), ":%d", 35753913Sarchie (u_int)ntohs(sin->sin_port)); 35853913Sarchie } 35953913Sarchie if (slen >= cbuflen) 36053913Sarchie return (ERANGE); 36153913Sarchie *off += sizeof(*sin); 36253913Sarchie return(0); 36353913Sarchie } 36453913Sarchie 36553913Sarchie#if 0 36653913Sarchie case PF_APPLETALK: /* XXX implement these someday */ 36753913Sarchie case PF_INET6: 36853913Sarchie case PF_IPX: 36953913Sarchie#endif 37053913Sarchie 37153913Sarchie default: 37253913Sarchie return (*ng_ksocket_generic_sockaddr_type.supertype->unparse) 37353913Sarchie (&ng_ksocket_generic_sockaddr_type, 37453913Sarchie data, off, cbuf, cbuflen); 37553913Sarchie } 37653913Sarchie} 37753913Sarchie 37853913Sarchie/* Parse type for struct sockaddr */ 37953913Sarchiestatic const struct ng_parse_type ng_ksocket_sockaddr_type = { 38053913Sarchie NULL, 38153913Sarchie NULL, 38253913Sarchie NULL, 38353913Sarchie &ng_ksocket_sockaddr_parse, 38453913Sarchie &ng_ksocket_sockaddr_unparse, 38553913Sarchie NULL /* no such thing as a default struct sockaddr */ 38653913Sarchie}; 38753913Sarchie 38853913Sarchie/************************************************************************ 38953913Sarchie STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE 39053913Sarchie ************************************************************************/ 39153913Sarchie 39253913Sarchie/* Get length of the struct ng_ksocket_sockopt value field, which is the 39353913Sarchie just the excess of the message argument portion over the length of 39453913Sarchie the struct ng_ksocket_sockopt. */ 39553913Sarchiestatic int 39653913Sarchieng_parse_sockoptval_getLength(const struct ng_parse_type *type, 39753913Sarchie const u_char *start, const u_char *buf) 39853913Sarchie{ 39953913Sarchie static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value); 40053913Sarchie const struct ng_ksocket_sockopt *sopt; 40153913Sarchie const struct ng_mesg *msg; 40253913Sarchie 40353913Sarchie sopt = (const struct ng_ksocket_sockopt *)(buf - offset); 40453913Sarchie msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg)); 40553913Sarchie return msg->header.arglen - sizeof(*sopt); 40653913Sarchie} 40753913Sarchie 40853913Sarchie/* Parse type for the option value part of a struct ng_ksocket_sockopt 40953913Sarchie XXX Eventually, we should handle the different socket options specially. 41053913Sarchie XXX This would avoid byte order problems, eg an integer value of 1 is 41153913Sarchie XXX going to be "[1]" for little endian or "[3=1]" for big endian. */ 41253913Sarchiestatic const struct ng_parse_type ng_ksocket_sockoptval_type = { 41353913Sarchie &ng_parse_bytearray_type, 41453913Sarchie &ng_parse_sockoptval_getLength 41553913Sarchie}; 41653913Sarchie 41753913Sarchie/* Parse type for struct ng_ksocket_sockopt */ 41897685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_sockopt_type_fields[] 41953913Sarchie = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type); 42053913Sarchiestatic const struct ng_parse_type ng_ksocket_sockopt_type = { 42153913Sarchie &ng_parse_struct_type, 42297685Sarchie &ng_ksocket_sockopt_type_fields 42353913Sarchie}; 42453913Sarchie 42583186Sjulian/* Parse type for struct ng_ksocket_accept */ 42697685Sarchiestatic const struct ng_parse_struct_field ng_ksocket_accept_type_fields[] 42783186Sjulian = NGM_KSOCKET_ACCEPT_INFO; 42883186Sjulianstatic const struct ng_parse_type ng_ksocket_accept_type = { 42983186Sjulian &ng_parse_struct_type, 43097685Sarchie &ng_ksocket_accept_type_fields 43183186Sjulian}; 43283186Sjulian 43353913Sarchie/* List of commands and how to convert arguments to/from ASCII */ 43453913Sarchiestatic const struct ng_cmdlist ng_ksocket_cmds[] = { 43553913Sarchie { 43653913Sarchie NGM_KSOCKET_COOKIE, 43753913Sarchie NGM_KSOCKET_BIND, 43853913Sarchie "bind", 43953913Sarchie &ng_ksocket_sockaddr_type, 44053913Sarchie NULL 44153913Sarchie }, 44253913Sarchie { 44353913Sarchie NGM_KSOCKET_COOKIE, 44453913Sarchie NGM_KSOCKET_LISTEN, 44553913Sarchie "listen", 44653913Sarchie &ng_parse_int32_type, 44753913Sarchie NULL 44853913Sarchie }, 44953913Sarchie { 45053913Sarchie NGM_KSOCKET_COOKIE, 45153913Sarchie NGM_KSOCKET_ACCEPT, 45253913Sarchie "accept", 45353913Sarchie NULL, 45483186Sjulian &ng_ksocket_accept_type 45553913Sarchie }, 45653913Sarchie { 45753913Sarchie NGM_KSOCKET_COOKIE, 45853913Sarchie NGM_KSOCKET_CONNECT, 45953913Sarchie "connect", 46053913Sarchie &ng_ksocket_sockaddr_type, 46183186Sjulian &ng_parse_int32_type 46253913Sarchie }, 46353913Sarchie { 46453913Sarchie NGM_KSOCKET_COOKIE, 46553913Sarchie NGM_KSOCKET_GETNAME, 46653913Sarchie "getname", 46753913Sarchie NULL, 46853913Sarchie &ng_ksocket_sockaddr_type 46953913Sarchie }, 47053913Sarchie { 47153913Sarchie NGM_KSOCKET_COOKIE, 47253913Sarchie NGM_KSOCKET_GETPEERNAME, 47353913Sarchie "getpeername", 47453913Sarchie NULL, 47553913Sarchie &ng_ksocket_sockaddr_type 47653913Sarchie }, 47753913Sarchie { 47853913Sarchie NGM_KSOCKET_COOKIE, 47953913Sarchie NGM_KSOCKET_SETOPT, 48053913Sarchie "setopt", 48153913Sarchie &ng_ksocket_sockopt_type, 48253913Sarchie NULL 48353913Sarchie }, 48453913Sarchie { 48553913Sarchie NGM_KSOCKET_COOKIE, 48653913Sarchie NGM_KSOCKET_GETOPT, 48753913Sarchie "getopt", 48853913Sarchie &ng_ksocket_sockopt_type, 48953913Sarchie &ng_ksocket_sockopt_type 49053913Sarchie }, 49153913Sarchie { 0 } 49253913Sarchie}; 49353913Sarchie 49453913Sarchie/* Node type descriptor */ 49553913Sarchiestatic struct ng_type ng_ksocket_typestruct = { 496129823Sjulian .version = NG_ABI_VERSION, 497129823Sjulian .name = NG_KSOCKET_NODE_TYPE, 498129823Sjulian .constructor = ng_ksocket_constructor, 499129823Sjulian .rcvmsg = ng_ksocket_rcvmsg, 500129823Sjulian .shutdown = ng_ksocket_shutdown, 501129823Sjulian .newhook = ng_ksocket_newhook, 502129823Sjulian .connect = ng_ksocket_connect, 503129823Sjulian .rcvdata = ng_ksocket_rcvdata, 504129823Sjulian .disconnect = ng_ksocket_disconnect, 505129823Sjulian .cmdlist = ng_ksocket_cmds, 50653913Sarchie}; 50753913SarchieNETGRAPH_INIT(ksocket, &ng_ksocket_typestruct); 50853913Sarchie 50997658Stanimura#define ERROUT(x) do { error = (x); goto done; } while (0) 51053246Sarchie 51153246Sarchie/************************************************************************ 51253246Sarchie NETGRAPH NODE STUFF 51353246Sarchie ************************************************************************/ 51453246Sarchie 51553246Sarchie/* 51653246Sarchie * Node type constructor 51783186Sjulian * The NODE part is assumed to be all set up. 51883186Sjulian * There is already a reference to the node for us. 51953246Sarchie */ 52053246Sarchiestatic int 52170700Sjulianng_ksocket_constructor(node_p node) 52253246Sarchie{ 52353246Sarchie priv_p priv; 52453246Sarchie 52553246Sarchie /* Allocate private structure */ 526184205Sdes priv = malloc(sizeof(*priv), 52772545Sarchie M_NETGRAPH_KSOCKET, M_NOWAIT | M_ZERO); 52853246Sarchie if (priv == NULL) 52953246Sarchie return (ENOMEM); 53053246Sarchie 53183186Sjulian LIST_INIT(&priv->embryos); 53283186Sjulian /* cross link them */ 53383186Sjulian priv->node = node; 53470784Sjulian NG_NODE_SET_PRIVATE(node, priv); 53553246Sarchie 53653246Sarchie /* Done */ 53753246Sarchie return (0); 53853246Sarchie} 53953246Sarchie 54053246Sarchie/* 54153246Sarchie * Give our OK for a hook to be added. The hook name is of the 54272545Sarchie * form "<family>/<type>/<proto>" where the three components may 54353246Sarchie * be decimal numbers or else aliases from the above lists. 54453246Sarchie * 54553246Sarchie * Connecting a hook amounts to opening the socket. Disconnecting 54653246Sarchie * the hook closes the socket and destroys the node as well. 54753246Sarchie */ 54853246Sarchiestatic int 54953246Sarchieng_ksocket_newhook(node_p node, hook_p hook, const char *name0) 55053246Sarchie{ 551134651Srwatson struct thread *td = curthread; /* XXX broken */ 55270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 553125028Sharti char *s1, *s2, name[NG_HOOKSIZ]; 55453246Sarchie int family, type, protocol, error; 55553246Sarchie 55653246Sarchie /* Check if we're already connected */ 55753246Sarchie if (priv->hook != NULL) 55853246Sarchie return (EISCONN); 55953246Sarchie 56083186Sjulian if (priv->flags & KSF_CLONED) { 56183186Sjulian if (priv->flags & KSF_EMBRYONIC) { 56283186Sjulian /* Remove ourselves from our parent's embryo list */ 56383186Sjulian LIST_REMOVE(priv, siblings); 56483186Sjulian priv->flags &= ~KSF_EMBRYONIC; 56583186Sjulian } 56683186Sjulian } else { 56783186Sjulian /* Extract family, type, and protocol from hook name */ 56883186Sjulian snprintf(name, sizeof(name), "%s", name0); 56983186Sjulian s1 = name; 57083186Sjulian if ((s2 = index(s1, '/')) == NULL) 57183186Sjulian return (EINVAL); 57283186Sjulian *s2++ = '\0'; 57383186Sjulian family = ng_ksocket_parse(ng_ksocket_families, s1, 0); 57483186Sjulian if (family == -1) 57583186Sjulian return (EINVAL); 57683186Sjulian s1 = s2; 57783186Sjulian if ((s2 = index(s1, '/')) == NULL) 57883186Sjulian return (EINVAL); 57983186Sjulian *s2++ = '\0'; 58083186Sjulian type = ng_ksocket_parse(ng_ksocket_types, s1, 0); 58183186Sjulian if (type == -1) 58283186Sjulian return (EINVAL); 58383186Sjulian s1 = s2; 58483186Sjulian protocol = ng_ksocket_parse(ng_ksocket_protos, s1, family); 58583186Sjulian if (protocol == -1) 58683186Sjulian return (EINVAL); 58753246Sarchie 58883186Sjulian /* Create the socket */ 58988739Srwatson error = socreate(family, &priv->so, type, protocol, 59091406Sjhb td->td_ucred, td); 59183186Sjulian if (error != 0) 59283186Sjulian return (error); 59353246Sarchie 59483186Sjulian /* XXX call soreserve() ? */ 59553246Sarchie 59683186Sjulian } 59783186Sjulian 59883186Sjulian /* OK */ 59983186Sjulian priv->hook = hook; 600145229Sglebius 601145229Sglebius /* 602145229Sglebius * In case of misconfigured routing a packet may reenter 603145229Sglebius * ksocket node recursively. Decouple stack to avoid possible 604145229Sglebius * panics about sleeping with locks held. 605145229Sglebius */ 606145229Sglebius NG_HOOK_FORCE_QUEUE(hook); 607145229Sglebius 60883186Sjulian return(0); 60983186Sjulian} 61083186Sjulian 61183186Sjulianstatic int 61283186Sjulianng_ksocket_connect(hook_p hook) 61383186Sjulian{ 61483186Sjulian node_p node = NG_HOOK_NODE(hook); 61583186Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 61683186Sjulian struct socket *const so = priv->so; 61783186Sjulian 61883186Sjulian /* Add our hook for incoming data and other events */ 619130653Srwatson SOCKBUF_LOCK(&priv->so->so_rcv); 620193272Sjhb soupcall_set(priv->so, SO_RCV, ng_ksocket_incoming, node); 621130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_rcv); 622130653Srwatson SOCKBUF_LOCK(&priv->so->so_snd); 623193272Sjhb soupcall_set(priv->so, SO_SND, ng_ksocket_incoming, node); 624130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_snd); 625130653Srwatson SOCK_LOCK(priv->so); 62683186Sjulian priv->so->so_state |= SS_NBIO; 627130653Srwatson SOCK_UNLOCK(priv->so); 62883186Sjulian /* 62983186Sjulian * --Original comment-- 63083186Sjulian * On a cloned socket we may have already received one or more 63183186Sjulian * upcalls which we couldn't handle without a hook. Handle 63283186Sjulian * those now. 63383186Sjulian * We cannot call the upcall function directly 63483186Sjulian * from here, because until this function has returned our 63583186Sjulian * hook isn't connected. 63683186Sjulian * 63783186Sjulian * ---meta comment for -current --- 63883186Sjulian * XXX This is dubius. 63983186Sjulian * Upcalls between the time that the hook was 64083186Sjulian * first created and now (on another processesor) will 64183186Sjulian * be earlier on the queue than the request to finalise the hook. 64283186Sjulian * By the time the hook is finalised, 64383186Sjulian * The queued upcalls will have happenned and the code 64483186Sjulian * will have discarded them because of a lack of a hook. 64583186Sjulian * (socket not open). 64683186Sjulian * 64783186Sjulian * This is a bad byproduct of the complicated way in which hooks 64883186Sjulian * are now created (3 daisy chained async events). 64983186Sjulian * 65083186Sjulian * Since we are a netgraph operation 65183186Sjulian * We know that we hold a lock on this node. This forces the 65283186Sjulian * request we make below to be queued rather than implemented 65383186Sjulian * immediatly which will cause the upcall function to be called a bit 65483186Sjulian * later. 65583186Sjulian * However, as we will run any waiting queued operations immediatly 65683186Sjulian * after doing this one, if we have not finalised the other end 65783186Sjulian * of the hook, those queued operations will fail. 65883186Sjulian */ 65983186Sjulian if (priv->flags & KSF_CLONED) { 66083186Sjulian ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_NOWAIT); 66183186Sjulian } 66253246Sarchie 66353246Sarchie return (0); 66453246Sarchie} 66553246Sarchie 66653246Sarchie/* 66753246Sarchie * Receive a control message 66853246Sarchie */ 66953246Sarchiestatic int 67070700Sjulianng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) 67153246Sarchie{ 672134651Srwatson struct thread *td = curthread; /* XXX broken */ 67370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 67453913Sarchie struct socket *const so = priv->so; 67553246Sarchie struct ng_mesg *resp = NULL; 67653246Sarchie int error = 0; 67770700Sjulian struct ng_mesg *msg; 67883186Sjulian ng_ID_t raddr; 67953246Sarchie 68070700Sjulian NGI_GET_MSG(item, msg); 68153246Sarchie switch (msg->header.typecookie) { 68253246Sarchie case NGM_KSOCKET_COOKIE: 68353246Sarchie switch (msg->header.cmd) { 68453246Sarchie case NGM_KSOCKET_BIND: 68553246Sarchie { 68653913Sarchie struct sockaddr *const sa 68753913Sarchie = (struct sockaddr *)msg->data; 68853246Sarchie 68953913Sarchie /* Sanity check */ 69053913Sarchie if (msg->header.arglen < SADATA_OFFSET 69153913Sarchie || msg->header.arglen < sa->sa_len) 69253913Sarchie ERROUT(EINVAL); 69353913Sarchie if (so == NULL) 69453913Sarchie ERROUT(ENXIO); 69553246Sarchie 69653913Sarchie /* Bind */ 69783366Sjulian error = sobind(so, sa, td); 69853246Sarchie break; 69953246Sarchie } 70053246Sarchie case NGM_KSOCKET_LISTEN: 70153246Sarchie { 70253913Sarchie /* Sanity check */ 70383186Sjulian if (msg->header.arglen != sizeof(int32_t)) 70453246Sarchie ERROUT(EINVAL); 70553913Sarchie if (so == NULL) 70653913Sarchie ERROUT(ENXIO); 70753246Sarchie 70853913Sarchie /* Listen */ 70983366Sjulian error = solisten(so, *((int32_t *)msg->data), td); 71053246Sarchie break; 71153246Sarchie } 71253246Sarchie 71353246Sarchie case NGM_KSOCKET_ACCEPT: 71453246Sarchie { 71553913Sarchie /* Sanity check */ 71653913Sarchie if (msg->header.arglen != 0) 71753913Sarchie ERROUT(EINVAL); 71853913Sarchie if (so == NULL) 71953913Sarchie ERROUT(ENXIO); 72053913Sarchie 72183186Sjulian /* Make sure the socket is capable of accepting */ 72283186Sjulian if (!(so->so_options & SO_ACCEPTCONN)) 72397658Stanimura ERROUT(EINVAL); 72483186Sjulian if (priv->flags & KSF_ACCEPTING) 72583186Sjulian ERROUT(EALREADY); 72653913Sarchie 72783186Sjulian error = ng_ksocket_check_accept(priv); 72883186Sjulian if (error != 0 && error != EWOULDBLOCK) 72983186Sjulian ERROUT(error); 73083186Sjulian 73183186Sjulian /* 73283186Sjulian * If a connection is already complete, take it. 73383186Sjulian * Otherwise let the upcall function deal with 73483186Sjulian * the connection when it comes in. 73583186Sjulian */ 73683186Sjulian priv->response_token = msg->header.token; 737103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 73883186Sjulian if (error == 0) { 73983186Sjulian ng_ksocket_finish_accept(priv); 74083186Sjulian } else 74183186Sjulian priv->flags |= KSF_ACCEPTING; 74253246Sarchie break; 74353246Sarchie } 74453246Sarchie 74553246Sarchie case NGM_KSOCKET_CONNECT: 74653246Sarchie { 74753913Sarchie struct sockaddr *const sa 74853913Sarchie = (struct sockaddr *)msg->data; 74953246Sarchie 75053913Sarchie /* Sanity check */ 75153913Sarchie if (msg->header.arglen < SADATA_OFFSET 75253913Sarchie || msg->header.arglen < sa->sa_len) 75353913Sarchie ERROUT(EINVAL); 75453913Sarchie if (so == NULL) 75553913Sarchie ERROUT(ENXIO); 75653246Sarchie 75753246Sarchie /* Do connect */ 75853246Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) 75997658Stanimura ERROUT(EALREADY); 76083366Sjulian if ((error = soconnect(so, sa, td)) != 0) { 76153246Sarchie so->so_state &= ~SS_ISCONNECTING; 76297658Stanimura ERROUT(error); 76353246Sarchie } 764114178Sarchie if ((so->so_state & SS_ISCONNECTING) != 0) { 76583186Sjulian /* We will notify the sender when we connect */ 76683186Sjulian priv->response_token = msg->header.token; 767103205Sbenno raddr = priv->response_addr = NGI_RETADDR(item); 76883186Sjulian priv->flags |= KSF_CONNECTING; 76997658Stanimura ERROUT(EINPROGRESS); 770114178Sarchie } 77153246Sarchie break; 77253246Sarchie } 77353246Sarchie 77453246Sarchie case NGM_KSOCKET_GETNAME: 77553913Sarchie case NGM_KSOCKET_GETPEERNAME: 77653246Sarchie { 77753913Sarchie int (*func)(struct socket *so, struct sockaddr **nam); 77853913Sarchie struct sockaddr *sa = NULL; 77953913Sarchie int len; 78053246Sarchie 78153913Sarchie /* Sanity check */ 78253913Sarchie if (msg->header.arglen != 0) 78353913Sarchie ERROUT(EINVAL); 78453913Sarchie if (so == NULL) 78553913Sarchie ERROUT(ENXIO); 78653913Sarchie 78753913Sarchie /* Get function */ 78853913Sarchie if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) { 78953913Sarchie if ((so->so_state 79053913Sarchie & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) 79197658Stanimura ERROUT(ENOTCONN); 79253913Sarchie func = so->so_proto->pr_usrreqs->pru_peeraddr; 79353913Sarchie } else 79453913Sarchie func = so->so_proto->pr_usrreqs->pru_sockaddr; 79553913Sarchie 79653913Sarchie /* Get local or peer address */ 79753913Sarchie if ((error = (*func)(so, &sa)) != 0) 79853913Sarchie goto bail; 79953913Sarchie len = (sa == NULL) ? 0 : sa->sa_len; 80053913Sarchie 80153913Sarchie /* Send it back in a response */ 80253913Sarchie NG_MKRESPONSE(resp, msg, len, M_NOWAIT); 80353913Sarchie if (resp == NULL) { 80453913Sarchie error = ENOMEM; 80553913Sarchie goto bail; 80653913Sarchie } 80753913Sarchie bcopy(sa, resp->data, len); 80853913Sarchie 80953913Sarchie bail: 81053913Sarchie /* Cleanup */ 81153913Sarchie if (sa != NULL) 812184205Sdes free(sa, M_SONAME); 81353246Sarchie break; 81453246Sarchie } 81553246Sarchie 81653246Sarchie case NGM_KSOCKET_GETOPT: 81753246Sarchie { 81853913Sarchie struct ng_ksocket_sockopt *ksopt = 81953913Sarchie (struct ng_ksocket_sockopt *)msg->data; 82053913Sarchie struct sockopt sopt; 82153913Sarchie 82253913Sarchie /* Sanity check */ 82353913Sarchie if (msg->header.arglen != sizeof(*ksopt)) 82453913Sarchie ERROUT(EINVAL); 82553913Sarchie if (so == NULL) 82653913Sarchie ERROUT(ENXIO); 82753913Sarchie 82853913Sarchie /* Get response with room for option value */ 82953913Sarchie NG_MKRESPONSE(resp, msg, sizeof(*ksopt) 83053913Sarchie + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT); 83153913Sarchie if (resp == NULL) 83253913Sarchie ERROUT(ENOMEM); 83353913Sarchie 83453913Sarchie /* Get socket option, and put value in the response */ 83553913Sarchie sopt.sopt_dir = SOPT_GET; 83653913Sarchie sopt.sopt_level = ksopt->level; 83753913Sarchie sopt.sopt_name = ksopt->name; 83883366Sjulian sopt.sopt_td = NULL; 83953913Sarchie sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN; 84053913Sarchie ksopt = (struct ng_ksocket_sockopt *)resp->data; 84153913Sarchie sopt.sopt_val = ksopt->value; 84253913Sarchie if ((error = sogetopt(so, &sopt)) != 0) { 84370700Sjulian NG_FREE_MSG(resp); 84453913Sarchie break; 84553913Sarchie } 84653913Sarchie 84753913Sarchie /* Set actual value length */ 84853913Sarchie resp->header.arglen = sizeof(*ksopt) 84953913Sarchie + sopt.sopt_valsize; 85053246Sarchie break; 85153246Sarchie } 85253246Sarchie 85353246Sarchie case NGM_KSOCKET_SETOPT: 85453246Sarchie { 85553913Sarchie struct ng_ksocket_sockopt *const ksopt = 85653913Sarchie (struct ng_ksocket_sockopt *)msg->data; 85753913Sarchie const int valsize = msg->header.arglen - sizeof(*ksopt); 85853913Sarchie struct sockopt sopt; 85953913Sarchie 86053913Sarchie /* Sanity check */ 86153913Sarchie if (valsize < 0) 86253913Sarchie ERROUT(EINVAL); 86353913Sarchie if (so == NULL) 86453913Sarchie ERROUT(ENXIO); 86553913Sarchie 86653913Sarchie /* Set socket option */ 86753913Sarchie sopt.sopt_dir = SOPT_SET; 86853913Sarchie sopt.sopt_level = ksopt->level; 86953913Sarchie sopt.sopt_name = ksopt->name; 87053913Sarchie sopt.sopt_val = ksopt->value; 87153913Sarchie sopt.sopt_valsize = valsize; 87283366Sjulian sopt.sopt_td = NULL; 87353913Sarchie error = sosetopt(so, &sopt); 87453246Sarchie break; 87553246Sarchie } 87653246Sarchie 87753246Sarchie default: 87853246Sarchie error = EINVAL; 87953246Sarchie break; 88053246Sarchie } 88153246Sarchie break; 88253246Sarchie default: 88353246Sarchie error = EINVAL; 88453246Sarchie break; 88553246Sarchie } 88653246Sarchiedone: 88770700Sjulian NG_RESPOND_MSG(error, node, item, resp); 88870700Sjulian NG_FREE_MSG(msg); 88953246Sarchie return (error); 89053246Sarchie} 89153246Sarchie 89253246Sarchie/* 89353246Sarchie * Receive incoming data on our hook. Send it out the socket. 89453246Sarchie */ 89553246Sarchiestatic int 89670700Sjulianng_ksocket_rcvdata(hook_p hook, item_p item) 89753246Sarchie{ 898134651Srwatson struct thread *td = curthread; /* XXX broken */ 89970784Sjulian const node_p node = NG_HOOK_NODE(hook); 90070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 90153246Sarchie struct socket *const so = priv->so; 90287070Sarchie struct sockaddr *sa = NULL; 90353246Sarchie int error; 90470700Sjulian struct mbuf *m; 905206017Smav#ifdef ALIGNED_POINTER 906206017Smav struct mbuf *n; 907206017Smav#endif /* ALIGNED_POINTER */ 908131108Sjulian struct sa_tag *stag; 90953246Sarchie 910131108Sjulian /* Extract data */ 91170700Sjulian NGI_GET_M(item, m); 91270700Sjulian NG_FREE_ITEM(item); 913206017Smav#ifdef ALIGNED_POINTER 914206017Smav if (!ALIGNED_POINTER(mtod(m, caddr_t), uint32_t)) { 915206017Smav n = m_defrag(m, M_NOWAIT); 916206017Smav if (n == NULL) { 917206017Smav m_freem(m); 918206017Smav return (ENOBUFS); 919206017Smav } 920206017Smav m = n; 921206017Smav } 922206017Smav#endif /* ALIGNED_POINTER */ 923141728Sglebius /* 924141728Sglebius * Look if socket address is stored in packet tags. 925141728Sglebius * If sockaddr is ours, or provided by a third party (zero id), 926141728Sglebius * then we accept it. 927141728Sglebius */ 928141728Sglebius if (((stag = (struct sa_tag *)m_tag_locate(m, NGM_KSOCKET_COOKIE, 929141728Sglebius NG_KSOCKET_TAG_SOCKADDR, NULL)) != NULL) && 930141728Sglebius (stag->id == NG_NODE_ID(node) || stag->id == 0)) 931131108Sjulian sa = &stag->sa; 93287070Sarchie 933166585Sbms /* Reset specific mbuf flags to prevent addressing problems. */ 934166585Sbms m->m_flags &= ~(M_BCAST|M_MCAST); 935166585Sbms 93687070Sarchie /* Send packet */ 937160619Srwatson error = sosend(so, sa, 0, m, 0, 0, td); 93887070Sarchie 93953246Sarchie return (error); 94053246Sarchie} 94153246Sarchie 94253246Sarchie/* 94353246Sarchie * Destroy node 94453246Sarchie */ 94553246Sarchiestatic int 94670700Sjulianng_ksocket_shutdown(node_p node) 94753246Sarchie{ 94870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 94983186Sjulian priv_p embryo; 95053246Sarchie 95153404Sarchie /* Close our socket (if any) */ 95253404Sarchie if (priv->so != NULL) { 953130653Srwatson SOCKBUF_LOCK(&priv->so->so_rcv); 954193272Sjhb soupcall_clear(priv->so, SO_RCV); 955130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_rcv); 956130653Srwatson SOCKBUF_LOCK(&priv->so->so_snd); 957193272Sjhb soupcall_clear(priv->so, SO_SND); 958130653Srwatson SOCKBUF_UNLOCK(&priv->so->so_snd); 95953404Sarchie soclose(priv->so); 96053404Sarchie priv->so = NULL; 96153404Sarchie } 96253404Sarchie 96383186Sjulian /* If we are an embryo, take ourselves out of the parent's list */ 96483186Sjulian if (priv->flags & KSF_EMBRYONIC) { 96583186Sjulian LIST_REMOVE(priv, siblings); 96683186Sjulian priv->flags &= ~KSF_EMBRYONIC; 96783186Sjulian } 96883186Sjulian 96983186Sjulian /* Remove any embryonic children we have */ 97083186Sjulian while (!LIST_EMPTY(&priv->embryos)) { 97183186Sjulian embryo = LIST_FIRST(&priv->embryos); 97283186Sjulian ng_rmnode_self(embryo->node); 97383186Sjulian } 97483186Sjulian 97553246Sarchie /* Take down netgraph node */ 97653246Sarchie bzero(priv, sizeof(*priv)); 977184205Sdes free(priv, M_NETGRAPH_KSOCKET); 97870784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 97970784Sjulian NG_NODE_UNREF(node); /* let the node escape */ 98053246Sarchie return (0); 98153246Sarchie} 98253246Sarchie 98353246Sarchie/* 98453246Sarchie * Hook disconnection 98553246Sarchie */ 98653246Sarchiestatic int 98753246Sarchieng_ksocket_disconnect(hook_p hook) 98853246Sarchie{ 98970784Sjulian KASSERT(NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0, 99087599Sobrien ("%s: numhooks=%d?", __func__, 99172545Sarchie NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)))); 99270784Sjulian if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) 99370784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 99453246Sarchie return (0); 99553246Sarchie} 99653246Sarchie 99753246Sarchie/************************************************************************ 99853246Sarchie HELPER STUFF 99953246Sarchie ************************************************************************/ 100083186Sjulian/* 1001176917Smav * You should not "just call" a netgraph node function from an external 1002176917Smav * asynchronous event. This is because in doing so you are ignoring the 1003176917Smav * locking on the netgraph nodes. Instead call your function via ng_send_fn(). 1004176917Smav * This will call the function you chose, but will first do all the 100583186Sjulian * locking rigmarole. Your function MAY only be called at some distant future 100683186Sjulian * time (several millisecs away) so don't give it any arguments 100783186Sjulian * that may be revoked soon (e.g. on your stack). 1008149820Sglebius * 1009149820Sglebius * To decouple stack, we use queue version of ng_send_fn(). 101083186Sjulian */ 101153246Sarchie 1012193272Sjhbstatic int 101383186Sjulianng_ksocket_incoming(struct socket *so, void *arg, int waitflag) 101483186Sjulian{ 101583186Sjulian const node_p node = arg; 1016176917Smav const priv_p priv = NG_NODE_PRIVATE(node); 1017176917Smav int wait = ((waitflag & M_WAITOK) ? NG_WAITOK : 0) | NG_QUEUE; 101883186Sjulian 1019176917Smav /* 1020176917Smav * Even if node is not locked, as soon as we are called, we assume 1021176917Smav * it exist and it's private area is valid. With some care we can 1022176917Smav * access it. Mark node that incoming event for it was sent to 1023176917Smav * avoid unneded queue trashing. 1024176917Smav */ 1025176917Smav if (atomic_cmpset_int(&priv->fn_sent, 0, 1) && 1026176917Smav ng_send_fn1(node, NULL, &ng_ksocket_incoming2, so, 0, wait)) { 1027176917Smav atomic_store_rel_int(&priv->fn_sent, 0); 1028176917Smav } 1029193272Sjhb return (SU_OK); 103083186Sjulian} 103183186Sjulian 103283186Sjulian 103353246Sarchie/* 103453246Sarchie * When incoming data is appended to the socket, we get notified here. 103583186Sjulian * This is also called whenever a significant event occurs for the socket. 103683186Sjulian * Our original caller may have queued this even some time ago and 103783186Sjulian * we cannot trust that he even still exists. The node however is being 1038176917Smav * held with a reference by the queueing code and guarantied to be valid. 103953246Sarchie */ 104053246Sarchiestatic void 1041176917Smavng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2) 104253246Sarchie{ 104383186Sjulian struct socket *so = arg1; 104470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 104553246Sarchie struct mbuf *m; 104683186Sjulian struct ng_mesg *response; 104753246Sarchie struct uio auio; 104853404Sarchie int s, flags, error; 104953246Sarchie 105053404Sarchie s = splnet(); 105153404Sarchie 105283186Sjulian /* so = priv->so; *//* XXX could have derived this like so */ 105387599Sobrien KASSERT(so == priv->so, ("%s: wrong socket", __func__)); 1054176917Smav 1055176917Smav /* Allow next incoming event to be queued. */ 1056176917Smav atomic_store_rel_int(&priv->fn_sent, 0); 105753246Sarchie 105883186Sjulian /* Check whether a pending connect operation has completed */ 105983186Sjulian if (priv->flags & KSF_CONNECTING) { 106083186Sjulian if ((error = so->so_error) != 0) { 106183186Sjulian so->so_error = 0; 106283186Sjulian so->so_state &= ~SS_ISCONNECTING; 106383186Sjulian } 106483186Sjulian if (!(so->so_state & SS_ISCONNECTING)) { 106583186Sjulian NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE, 1066176917Smav NGM_KSOCKET_CONNECT, sizeof(int32_t), M_NOWAIT); 106783186Sjulian if (response != NULL) { 106883186Sjulian response->header.flags |= NGF_RESP; 106983186Sjulian response->header.token = priv->response_token; 107083186Sjulian *(int32_t *)response->data = error; 107183186Sjulian /* 107283186Sjulian * send an async "response" message 107383186Sjulian * to the node that set us up 107483186Sjulian * (if it still exists) 107583186Sjulian */ 1076102244Sarchie NG_SEND_MSG_ID(error, node, 1077102244Sarchie response, priv->response_addr, 0); 107883186Sjulian } 107983186Sjulian priv->flags &= ~KSF_CONNECTING; 108097658Stanimura } 108183186Sjulian } 108283186Sjulian 108383186Sjulian /* Check whether a pending accept operation has completed */ 108483186Sjulian if (priv->flags & KSF_ACCEPTING) { 108583186Sjulian error = ng_ksocket_check_accept(priv); 108683186Sjulian if (error != EWOULDBLOCK) 108783186Sjulian priv->flags &= ~KSF_ACCEPTING; 108883186Sjulian if (error == 0) 108983186Sjulian ng_ksocket_finish_accept(priv); 109083186Sjulian } 109183186Sjulian 109283186Sjulian /* 109383186Sjulian * If we don't have a hook, we must handle data events later. When 109483186Sjulian * the hook gets created and is connected, this upcall function 109583186Sjulian * will be called again. 109683186Sjulian */ 109783186Sjulian if (priv->hook == NULL) { 109883186Sjulian splx(s); 109983186Sjulian return; 110083186Sjulian } 110183186Sjulian 110253246Sarchie /* Read and forward available mbuf's */ 110383366Sjulian auio.uio_td = NULL; 110453246Sarchie auio.uio_resid = 1000000000; 110553246Sarchie flags = MSG_DONTWAIT; 110687070Sarchie while (1) { 110787070Sarchie struct sockaddr *sa = NULL; 110887070Sarchie struct mbuf *n; 110987070Sarchie 111087070Sarchie /* Try to get next packet from socket */ 1111160619Srwatson if ((error = soreceive(so, (so->so_state & SS_ISCONNECTED) ? 1112160619Srwatson NULL : &sa, &auio, &m, (struct mbuf **)0, &flags)) != 0) 111387070Sarchie break; 111453913Sarchie 111587070Sarchie /* See if we got anything */ 111687070Sarchie if (m == NULL) { 111787070Sarchie if (sa != NULL) 1118184205Sdes free(sa, M_SONAME); 111987070Sarchie break; 112053913Sarchie } 112183186Sjulian 1122149820Sglebius /* 1123149820Sglebius * Don't trust the various socket layers to get the 1124149820Sglebius * packet header and length correct (e.g. kern/15175). 1125149820Sglebius * 1126149820Sglebius * Also, do not trust that soreceive() will clear m_nextpkt 1127149820Sglebius * for us (e.g. kern/84952, kern/82413). 1128149820Sglebius */ 1129155877Sru m->m_pkthdr.csum_flags = 0; 1130149820Sglebius for (n = m, m->m_pkthdr.len = 0; n != NULL; n = n->m_next) { 113187070Sarchie m->m_pkthdr.len += n->m_len; 1132149820Sglebius n->m_nextpkt = NULL; 1133149820Sglebius } 113487070Sarchie 1135131108Sjulian /* Put peer's socket address (if any) into a tag */ 113687070Sarchie if (sa != NULL) { 1137131108Sjulian struct sa_tag *stag; 113887070Sarchie 1139131108Sjulian stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE, 1140141743Sglebius NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) + 1141141743Sglebius sa->sa_len, M_NOWAIT); 1142131108Sjulian if (stag == NULL) { 1143184205Sdes free(sa, M_SONAME); 114487070Sarchie goto sendit; 114587070Sarchie } 1146131108Sjulian bcopy(sa, &stag->sa, sa->sa_len); 1147184205Sdes free(sa, M_SONAME); 1148141728Sglebius stag->id = NG_NODE_ID(node); 1149131108Sjulian m_tag_prepend(m, &stag->tag); 115087070Sarchie } 115187070Sarchie 1152131108Sjuliansendit: /* Forward data with optional peer sockaddr as packet tag */ 1153131108Sjulian NG_SEND_DATA_ONLY(error, priv->hook, m); 115487070Sarchie } 115587070Sarchie 115683186Sjulian /* 115783186Sjulian * If the peer has closed the connection, forward a 0-length mbuf 115883186Sjulian * to indicate end-of-file. 115983186Sjulian */ 1160130480Srwatson if (so->so_rcv.sb_state & SBS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) { 1161176917Smav MGETHDR(m, M_NOWAIT, MT_DATA); 116283186Sjulian if (m != NULL) { 116383186Sjulian m->m_len = m->m_pkthdr.len = 0; 116483186Sjulian NG_SEND_DATA_ONLY(error, priv->hook, m); 116583186Sjulian } 116683186Sjulian priv->flags |= KSF_EOFSEEN; 116797658Stanimura } 116853404Sarchie splx(s); 116953246Sarchie} 117053246Sarchie 117153246Sarchie/* 117283186Sjulian * Check for a completed incoming connection and return 0 if one is found. 117383186Sjulian * Otherwise return the appropriate error code. 117483186Sjulian */ 117583186Sjulianstatic int 117683186Sjulianng_ksocket_check_accept(priv_p priv) 117783186Sjulian{ 117883186Sjulian struct socket *const head = priv->so; 117983186Sjulian int error; 118083186Sjulian 118183186Sjulian if ((error = head->so_error) != 0) { 118283186Sjulian head->so_error = 0; 118383186Sjulian return error; 118483186Sjulian } 1185129979Srwatson /* Unlocked read. */ 118683186Sjulian if (TAILQ_EMPTY(&head->so_comp)) { 1187130480Srwatson if (head->so_rcv.sb_state & SBS_CANTRCVMORE) 118883186Sjulian return ECONNABORTED; 118983186Sjulian return EWOULDBLOCK; 119083186Sjulian } 119183186Sjulian return 0; 119283186Sjulian} 119383186Sjulian 119483186Sjulian/* 119583186Sjulian * Handle the first completed incoming connection, assumed to be already 119683186Sjulian * on the socket's so_comp queue. 119783186Sjulian */ 119883186Sjulianstatic void 119983186Sjulianng_ksocket_finish_accept(priv_p priv) 120083186Sjulian{ 120183186Sjulian struct socket *const head = priv->so; 120283186Sjulian struct socket *so; 120383186Sjulian struct sockaddr *sa = NULL; 120483186Sjulian struct ng_mesg *resp; 120583186Sjulian struct ng_ksocket_accept *resp_data; 120683186Sjulian node_p node; 120783186Sjulian priv_p priv2; 120883186Sjulian int len; 120983186Sjulian int error; 121083186Sjulian 1211129979Srwatson ACCEPT_LOCK(); 121283186Sjulian so = TAILQ_FIRST(&head->so_comp); 1213129979Srwatson if (so == NULL) { /* Should never happen */ 1214129979Srwatson ACCEPT_UNLOCK(); 121583186Sjulian return; 1216129979Srwatson } 121783186Sjulian TAILQ_REMOVE(&head->so_comp, so, so_list); 121883186Sjulian head->so_qlen--; 1219129979Srwatson so->so_qstate &= ~SQ_COMP; 1220129979Srwatson so->so_head = NULL; 1221130387Srwatson SOCK_LOCK(so); 1222129979Srwatson soref(so); 1223129979Srwatson so->so_state |= SS_NBIO; 1224130387Srwatson SOCK_UNLOCK(so); 1225129979Srwatson ACCEPT_UNLOCK(); 122683186Sjulian 1227195148Sstas /* XXX KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); */ 122883186Sjulian 122983186Sjulian soaccept(so, &sa); 123083186Sjulian 123183186Sjulian len = OFFSETOF(struct ng_ksocket_accept, addr); 123283186Sjulian if (sa != NULL) 123383186Sjulian len += sa->sa_len; 123483186Sjulian 123583186Sjulian NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len, 123683186Sjulian M_NOWAIT); 123783186Sjulian if (resp == NULL) { 123883186Sjulian soclose(so); 123983186Sjulian goto out; 124083186Sjulian } 124183186Sjulian resp->header.flags |= NGF_RESP; 124283186Sjulian resp->header.token = priv->response_token; 124383186Sjulian 124483186Sjulian /* Clone a ksocket node to wrap the new socket */ 124583186Sjulian error = ng_make_node_common(&ng_ksocket_typestruct, &node); 124683186Sjulian if (error) { 1247184205Sdes free(resp, M_NETGRAPH); 124883186Sjulian soclose(so); 124983186Sjulian goto out; 125083186Sjulian } 125183186Sjulian 125283186Sjulian if (ng_ksocket_constructor(node) != 0) { 125383186Sjulian NG_NODE_UNREF(node); 1254184205Sdes free(resp, M_NETGRAPH); 125583186Sjulian soclose(so); 125683186Sjulian goto out; 125783186Sjulian } 125883186Sjulian 125983186Sjulian priv2 = NG_NODE_PRIVATE(node); 126083186Sjulian priv2->so = so; 126183186Sjulian priv2->flags |= KSF_CLONED | KSF_EMBRYONIC; 126283186Sjulian 126383186Sjulian /* 126483186Sjulian * Insert the cloned node into a list of embryonic children 126583186Sjulian * on the parent node. When a hook is created on the cloned 126683186Sjulian * node it will be removed from this list. When the parent 126783186Sjulian * is destroyed it will destroy any embryonic children it has. 126883186Sjulian */ 126983186Sjulian LIST_INSERT_HEAD(&priv->embryos, priv2, siblings); 127083186Sjulian 1271130653Srwatson SOCKBUF_LOCK(&so->so_rcv); 1272193272Sjhb soupcall_set(so, SO_RCV, ng_ksocket_incoming, node); 1273130653Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 1274130653Srwatson SOCKBUF_LOCK(&so->so_snd); 1275207732Sfabient soupcall_set(so, SO_SND, ng_ksocket_incoming, node); 1276130653Srwatson SOCKBUF_UNLOCK(&so->so_snd); 127783186Sjulian 127883186Sjulian /* Fill in the response data and send it or return it to the caller */ 127983186Sjulian resp_data = (struct ng_ksocket_accept *)resp->data; 128083186Sjulian resp_data->nodeid = NG_NODE_ID(node); 128183186Sjulian if (sa != NULL) 128283186Sjulian bcopy(sa, &resp_data->addr, sa->sa_len); 1283102244Sarchie NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0); 128483186Sjulian 128583186Sjulianout: 128683186Sjulian if (sa != NULL) 1287184205Sdes free(sa, M_SONAME); 128883186Sjulian} 128983186Sjulian 129083186Sjulian/* 129153246Sarchie * Parse out either an integer value or an alias. 129253246Sarchie */ 129353246Sarchiestatic int 129453246Sarchieng_ksocket_parse(const struct ng_ksocket_alias *aliases, 129553246Sarchie const char *s, int family) 129653246Sarchie{ 129753246Sarchie int k, val; 129853648Sarchie char *eptr; 129953246Sarchie 130053246Sarchie /* Try aliases */ 130153246Sarchie for (k = 0; aliases[k].name != NULL; k++) { 130253246Sarchie if (strcmp(s, aliases[k].name) == 0 130353246Sarchie && aliases[k].family == family) 130453246Sarchie return aliases[k].value; 130553246Sarchie } 130653246Sarchie 130753246Sarchie /* Try parsing as a number */ 130853246Sarchie val = (int)strtoul(s, &eptr, 10); 130953913Sarchie if (val < 0 || *eptr != '\0') 131053246Sarchie return (-1); 131153246Sarchie return (val); 131253246Sarchie} 131353246Sarchie 1314