send.c revision 241394
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 241394 2012-10-10 08:36:38Z kevlo $"); 29211501Sanchie 30211501Sanchie#include <sys/param.h> 31211501Sanchie#include <sys/kernel.h> 32211501Sanchie#include <sys/mbuf.h> 33211501Sanchie#include <sys/module.h> 34211501Sanchie#include <sys/priv.h> 35211501Sanchie#include <sys/protosw.h> 36211501Sanchie#include <sys/systm.h> 37211501Sanchie#include <sys/socket.h> 38211501Sanchie#include <sys/sockstate.h> 39211501Sanchie#include <sys/sockbuf.h> 40211501Sanchie#include <sys/socketvar.h> 41211501Sanchie#include <sys/types.h> 42211501Sanchie 43211501Sanchie#include <net/route.h> 44211501Sanchie#include <net/if.h> 45211501Sanchie#include <net/if_var.h> 46211501Sanchie#include <net/vnet.h> 47211501Sanchie 48211501Sanchie#include <netinet/in.h> 49211501Sanchie#include <netinet/ip_var.h> 50211501Sanchie#include <netinet/ip6.h> 51211501Sanchie#include <netinet/icmp6.h> 52211501Sanchie 53211501Sanchie#include <netinet6/in6_var.h> 54211501Sanchie#include <netinet6/nd6.h> 55211501Sanchie#include <netinet6/scope6_var.h> 56211501Sanchie#include <netinet6/send.h> 57211501Sanchie 58227293Sedstatic MALLOC_DEFINE(M_SEND, "send", "Secure Neighbour Discovery"); 59211501Sanchie 60211501Sanchie/* 61211501Sanchie * The socket used to communicate with the SeND daemon. 62211501Sanchie */ 63215701Sdimstatic VNET_DEFINE(struct socket *, send_so); 64211501Sanchie#define V_send_so VNET(send_so) 65211501Sanchie 66211501Sanchieu_long send_sendspace = 8 * (1024 + sizeof(struct sockaddr_send)); 67211501Sanchieu_long send_recvspace = 9216; 68211501Sanchie 69211501Sanchiestruct mtx send_mtx; 70211501Sanchie#define SEND_LOCK_INIT() mtx_init(&send_mtx, "send_mtx", NULL, MTX_DEF) 71211501Sanchie#define SEND_LOCK() mtx_lock(&send_mtx) 72211501Sanchie#define SEND_UNLOCK() mtx_unlock(&send_mtx) 73211501Sanchie#define SEND_LOCK_DESTROY() mtx_destroy(&send_mtx) 74211501Sanchie 75211501Sanchiestatic int 76211501Sanchiesend_attach(struct socket *so, int proto, struct thread *td) 77211501Sanchie{ 78211501Sanchie int error; 79211501Sanchie 80211501Sanchie SEND_LOCK(); 81211501Sanchie if (V_send_so != NULL) { 82211501Sanchie SEND_UNLOCK(); 83211501Sanchie return (EEXIST); 84211501Sanchie } 85211501Sanchie 86211501Sanchie error = priv_check(td, PRIV_NETINET_RAW); 87211501Sanchie if (error) { 88211501Sanchie SEND_UNLOCK(); 89211501Sanchie return(error); 90211501Sanchie } 91211501Sanchie 92211501Sanchie if (proto != IPPROTO_SEND) { 93211501Sanchie SEND_UNLOCK(); 94211501Sanchie return (EPROTONOSUPPORT); 95211501Sanchie } 96211501Sanchie error = soreserve(so, send_sendspace, send_recvspace); 97211501Sanchie if (error) { 98211501Sanchie SEND_UNLOCK(); 99211501Sanchie return(error); 100211501Sanchie } 101211501Sanchie 102211501Sanchie V_send_so = so; 103211501Sanchie SEND_UNLOCK(); 104211501Sanchie 105211501Sanchie return (0); 106211501Sanchie} 107211501Sanchie 108211501Sanchiestatic int 109211501Sanchiesend_output(struct mbuf *m, struct ifnet *ifp, int direction) 110211501Sanchie{ 111211501Sanchie struct ip6_hdr *ip6; 112211501Sanchie struct sockaddr_in6 dst; 113211501Sanchie struct icmp6_hdr *icmp6; 114211501Sanchie int icmp6len; 115211501Sanchie 116211501Sanchie /* 117211501Sanchie * Receive incoming (SeND-protected) or outgoing traffic 118211501Sanchie * (SeND-validated) from the SeND user space application. 119211501Sanchie */ 120211501Sanchie 121211501Sanchie switch (direction) { 122211501Sanchie case SND_IN: 123211501Sanchie if (m->m_len < (sizeof(struct ip6_hdr) + 124211501Sanchie sizeof(struct icmp6_hdr))) { 125211501Sanchie m = m_pullup(m, sizeof(struct ip6_hdr) + 126211501Sanchie sizeof(struct icmp6_hdr)); 127211501Sanchie if (!m) 128211501Sanchie return (ENOBUFS); 129211501Sanchie } 130211501Sanchie 131211501Sanchie /* Before passing off the mbuf record the proper interface. */ 132211501Sanchie m->m_pkthdr.rcvif = ifp; 133211501Sanchie 134211501Sanchie if (m->m_flags & M_PKTHDR) 135211501Sanchie icmp6len = m->m_pkthdr.len - sizeof(struct ip6_hdr); 136211501Sanchie else 137211501Sanchie panic("Doh! not the first mbuf."); 138211501Sanchie 139211501Sanchie ip6 = mtod(m, struct ip6_hdr *); 140211501Sanchie icmp6 = (struct icmp6_hdr *)(ip6 + 1); 141211501Sanchie 142211501Sanchie /* 143211501Sanchie * Output the packet as icmp6.c:icpm6_input() would do. 144211501Sanchie * The mbuf is always consumed, so we do not have to 145211501Sanchie * care about that. 146211501Sanchie */ 147211501Sanchie switch (icmp6->icmp6_type) { 148211501Sanchie case ND_NEIGHBOR_SOLICIT: 149211501Sanchie nd6_ns_input(m, sizeof(struct ip6_hdr), icmp6len); 150211501Sanchie break; 151211501Sanchie case ND_NEIGHBOR_ADVERT: 152211501Sanchie nd6_na_input(m, sizeof(struct ip6_hdr), icmp6len); 153211501Sanchie break; 154211501Sanchie case ND_REDIRECT: 155211501Sanchie icmp6_redirect_input(m, sizeof(struct ip6_hdr)); 156211501Sanchie break; 157211501Sanchie case ND_ROUTER_SOLICIT: 158211501Sanchie nd6_rs_input(m, sizeof(struct ip6_hdr), icmp6len); 159211501Sanchie break; 160211501Sanchie case ND_ROUTER_ADVERT: 161211501Sanchie nd6_ra_input(m, sizeof(struct ip6_hdr), icmp6len); 162211501Sanchie break; 163211501Sanchie default: 164211501Sanchie return (ENOSYS); 165211501Sanchie } 166211501Sanchie return (0); 167211501Sanchie 168211501Sanchie case SND_OUT: 169211501Sanchie if (m->m_len < sizeof(struct ip6_hdr)) { 170211501Sanchie m = m_pullup(m, sizeof(struct ip6_hdr)); 171211501Sanchie if (!m) 172211501Sanchie return (ENOBUFS); 173211501Sanchie } 174211501Sanchie ip6 = mtod(m, struct ip6_hdr *); 175211501Sanchie if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 176211501Sanchie m->m_flags |= M_MCAST; 177211501Sanchie 178211501Sanchie bzero(&dst, sizeof(dst)); 179211501Sanchie dst.sin6_family = AF_INET6; 180211501Sanchie dst.sin6_len = sizeof(dst); 181211501Sanchie dst.sin6_addr = ip6->ip6_dst; 182211501Sanchie 183211501Sanchie /* 184211501Sanchie * Output the packet as nd6.c:nd6_output_lle() would do. 185211501Sanchie * The mbuf is always consumed, so we do not have to care 186211501Sanchie * about that. 187211501Sanchie * XXX-BZ as we added data, what about fragmenting, 188211501Sanchie * if now needed? 189211501Sanchie */ 190211501Sanchie int error; 191211501Sanchie error = ((*ifp->if_output)(ifp, m, (struct sockaddr *)&dst, 192211501Sanchie NULL)); 193211501Sanchie if (error) 194211501Sanchie error = ENOENT; 195211501Sanchie return (error); 196211501Sanchie 197211501Sanchie default: 198211501Sanchie panic("%s: direction %d neither SND_IN nor SND_OUT.", 199211501Sanchie __func__, direction); 200211501Sanchie } 201211501Sanchie} 202211501Sanchie 203211501Sanchie/* 204211501Sanchie * Receive a SeND message from user space to be either send out by the kernel 205211501Sanchie * or, with SeND ICMPv6 options removed, to be further processed by the icmp6 206211501Sanchie * input path. 207211501Sanchie */ 208211501Sanchiestatic int 209211501Sanchiesend_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 210211501Sanchie struct mbuf *control, struct thread *td) 211211501Sanchie{ 212211501Sanchie struct sockaddr_send *sendsrc; 213211501Sanchie struct ifnet *ifp; 214211501Sanchie int error; 215211501Sanchie 216211501Sanchie KASSERT(V_send_so == so, ("%s: socket %p not send socket %p", 217211501Sanchie __func__, so, V_send_so)); 218211501Sanchie 219211501Sanchie sendsrc = (struct sockaddr_send *)nam; 220211501Sanchie ifp = ifnet_byindex_ref(sendsrc->send_ifidx); 221211501Sanchie if (ifp == NULL) { 222211501Sanchie error = ENETUNREACH; 223211501Sanchie goto err; 224211501Sanchie } 225211501Sanchie 226211501Sanchie error = send_output(m, ifp, sendsrc->send_direction); 227211501Sanchie if_rele(ifp); 228211501Sanchie m = NULL; 229211501Sanchie 230211501Sanchieerr: 231211501Sanchie if (m != NULL) 232211501Sanchie m_freem(m); 233211501Sanchie return (error); 234211501Sanchie} 235211501Sanchie 236211501Sanchiestatic void 237211501Sanchiesend_close(struct socket *so) 238211501Sanchie{ 239211501Sanchie 240211501Sanchie SEND_LOCK(); 241211501Sanchie if (V_send_so) 242211501Sanchie V_send_so = NULL; 243211501Sanchie SEND_UNLOCK(); 244211501Sanchie} 245211501Sanchie 246211501Sanchie/* 247211501Sanchie * Send a SeND message to user space, that was either received and has to be 248211501Sanchie * validated or was about to be send out and has to be handled by the SEND 249211501Sanchie * daemon adding SeND ICMPv6 options. 250211501Sanchie */ 251211501Sanchiestatic int 252211501Sanchiesend_input(struct mbuf *m, struct ifnet *ifp, int direction, int msglen __unused) 253211501Sanchie{ 254211501Sanchie struct ip6_hdr *ip6; 255211501Sanchie struct sockaddr_send sendsrc; 256211501Sanchie 257211501Sanchie SEND_LOCK(); 258211501Sanchie if (V_send_so == NULL) { 259211501Sanchie SEND_UNLOCK(); 260211501Sanchie return (-1); 261211501Sanchie } 262211501Sanchie 263211501Sanchie /* 264211501Sanchie * Make sure to clear any possible internally embedded scope before 265211501Sanchie * passing the packet to user space for SeND cryptographic signature 266211501Sanchie * validation to succeed. 267211501Sanchie */ 268211501Sanchie ip6 = mtod(m, struct ip6_hdr *); 269211501Sanchie in6_clearscope(&ip6->ip6_src); 270211501Sanchie in6_clearscope(&ip6->ip6_dst); 271211501Sanchie 272211501Sanchie bzero(&sendsrc, sizeof(sendsrc)); 273211501Sanchie sendsrc.send_len = sizeof(sendsrc); 274211501Sanchie sendsrc.send_family = AF_INET6; 275211501Sanchie sendsrc.send_direction = direction; 276211501Sanchie sendsrc.send_ifidx = ifp->if_index; 277211501Sanchie 278211501Sanchie /* 279211501Sanchie * Send incoming or outgoing traffic to user space either to be 280211501Sanchie * protected (outgoing) or validated (incoming) according to rfc3971. 281211501Sanchie */ 282211501Sanchie SOCKBUF_LOCK(&V_send_so->so_rcv); 283211501Sanchie if (sbappendaddr_locked(&V_send_so->so_rcv, 284211501Sanchie (struct sockaddr *)&sendsrc, m, NULL) == 0) { 285211501Sanchie SOCKBUF_UNLOCK(&V_send_so->so_rcv); 286211501Sanchie /* XXX stats. */ 287211501Sanchie m_freem(m); 288211501Sanchie } else { 289211501Sanchie sorwakeup_locked(V_send_so); 290211501Sanchie } 291211501Sanchie 292211501Sanchie SEND_UNLOCK(); 293211501Sanchie return (0); 294211501Sanchie} 295211501Sanchie 296211501Sanchiestruct pr_usrreqs send_usrreqs = { 297211501Sanchie .pru_attach = send_attach, 298211501Sanchie .pru_send = send_send, 299211501Sanchie .pru_detach = send_close 300211501Sanchie}; 301211501Sanchiestruct protosw send_protosw = { 302211501Sanchie .pr_type = SOCK_RAW, 303211501Sanchie .pr_flags = PR_ATOMIC|PR_ADDR, 304211501Sanchie .pr_protocol = IPPROTO_SEND, 305211501Sanchie .pr_usrreqs = &send_usrreqs 306211501Sanchie}; 307211501Sanchie 308211501Sanchiestatic int 309211501Sanchiesend_modevent(module_t mod, int type, void *unused) 310211501Sanchie{ 311211501Sanchie#ifdef __notyet__ 312211501Sanchie VNET_ITERATOR_DECL(vnet_iter); 313211501Sanchie#endif 314211501Sanchie int error; 315211501Sanchie 316211501Sanchie switch (type) { 317211501Sanchie case MOD_LOAD: 318211501Sanchie SEND_LOCK_INIT(); 319211501Sanchie 320211501Sanchie error = pf_proto_register(PF_INET6, &send_protosw); 321211501Sanchie if (error != 0) { 322211501Sanchie printf("%s:%d: MOD_LOAD pf_proto_register(): %d\n", 323211501Sanchie __func__, __LINE__, error); 324211501Sanchie SEND_LOCK_DESTROY(); 325211501Sanchie break; 326211501Sanchie } 327211501Sanchie send_sendso_input_hook = send_input; 328211501Sanchie break; 329211501Sanchie case MOD_UNLOAD: 330211501Sanchie /* Do not allow unloading w/o locking. */ 331211501Sanchie return (EBUSY); 332211501Sanchie#ifdef __notyet__ 333211501Sanchie VNET_LIST_RLOCK_NOSLEEP(); 334211501Sanchie SEND_LOCK(); 335211501Sanchie VNET_FOREACH(vnet_iter) { 336211501Sanchie CURVNET_SET(vnet_iter); 337211501Sanchie if (V_send_so != NULL) { 338211501Sanchie CURVNET_RESTORE(); 339211501Sanchie SEND_UNLOCK(); 340211501Sanchie VNET_LIST_RUNLOCK_NOSLEEP(); 341211501Sanchie return (EBUSY); 342211501Sanchie } 343211501Sanchie CURVNET_RESTORE(); 344211501Sanchie } 345211501Sanchie SEND_UNLOCK(); 346211501Sanchie VNET_LIST_RUNLOCK_NOSLEEP(); 347211501Sanchie error = pf_proto_unregister(PF_INET6, IPPROTO_SEND, SOCK_RAW); 348211501Sanchie if (error == 0) 349211501Sanchie SEND_LOCK_DESTROY(); 350211501Sanchie send_sendso_input_hook = NULL; 351211501Sanchie break; 352211501Sanchie#endif 353211501Sanchie default: 354211501Sanchie error = 0; 355211501Sanchie break; 356211501Sanchie } 357211501Sanchie 358211501Sanchie return (error); 359211501Sanchie} 360211501Sanchie 361211501Sanchiestatic moduledata_t sendmod = { 362211501Sanchie "send", 363211501Sanchie send_modevent, 364241394Skevlo 0 365211501Sanchie}; 366211501Sanchie 367211501SanchieDECLARE_MODULE(send, sendmod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 368