send.c revision 295126
1211501Sanchie/*- 2211501Sanchie * Copyright (c) 2009-2010 Ana Kukec <anchie@FreeBSD.org> 3211501Sanchie * All rights reserved. 4211501Sanchie * 5211501Sanchie * Redistribution and use in source and binary forms, with or without 6211501Sanchie * modification, are permitted provided that the following conditions 7211501Sanchie * are met: 8211501Sanchie * 1. Redistributions of source code must retain the above copyright 9211501Sanchie * notice, this list of conditions and the following disclaimer. 10211501Sanchie * 2. Redistributions in binary form must reproduce the above copyright 11211501Sanchie * notice, this list of conditions and the following disclaimer in the 12211501Sanchie * documentation and/or other materials provided with the distribution. 13211501Sanchie * 14211501Sanchie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15211501Sanchie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16211501Sanchie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17211501Sanchie * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18211501Sanchie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19211501Sanchie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20211501Sanchie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21211501Sanchie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22211501Sanchie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23211501Sanchie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24211501Sanchie * SUCH DAMAGE. 25211501Sanchie */ 26211501Sanchie 27211501Sanchie#include <sys/cdefs.h> 28211501Sanchie__FBSDID("$FreeBSD: head/sys/netinet6/send.c 295126 2016-02-01 17:41:21Z glebius $"); 29211501Sanchie 30211501Sanchie#include <sys/param.h> 31211501Sanchie#include <sys/kernel.h> 32295126Sglebius#include <sys/malloc.h> 33211501Sanchie#include <sys/mbuf.h> 34211501Sanchie#include <sys/module.h> 35211501Sanchie#include <sys/priv.h> 36211501Sanchie#include <sys/protosw.h> 37254889Smarkj#include <sys/sdt.h> 38211501Sanchie#include <sys/systm.h> 39211501Sanchie#include <sys/socket.h> 40211501Sanchie#include <sys/sockstate.h> 41211501Sanchie#include <sys/sockbuf.h> 42211501Sanchie#include <sys/socketvar.h> 43211501Sanchie#include <sys/types.h> 44211501Sanchie 45211501Sanchie#include <net/route.h> 46211501Sanchie#include <net/if.h> 47211501Sanchie#include <net/if_var.h> 48211501Sanchie#include <net/vnet.h> 49211501Sanchie 50211501Sanchie#include <netinet/in.h> 51254889Smarkj#include <netinet/in_kdtrace.h> 52211501Sanchie#include <netinet/ip_var.h> 53211501Sanchie#include <netinet/ip6.h> 54211501Sanchie#include <netinet/icmp6.h> 55211501Sanchie 56211501Sanchie#include <netinet6/in6_var.h> 57211501Sanchie#include <netinet6/nd6.h> 58211501Sanchie#include <netinet6/scope6_var.h> 59211501Sanchie#include <netinet6/send.h> 60211501Sanchie 61227293Sedstatic MALLOC_DEFINE(M_SEND, "send", "Secure Neighbour Discovery"); 62211501Sanchie 63211501Sanchie/* 64211501Sanchie * The socket used to communicate with the SeND daemon. 65211501Sanchie */ 66215701Sdimstatic VNET_DEFINE(struct socket *, send_so); 67211501Sanchie#define V_send_so VNET(send_so) 68211501Sanchie 69211501Sanchieu_long send_sendspace = 8 * (1024 + sizeof(struct sockaddr_send)); 70211501Sanchieu_long send_recvspace = 9216; 71211501Sanchie 72211501Sanchiestruct mtx send_mtx; 73211501Sanchie#define SEND_LOCK_INIT() mtx_init(&send_mtx, "send_mtx", NULL, MTX_DEF) 74211501Sanchie#define SEND_LOCK() mtx_lock(&send_mtx) 75211501Sanchie#define SEND_UNLOCK() mtx_unlock(&send_mtx) 76211501Sanchie#define SEND_LOCK_DESTROY() mtx_destroy(&send_mtx) 77211501Sanchie 78211501Sanchiestatic int 79211501Sanchiesend_attach(struct socket *so, int proto, struct thread *td) 80211501Sanchie{ 81211501Sanchie int error; 82211501Sanchie 83211501Sanchie SEND_LOCK(); 84211501Sanchie if (V_send_so != NULL) { 85211501Sanchie SEND_UNLOCK(); 86211501Sanchie return (EEXIST); 87211501Sanchie } 88211501Sanchie 89211501Sanchie error = priv_check(td, PRIV_NETINET_RAW); 90211501Sanchie if (error) { 91211501Sanchie SEND_UNLOCK(); 92211501Sanchie return(error); 93211501Sanchie } 94211501Sanchie 95211501Sanchie if (proto != IPPROTO_SEND) { 96211501Sanchie SEND_UNLOCK(); 97211501Sanchie return (EPROTONOSUPPORT); 98211501Sanchie } 99211501Sanchie error = soreserve(so, send_sendspace, send_recvspace); 100211501Sanchie if (error) { 101211501Sanchie SEND_UNLOCK(); 102211501Sanchie return(error); 103211501Sanchie } 104211501Sanchie 105211501Sanchie V_send_so = so; 106211501Sanchie SEND_UNLOCK(); 107211501Sanchie 108211501Sanchie return (0); 109211501Sanchie} 110211501Sanchie 111211501Sanchiestatic int 112211501Sanchiesend_output(struct mbuf *m, struct ifnet *ifp, int direction) 113211501Sanchie{ 114211501Sanchie struct ip6_hdr *ip6; 115211501Sanchie struct sockaddr_in6 dst; 116211501Sanchie struct icmp6_hdr *icmp6; 117211501Sanchie int icmp6len; 118211501Sanchie 119211501Sanchie /* 120211501Sanchie * Receive incoming (SeND-protected) or outgoing traffic 121211501Sanchie * (SeND-validated) from the SeND user space application. 122211501Sanchie */ 123211501Sanchie 124211501Sanchie switch (direction) { 125211501Sanchie case SND_IN: 126211501Sanchie if (m->m_len < (sizeof(struct ip6_hdr) + 127211501Sanchie sizeof(struct icmp6_hdr))) { 128211501Sanchie m = m_pullup(m, sizeof(struct ip6_hdr) + 129211501Sanchie sizeof(struct icmp6_hdr)); 130211501Sanchie if (!m) 131211501Sanchie return (ENOBUFS); 132211501Sanchie } 133211501Sanchie 134211501Sanchie /* Before passing off the mbuf record the proper interface. */ 135211501Sanchie m->m_pkthdr.rcvif = ifp; 136211501Sanchie 137211501Sanchie if (m->m_flags & M_PKTHDR) 138211501Sanchie icmp6len = m->m_pkthdr.len - sizeof(struct ip6_hdr); 139211501Sanchie else 140211501Sanchie panic("Doh! not the first mbuf."); 141211501Sanchie 142211501Sanchie ip6 = mtod(m, struct ip6_hdr *); 143211501Sanchie icmp6 = (struct icmp6_hdr *)(ip6 + 1); 144211501Sanchie 145211501Sanchie /* 146211501Sanchie * Output the packet as icmp6.c:icpm6_input() would do. 147211501Sanchie * The mbuf is always consumed, so we do not have to 148211501Sanchie * care about that. 149211501Sanchie */ 150211501Sanchie switch (icmp6->icmp6_type) { 151211501Sanchie case ND_NEIGHBOR_SOLICIT: 152211501Sanchie nd6_ns_input(m, sizeof(struct ip6_hdr), icmp6len); 153211501Sanchie break; 154211501Sanchie case ND_NEIGHBOR_ADVERT: 155211501Sanchie nd6_na_input(m, sizeof(struct ip6_hdr), icmp6len); 156211501Sanchie break; 157211501Sanchie case ND_REDIRECT: 158211501Sanchie icmp6_redirect_input(m, sizeof(struct ip6_hdr)); 159211501Sanchie break; 160211501Sanchie case ND_ROUTER_SOLICIT: 161211501Sanchie nd6_rs_input(m, sizeof(struct ip6_hdr), icmp6len); 162211501Sanchie break; 163211501Sanchie case ND_ROUTER_ADVERT: 164211501Sanchie nd6_ra_input(m, sizeof(struct ip6_hdr), icmp6len); 165211501Sanchie break; 166211501Sanchie default: 167259503Sae m_freem(m); 168211501Sanchie return (ENOSYS); 169211501Sanchie } 170211501Sanchie return (0); 171211501Sanchie 172211501Sanchie case SND_OUT: 173211501Sanchie if (m->m_len < sizeof(struct ip6_hdr)) { 174211501Sanchie m = m_pullup(m, sizeof(struct ip6_hdr)); 175211501Sanchie if (!m) 176211501Sanchie return (ENOBUFS); 177211501Sanchie } 178211501Sanchie ip6 = mtod(m, struct ip6_hdr *); 179211501Sanchie if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 180211501Sanchie m->m_flags |= M_MCAST; 181211501Sanchie 182211501Sanchie bzero(&dst, sizeof(dst)); 183211501Sanchie dst.sin6_family = AF_INET6; 184211501Sanchie dst.sin6_len = sizeof(dst); 185211501Sanchie dst.sin6_addr = ip6->ip6_dst; 186211501Sanchie 187254523Sandre m_clrprotoflags(m); /* Avoid confusing lower layers. */ 188254523Sandre 189254889Smarkj IP_PROBE(send, NULL, NULL, ip6, ifp, NULL, ip6); 190254889Smarkj 191211501Sanchie /* 192211501Sanchie * Output the packet as nd6.c:nd6_output_lle() would do. 193211501Sanchie * The mbuf is always consumed, so we do not have to care 194211501Sanchie * about that. 195211501Sanchie * XXX-BZ as we added data, what about fragmenting, 196211501Sanchie * if now needed? 197211501Sanchie */ 198211501Sanchie int error; 199211501Sanchie error = ((*ifp->if_output)(ifp, m, (struct sockaddr *)&dst, 200211501Sanchie NULL)); 201211501Sanchie if (error) 202211501Sanchie error = ENOENT; 203211501Sanchie return (error); 204211501Sanchie 205211501Sanchie default: 206211501Sanchie panic("%s: direction %d neither SND_IN nor SND_OUT.", 207211501Sanchie __func__, direction); 208211501Sanchie } 209211501Sanchie} 210211501Sanchie 211211501Sanchie/* 212211501Sanchie * Receive a SeND message from user space to be either send out by the kernel 213211501Sanchie * or, with SeND ICMPv6 options removed, to be further processed by the icmp6 214211501Sanchie * input path. 215211501Sanchie */ 216211501Sanchiestatic int 217211501Sanchiesend_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 218211501Sanchie struct mbuf *control, struct thread *td) 219211501Sanchie{ 220211501Sanchie struct sockaddr_send *sendsrc; 221211501Sanchie struct ifnet *ifp; 222211501Sanchie int error; 223211501Sanchie 224211501Sanchie KASSERT(V_send_so == so, ("%s: socket %p not send socket %p", 225211501Sanchie __func__, so, V_send_so)); 226211501Sanchie 227211501Sanchie sendsrc = (struct sockaddr_send *)nam; 228211501Sanchie ifp = ifnet_byindex_ref(sendsrc->send_ifidx); 229211501Sanchie if (ifp == NULL) { 230211501Sanchie error = ENETUNREACH; 231211501Sanchie goto err; 232211501Sanchie } 233211501Sanchie 234211501Sanchie error = send_output(m, ifp, sendsrc->send_direction); 235211501Sanchie if_rele(ifp); 236211501Sanchie m = NULL; 237211501Sanchie 238211501Sanchieerr: 239211501Sanchie if (m != NULL) 240211501Sanchie m_freem(m); 241211501Sanchie return (error); 242211501Sanchie} 243211501Sanchie 244211501Sanchiestatic void 245211501Sanchiesend_close(struct socket *so) 246211501Sanchie{ 247211501Sanchie 248211501Sanchie SEND_LOCK(); 249211501Sanchie if (V_send_so) 250211501Sanchie V_send_so = NULL; 251211501Sanchie SEND_UNLOCK(); 252211501Sanchie} 253211501Sanchie 254211501Sanchie/* 255211501Sanchie * Send a SeND message to user space, that was either received and has to be 256211501Sanchie * validated or was about to be send out and has to be handled by the SEND 257211501Sanchie * daemon adding SeND ICMPv6 options. 258211501Sanchie */ 259211501Sanchiestatic int 260211501Sanchiesend_input(struct mbuf *m, struct ifnet *ifp, int direction, int msglen __unused) 261211501Sanchie{ 262211501Sanchie struct ip6_hdr *ip6; 263211501Sanchie struct sockaddr_send sendsrc; 264211501Sanchie 265211501Sanchie SEND_LOCK(); 266211501Sanchie if (V_send_so == NULL) { 267211501Sanchie SEND_UNLOCK(); 268211501Sanchie return (-1); 269211501Sanchie } 270211501Sanchie 271211501Sanchie /* 272211501Sanchie * Make sure to clear any possible internally embedded scope before 273211501Sanchie * passing the packet to user space for SeND cryptographic signature 274211501Sanchie * validation to succeed. 275211501Sanchie */ 276211501Sanchie ip6 = mtod(m, struct ip6_hdr *); 277211501Sanchie in6_clearscope(&ip6->ip6_src); 278211501Sanchie in6_clearscope(&ip6->ip6_dst); 279211501Sanchie 280211501Sanchie bzero(&sendsrc, sizeof(sendsrc)); 281211501Sanchie sendsrc.send_len = sizeof(sendsrc); 282211501Sanchie sendsrc.send_family = AF_INET6; 283211501Sanchie sendsrc.send_direction = direction; 284211501Sanchie sendsrc.send_ifidx = ifp->if_index; 285211501Sanchie 286211501Sanchie /* 287211501Sanchie * Send incoming or outgoing traffic to user space either to be 288211501Sanchie * protected (outgoing) or validated (incoming) according to rfc3971. 289211501Sanchie */ 290211501Sanchie SOCKBUF_LOCK(&V_send_so->so_rcv); 291211501Sanchie if (sbappendaddr_locked(&V_send_so->so_rcv, 292211501Sanchie (struct sockaddr *)&sendsrc, m, NULL) == 0) { 293211501Sanchie SOCKBUF_UNLOCK(&V_send_so->so_rcv); 294211501Sanchie /* XXX stats. */ 295211501Sanchie m_freem(m); 296211501Sanchie } else { 297211501Sanchie sorwakeup_locked(V_send_so); 298211501Sanchie } 299211501Sanchie 300211501Sanchie SEND_UNLOCK(); 301211501Sanchie return (0); 302211501Sanchie} 303211501Sanchie 304211501Sanchiestruct pr_usrreqs send_usrreqs = { 305211501Sanchie .pru_attach = send_attach, 306211501Sanchie .pru_send = send_send, 307211501Sanchie .pru_detach = send_close 308211501Sanchie}; 309211501Sanchiestruct protosw send_protosw = { 310211501Sanchie .pr_type = SOCK_RAW, 311211501Sanchie .pr_flags = PR_ATOMIC|PR_ADDR, 312211501Sanchie .pr_protocol = IPPROTO_SEND, 313211501Sanchie .pr_usrreqs = &send_usrreqs 314211501Sanchie}; 315211501Sanchie 316211501Sanchiestatic int 317211501Sanchiesend_modevent(module_t mod, int type, void *unused) 318211501Sanchie{ 319211501Sanchie#ifdef __notyet__ 320211501Sanchie VNET_ITERATOR_DECL(vnet_iter); 321211501Sanchie#endif 322211501Sanchie int error; 323211501Sanchie 324211501Sanchie switch (type) { 325211501Sanchie case MOD_LOAD: 326211501Sanchie SEND_LOCK_INIT(); 327211501Sanchie 328211501Sanchie error = pf_proto_register(PF_INET6, &send_protosw); 329211501Sanchie if (error != 0) { 330211501Sanchie printf("%s:%d: MOD_LOAD pf_proto_register(): %d\n", 331211501Sanchie __func__, __LINE__, error); 332211501Sanchie SEND_LOCK_DESTROY(); 333211501Sanchie break; 334211501Sanchie } 335211501Sanchie send_sendso_input_hook = send_input; 336211501Sanchie break; 337211501Sanchie case MOD_UNLOAD: 338211501Sanchie /* Do not allow unloading w/o locking. */ 339211501Sanchie return (EBUSY); 340211501Sanchie#ifdef __notyet__ 341211501Sanchie VNET_LIST_RLOCK_NOSLEEP(); 342211501Sanchie SEND_LOCK(); 343211501Sanchie VNET_FOREACH(vnet_iter) { 344211501Sanchie CURVNET_SET(vnet_iter); 345211501Sanchie if (V_send_so != NULL) { 346211501Sanchie CURVNET_RESTORE(); 347211501Sanchie SEND_UNLOCK(); 348211501Sanchie VNET_LIST_RUNLOCK_NOSLEEP(); 349211501Sanchie return (EBUSY); 350211501Sanchie } 351211501Sanchie CURVNET_RESTORE(); 352211501Sanchie } 353211501Sanchie SEND_UNLOCK(); 354211501Sanchie VNET_LIST_RUNLOCK_NOSLEEP(); 355211501Sanchie error = pf_proto_unregister(PF_INET6, IPPROTO_SEND, SOCK_RAW); 356211501Sanchie if (error == 0) 357211501Sanchie SEND_LOCK_DESTROY(); 358211501Sanchie send_sendso_input_hook = NULL; 359211501Sanchie break; 360211501Sanchie#endif 361211501Sanchie default: 362211501Sanchie error = 0; 363211501Sanchie break; 364211501Sanchie } 365211501Sanchie 366211501Sanchie return (error); 367211501Sanchie} 368211501Sanchie 369211501Sanchiestatic moduledata_t sendmod = { 370211501Sanchie "send", 371211501Sanchie send_modevent, 372241394Skevlo 0 373211501Sanchie}; 374211501Sanchie 375211501SanchieDECLARE_MODULE(send, sendmod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 376