raw_ip6.c revision 121472
1221828Sgrehan/* 2221828Sgrehan * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3221828Sgrehan * All rights reserved. 4221828Sgrehan * 5221828Sgrehan * Redistribution and use in source and binary forms, with or without 6221828Sgrehan * modification, are permitted provided that the following conditions 7221828Sgrehan * are met: 8221828Sgrehan * 1. Redistributions of source code must retain the above copyright 9221828Sgrehan * notice, this list of conditions and the following disclaimer. 10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11221828Sgrehan * notice, this list of conditions and the following disclaimer in the 12221828Sgrehan * documentation and/or other materials provided with the distribution. 13221828Sgrehan * 3. Neither the name of the project nor the names of its contributors 14221828Sgrehan * may be used to endorse or promote products derived from this software 15221828Sgrehan * without specific prior written permission. 16221828Sgrehan * 17221828Sgrehan * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20221828Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27221828Sgrehan * SUCH DAMAGE. 28221828Sgrehan * 29222605Sjhb * $FreeBSD: head/sys/netinet6/raw_ip6.c 121472 2003-10-24 18:26:30Z ume $ 30222605Sjhb */ 31221828Sgrehan 32221828Sgrehan/* 33221828Sgrehan * Copyright (c) 1982, 1986, 1988, 1993 34221828Sgrehan * The Regents of the University of California. All rights reserved. 35330713Stychon * 36221828Sgrehan * Redistribution and use in source and binary forms, with or without 37221828Sgrehan * modification, are permitted provided that the following conditions 38221828Sgrehan * are met: 39221828Sgrehan * 1. Redistributions of source code must retain the above copyright 40221828Sgrehan * notice, this list of conditions and the following disclaimer. 41221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 42221828Sgrehan * notice, this list of conditions and the following disclaimer in the 43221828Sgrehan * documentation and/or other materials provided with the distribution. 44242275Sneel * 3. All advertising materials mentioning features or use of this software 45262352Sjhb * must display the following acknowledgement: 46221828Sgrehan * This product includes software developed by the University of 47221828Sgrehan * California, Berkeley and its contributors. 48221828Sgrehan * 4. Neither the name of the University nor the names of its contributors 49221828Sgrehan * may be used to endorse or promote products derived from this software 50222605Sjhb * without specific prior written permission. 51222605Sjhb * 52222605Sjhb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53222605Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54330713Stychon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55330713Stychon * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56330713Stychon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57330713Stychon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58330713Stychon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59330713Stychon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62221828Sgrehan * SUCH DAMAGE. 63221828Sgrehan * 64221828Sgrehan * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 65221828Sgrehan */ 66221828Sgrehan 67221828Sgrehan#include "opt_ipsec.h" 68221828Sgrehan#include "opt_inet6.h" 69221828Sgrehan 70221828Sgrehan#include <sys/param.h> 71221828Sgrehan#include <sys/errno.h> 72221828Sgrehan#include <sys/lock.h> 73221828Sgrehan#include <sys/malloc.h> 74221828Sgrehan#include <sys/mbuf.h> 75221828Sgrehan#include <sys/proc.h> 76221828Sgrehan#include <sys/protosw.h> 77221828Sgrehan#include <sys/signalvar.h> 78221828Sgrehan#include <sys/socket.h> 79221828Sgrehan#include <sys/socketvar.h> 80221828Sgrehan#include <sys/sx.h> 81221828Sgrehan#include <sys/systm.h> 82221828Sgrehan 83221828Sgrehan#include <net/if.h> 84221828Sgrehan#include <net/if_types.h> 85221828Sgrehan#include <net/route.h> 86221828Sgrehan 87221828Sgrehan#include <netinet/in.h> 88221828Sgrehan#include <netinet/in_var.h> 89221828Sgrehan#include <netinet/in_systm.h> 90221828Sgrehan#include <netinet/icmp6.h> 91221828Sgrehan#include <netinet/in_pcb.h> 92221828Sgrehan#include <netinet/ip6.h> 93221828Sgrehan#include <netinet6/ip6protosw.h> 94221828Sgrehan#include <netinet6/ip6_mroute.h> 95221828Sgrehan#include <netinet6/in6_pcb.h> 96221828Sgrehan#include <netinet6/ip6_var.h> 97221828Sgrehan#include <netinet6/nd6.h> 98221828Sgrehan#include <netinet6/raw_ip6.h> 99221828Sgrehan#ifdef ENABLE_DEFAULT_SCOPE 100221828Sgrehan#include <netinet6/scope6_var.h> 101221828Sgrehan#endif 102221828Sgrehan 103221828Sgrehan#ifdef IPSEC 104221828Sgrehan#include <netinet6/ipsec.h> 105221828Sgrehan#include <netinet6/ipsec6.h> 106221828Sgrehan#endif /*IPSEC*/ 107221828Sgrehan 108221828Sgrehan#ifdef FAST_IPSEC 109221828Sgrehan#include <netipsec/ipsec.h> 110221828Sgrehan#include <netipsec/ipsec6.h> 111221828Sgrehan#endif /* FAST_IPSEC */ 112221828Sgrehan 113270159Sgrehan#include <machine/stdarg.h> 114270159Sgrehan 115270159Sgrehan#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) 116270159Sgrehan#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) 117270159Sgrehan 118270159Sgrehan/* 119270159Sgrehan * Raw interface to IP6 protocol. 120270159Sgrehan */ 121221828Sgrehan 122221828Sgrehanextern struct inpcbhead ripcb; 123221828Sgrehanextern struct inpcbinfo ripcbinfo; 124221828Sgrehanextern u_long rip_sendspace; 125221828Sgrehanextern u_long rip_recvspace; 126221828Sgrehan 127221828Sgrehanstruct rip6stat rip6stat; 128221828Sgrehan 129221828Sgrehan/* 130221828Sgrehan * Setup generic address and protocol structures 131221828Sgrehan * for raw_input routine, then pass them along with 132221828Sgrehan * mbuf chain. 133221828Sgrehan */ 134221828Sgrehanint 135221828Sgrehanrip6_input(mp, offp, proto) 136221828Sgrehan struct mbuf **mp; 137221828Sgrehan int *offp, proto; 138221828Sgrehan{ 139221828Sgrehan struct mbuf *m = *mp; 140221828Sgrehan register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 141221828Sgrehan register struct inpcb *in6p; 142221828Sgrehan struct inpcb *last = 0; 143221828Sgrehan struct mbuf *opts = NULL; 144221828Sgrehan struct sockaddr_in6 rip6src; 145221828Sgrehan 146221828Sgrehan rip6stat.rip6s_ipackets++; 147221828Sgrehan 148221828Sgrehan if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) { 149221828Sgrehan /* XXX send icmp6 host/port unreach? */ 150221828Sgrehan m_freem(m); 151221828Sgrehan return IPPROTO_DONE; 152221828Sgrehan } 153221828Sgrehan 154221828Sgrehan init_sin6(&rip6src, m); /* general init */ 155221828Sgrehan 156221828Sgrehan LIST_FOREACH(in6p, &ripcb, inp_list) { 157221828Sgrehan if ((in6p->in6p_vflag & INP_IPV6) == 0) 158221828Sgrehan continue; 159221828Sgrehan if (in6p->in6p_ip6_nxt && 160221828Sgrehan in6p->in6p_ip6_nxt != proto) 161221828Sgrehan continue; 162221828Sgrehan if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && 163221828Sgrehan !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) 164221828Sgrehan continue; 165221828Sgrehan if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && 166221828Sgrehan !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) 167221828Sgrehan continue; 168221828Sgrehan if (in6p->in6p_cksum != -1) { 169221828Sgrehan rip6stat.rip6s_isum++; 170221828Sgrehan if (in6_cksum(m, ip6->ip6_nxt, *offp, 171221828Sgrehan m->m_pkthdr.len - *offp)) { 172221828Sgrehan rip6stat.rip6s_badsum++; 173221828Sgrehan continue; 174221828Sgrehan } 175221828Sgrehan } 176221828Sgrehan if (last) { 177221828Sgrehan struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 178221828Sgrehan 179221828Sgrehan#ifdef IPSEC 180221828Sgrehan /* 181221828Sgrehan * Check AH/ESP integrity. 182221828Sgrehan */ 183221828Sgrehan if (n && ipsec6_in_reject(n, last)) { 184221828Sgrehan m_freem(n); 185221828Sgrehan ipsec6stat.in_polvio++; 186221828Sgrehan /* do not inject data into pcb */ 187221828Sgrehan } else 188221828Sgrehan#endif /*IPSEC*/ 189221828Sgrehan#ifdef FAST_IPSEC 190249879Sgrehan /* 191221828Sgrehan * Check AH/ESP integrity. 192221828Sgrehan */ 193221828Sgrehan if (n && ipsec6_in_reject(n, last)) { 194221828Sgrehan m_freem(n); 195221828Sgrehan /* do not inject data into pcb */ 196221828Sgrehan } else 197221828Sgrehan#endif /*FAST_IPSEC*/ 198221828Sgrehan if (n) { 199221828Sgrehan if (last->in6p_flags & IN6P_CONTROLOPTS || 200221828Sgrehan last->in6p_socket->so_options & SO_TIMESTAMP) 201221828Sgrehan ip6_savecontrol(last, &opts, ip6, n); 202221828Sgrehan /* strip intermediate headers */ 203221828Sgrehan m_adj(n, *offp); 204221828Sgrehan if (sbappendaddr(&last->in6p_socket->so_rcv, 205221828Sgrehan (struct sockaddr *)&rip6src, 206221828Sgrehan n, opts) == 0) { 207221828Sgrehan m_freem(n); 208221828Sgrehan if (opts) 209221828Sgrehan m_freem(opts); 210249879Sgrehan rip6stat.rip6s_fullsock++; 211249879Sgrehan } else 212249879Sgrehan sorwakeup(last->in6p_socket); 213221828Sgrehan opts = NULL; 214249879Sgrehan } 215249879Sgrehan } 216249879Sgrehan last = in6p; 217249879Sgrehan } 218221828Sgrehan#ifdef IPSEC 219221828Sgrehan /* 220221828Sgrehan * Check AH/ESP integrity. 221221828Sgrehan */ 222249879Sgrehan if (last && ipsec6_in_reject(m, last)) { 223221828Sgrehan m_freem(m); 224221828Sgrehan ipsec6stat.in_polvio++; 225221828Sgrehan ip6stat.ip6s_delivered--; 226221828Sgrehan /* do not inject data into pcb */ 227221828Sgrehan } else 228221828Sgrehan#endif /*IPSEC*/ 229221828Sgrehan#ifdef FAST_IPSEC 230221828Sgrehan /* 231221828Sgrehan * Check AH/ESP integrity. 232221828Sgrehan */ 233221828Sgrehan if (last && ipsec6_in_reject(m, last)) { 234221828Sgrehan m_freem(m); 235221828Sgrehan ip6stat.ip6s_delivered--; 236221828Sgrehan /* do not inject data into pcb */ 237249879Sgrehan } else 238249879Sgrehan#endif /*FAST_IPSEC*/ 239249879Sgrehan if (last) { 240221828Sgrehan if (last->in6p_flags & IN6P_CONTROLOPTS || 241249879Sgrehan last->in6p_socket->so_options & SO_TIMESTAMP) 242249879Sgrehan ip6_savecontrol(last, &opts, ip6, m); 243249879Sgrehan /* strip intermediate headers */ 244249879Sgrehan m_adj(m, *offp); 245221828Sgrehan if (sbappendaddr(&last->in6p_socket->so_rcv, 246221828Sgrehan (struct sockaddr *)&rip6src, m, opts) == 0) { 247221828Sgrehan m_freem(m); 248221828Sgrehan if (opts) 249268953Sjhb m_freem(opts); 250221828Sgrehan rip6stat.rip6s_fullsock++; 251221828Sgrehan } else 252221828Sgrehan sorwakeup(last->in6p_socket); 253221828Sgrehan } else { 254221828Sgrehan rip6stat.rip6s_nosock++; 255221828Sgrehan if (m->m_flags & M_MCAST) 256221828Sgrehan rip6stat.rip6s_nosockmcast++; 257221828Sgrehan if (proto == IPPROTO_NONE) 258268953Sjhb m_freem(m); 259268953Sjhb else { 260221828Sgrehan char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ 261221828Sgrehan icmp6_error(m, ICMP6_PARAM_PROB, 262221828Sgrehan ICMP6_PARAMPROB_NEXTHEADER, 263221828Sgrehan prvnxtp - mtod(m, char *)); 264221828Sgrehan } 265221828Sgrehan ip6stat.ip6s_delivered--; 266221828Sgrehan } 267221828Sgrehan return IPPROTO_DONE; 268221828Sgrehan} 269221828Sgrehan 270221828Sgrehanvoid 271268953Sjhbrip6_ctlinput(cmd, sa, d) 272268953Sjhb int cmd; 273221828Sgrehan struct sockaddr *sa; 274221828Sgrehan void *d; 275221828Sgrehan{ 276221828Sgrehan struct ip6_hdr *ip6; 277268953Sjhb struct mbuf *m; 278221828Sgrehan int off = 0; 279221828Sgrehan struct ip6ctlparam *ip6cp = NULL; 280221828Sgrehan const struct sockaddr_in6 *sa6_src = NULL; 281221828Sgrehan struct inpcb *(*notify) __P((struct inpcb *, int)) = in6_rtchange; 282221828Sgrehan 283221828Sgrehan if (sa->sa_family != AF_INET6 || 284221828Sgrehan sa->sa_len != sizeof(struct sockaddr_in6)) 285221828Sgrehan return; 286221828Sgrehan 287268953Sjhb if ((unsigned)cmd >= PRC_NCMDS) 288268953Sjhb return; 289221828Sgrehan if (PRC_IS_REDIRECT(cmd)) 290221828Sgrehan notify = in6_rtchange, d = NULL; 291221828Sgrehan else if (cmd == PRC_HOSTDEAD) 292221828Sgrehan d = NULL; 293221828Sgrehan else if (inet6ctlerrmap[cmd] == 0) 294221828Sgrehan return; 295221828Sgrehan 296221828Sgrehan /* if the parameter is from icmp6, decode it. */ 297221828Sgrehan if (d != NULL) { 298221828Sgrehan ip6cp = (struct ip6ctlparam *)d; 299221828Sgrehan m = ip6cp->ip6c_m; 300221828Sgrehan ip6 = ip6cp->ip6c_ip6; 301221828Sgrehan off = ip6cp->ip6c_off; 302221828Sgrehan sa6_src = ip6cp->ip6c_src; 303268953Sjhb } else { 304268953Sjhb m = NULL; 305221828Sgrehan ip6 = NULL; 306221828Sgrehan sa6_src = &sa6_any; 307221828Sgrehan } 308221828Sgrehan 309221828Sgrehan (void) in6_pcbnotify(&ripcb, sa, 0, (const struct sockaddr *)sa6_src, 310221828Sgrehan 0, cmd, notify); 311221828Sgrehan} 312221828Sgrehan 313221828Sgrehan/* 314221828Sgrehan * Generate IPv6 header and pass packet to ip6_output. 315221828Sgrehan * Tack on options user may have setup with control call. 316221828Sgrehan */ 317221828Sgrehanint 318221828Sgrehan#if __STDC__ 319221828Sgrehanrip6_output(struct mbuf *m, ...) 320221828Sgrehan#else 321221828Sgrehanrip6_output(m, va_alist) 322221828Sgrehan struct mbuf *m; 323221828Sgrehan va_dcl 324221828Sgrehan#endif 325221828Sgrehan{ 326221828Sgrehan struct mbuf *control; 327221828Sgrehan struct socket *so; 328221828Sgrehan struct sockaddr_in6 *dstsock; 329221828Sgrehan struct in6_addr *dst; 330221828Sgrehan struct ip6_hdr *ip6; 331221828Sgrehan struct inpcb *in6p; 332221828Sgrehan u_int plen = m->m_pkthdr.len; 333221828Sgrehan int error = 0; 334221828Sgrehan struct ip6_pktopts opt, *stickyopt = NULL; 335221828Sgrehan struct ifnet *oifp = NULL; 336221828Sgrehan int type = 0, code = 0; /* for ICMPv6 output statistics only */ 337266339Sjhb int priv = 0; 338221828Sgrehan struct in6_addr *in6a; 339221828Sgrehan va_list ap; 340221828Sgrehan 341256072Sneel va_start(ap, m); 342221828Sgrehan so = va_arg(ap, struct socket *); 343242275Sneel dstsock = va_arg(ap, struct sockaddr_in6 *); 344242275Sneel control = va_arg(ap, struct mbuf *); 345242275Sneel va_end(ap); 346221828Sgrehan 347221828Sgrehan in6p = sotoin6pcb(so); 348221828Sgrehan stickyopt = in6p->in6p_outputopts; 349221828Sgrehan 350221828Sgrehan priv = 0; 351221828Sgrehan if (so->so_cred->cr_uid == 0) 352221828Sgrehan priv = 1; 353221828Sgrehan dst = &dstsock->sin6_addr; 354221828Sgrehan if (control) { 355242275Sneel if ((error = ip6_setpktoptions(control, &opt, 356221828Sgrehan stickyopt, priv, 0, 357221828Sgrehan so->so_proto->pr_protocol)) 358221828Sgrehan != 0) { 359221828Sgrehan goto bad; 360242275Sneel } 361221828Sgrehan in6p->in6p_outputopts = &opt; 362221828Sgrehan } 363221828Sgrehan 364221828Sgrehan /* 365242122Sneel * For an ICMPv6 packet, we should know its type and code 366242275Sneel * to update statistics. 367221828Sgrehan */ 368221828Sgrehan if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 369221828Sgrehan struct icmp6_hdr *icmp6; 370242275Sneel if (m->m_len < sizeof(struct icmp6_hdr) && 371221828Sgrehan (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 372221828Sgrehan error = ENOBUFS; 373221828Sgrehan goto bad; 374221828Sgrehan } 375221828Sgrehan icmp6 = mtod(m, struct icmp6_hdr *); 376221828Sgrehan type = icmp6->icmp6_type; 377221828Sgrehan code = icmp6->icmp6_code; 378221828Sgrehan } 379221828Sgrehan 380221828Sgrehan M_PREPEND(m, sizeof(*ip6), M_TRYWAIT); 381221828Sgrehan ip6 = mtod(m, struct ip6_hdr *); 382221828Sgrehan 383221828Sgrehan /* 384221828Sgrehan * Next header might not be ICMP6 but use its pseudo header anyway. 385221828Sgrehan */ 386221828Sgrehan ip6->ip6_dst = *dst; 387221828Sgrehan 388221828Sgrehan /* 389221828Sgrehan * If the scope of the destination is link-local, embed the interface 390221828Sgrehan * index in the address. 391221828Sgrehan * 392221828Sgrehan * XXX advanced-api value overrides sin6_scope_id 393221828Sgrehan */ 394221828Sgrehan if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 395221828Sgrehan struct in6_pktinfo *pi; 396221828Sgrehan 397221828Sgrehan /* 398221828Sgrehan * XXX Boundary check is assumed to be already done in 399221828Sgrehan * ip6_setpktoptions(). 400221828Sgrehan */ 401221828Sgrehan if (in6p->in6p_outputopts && 402242275Sneel (pi = in6p->in6p_outputopts->ip6po_pktinfo) && 403242275Sneel pi->ipi6_ifindex) { 404221828Sgrehan ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex); 405221828Sgrehan oifp = ifnet_byindex(pi->ipi6_ifindex); 406242275Sneel } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && 407242275Sneel in6p->in6p_moptions && 408221828Sgrehan in6p->in6p_moptions->im6o_multicast_ifp) { 409221828Sgrehan oifp = in6p->in6p_moptions->im6o_multicast_ifp; 410221828Sgrehan ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index); 411330713Stychon } else if (dstsock->sin6_scope_id) { 412330713Stychon /* boundary check */ 413330713Stychon if (dstsock->sin6_scope_id < 0 || 414330713Stychon if_index < dstsock->sin6_scope_id) { 415330713Stychon error = ENXIO; /* XXX EINVAL? */ 416330713Stychon goto bad; 417330713Stychon } 418330713Stychon ip6->ip6_dst.s6_addr16[1] = 419330713Stychon htons(dstsock->sin6_scope_id & 0xffff); /* XXX */ 420221828Sgrehan } 421221828Sgrehan } 422221828Sgrehan 423221828Sgrehan /* 424221828Sgrehan * Source address selection. 425221828Sgrehan */ 426221828Sgrehan if ((in6a = in6_selectsrc(dstsock, in6p->in6p_outputopts, 427221828Sgrehan in6p->in6p_moptions, &in6p->in6p_route, &in6p->in6p_laddr, 428221828Sgrehan &error)) == 0) { 429222605Sjhb if (error == 0) 430222605Sjhb error = EADDRNOTAVAIL; 431222605Sjhb goto bad; 432222605Sjhb } 433222605Sjhb ip6->ip6_src = *in6a; 434222605Sjhb if (in6p->in6p_route.ro_rt) 435222605Sjhb oifp = ifnet_byindex(in6p->in6p_route.ro_rt->rt_ifp->if_index); 436222605Sjhb ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | 437222605Sjhb (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); 438222605Sjhb ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | 439222605Sjhb (IPV6_VERSION & IPV6_VERSION_MASK); 440222605Sjhb /* ip6_plen will be filled in ip6_output, so not fill it here. */ 441222605Sjhb ip6->ip6_nxt = in6p->in6p_ip6_nxt; 442222605Sjhb ip6->ip6_hlim = in6_selecthlim(in6p, oifp); 443222605Sjhb 444222605Sjhb if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 445222605Sjhb in6p->in6p_cksum != -1) { 446222605Sjhb struct mbuf *n; 447222605Sjhb int off; 448222605Sjhb u_int16_t *p; 449222605Sjhb 450222605Sjhb /* compute checksum */ 451222605Sjhb if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 452222605Sjhb off = offsetof(struct icmp6_hdr, icmp6_cksum); 453222605Sjhb else 454222605Sjhb off = in6p->in6p_cksum; 455222605Sjhb if (plen < off + 1) { 456222605Sjhb error = EINVAL; 457222605Sjhb goto bad; 458222605Sjhb } 459222605Sjhb off += sizeof(struct ip6_hdr); 460222605Sjhb 461222605Sjhb n = m; 462222605Sjhb while (n && n->m_len <= off) { 463222605Sjhb off -= n->m_len; 464222605Sjhb n = n->m_next; 465222605Sjhb } 466222605Sjhb if (!n) 467222605Sjhb goto bad; 468222605Sjhb p = (u_int16_t *)(mtod(n, caddr_t) + off); 469222605Sjhb *p = 0; 470222605Sjhb *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 471222605Sjhb } 472222605Sjhb 473222605Sjhb error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, 0, 474222605Sjhb in6p->in6p_moptions, &oifp, in6p); 475222605Sjhb if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 476222605Sjhb if (oifp) 477222605Sjhb icmp6_ifoutstat_inc(oifp, type, code); 478222605Sjhb icmp6stat.icp6s_outhist[type]++; 479222605Sjhb } else 480222605Sjhb rip6stat.rip6s_opackets++; 481222605Sjhb 482222605Sjhb goto freectl; 483222605Sjhb 484266339Sjhb bad: 485222605Sjhb if (m) 486222605Sjhb m_freem(m); 487222605Sjhb 488222605Sjhb freectl: 489222605Sjhb if (control) { 490222605Sjhb ip6_clearpktopts(in6p->in6p_outputopts, -1); 491222605Sjhb in6p->in6p_outputopts = stickyopt; 492222605Sjhb m_freem(control); 493222605Sjhb } 494222605Sjhb return (error); 495222605Sjhb} 496222605Sjhb 497222605Sjhb/* 498222605Sjhb * Raw IPv6 socket option processing. 499222605Sjhb */ 500222605Sjhbint 501222605Sjhbrip6_ctloutput(so, sopt) 502222605Sjhb struct socket *so; 503222605Sjhb struct sockopt *sopt; 504222605Sjhb{ 505222605Sjhb int error; 506266339Sjhb 507222605Sjhb if (sopt->sopt_level == IPPROTO_ICMPV6) 508222605Sjhb /* 509222605Sjhb * XXX: is it better to call icmp6_ctloutput() directly 510222605Sjhb * from protosw? 511222605Sjhb */ 512222605Sjhb return (icmp6_ctloutput(so, sopt)); 513222605Sjhb else if (sopt->sopt_level != IPPROTO_IPV6) 514222605Sjhb return (EINVAL); 515222605Sjhb 516222605Sjhb error = 0; 517222605Sjhb 518 switch (sopt->sopt_dir) { 519 case SOPT_GET: 520 switch (sopt->sopt_name) { 521 case MRT6_INIT: 522 case MRT6_DONE: 523 case MRT6_ADD_MIF: 524 case MRT6_DEL_MIF: 525 case MRT6_ADD_MFC: 526 case MRT6_DEL_MFC: 527 case MRT6_PIM: 528 error = ip6_mrouter_get(so, sopt); 529 break; 530 default: 531 error = ip6_ctloutput(so, sopt); 532 break; 533 } 534 break; 535 536 case SOPT_SET: 537 switch (sopt->sopt_name) { 538 case MRT6_INIT: 539 case MRT6_DONE: 540 case MRT6_ADD_MIF: 541 case MRT6_DEL_MIF: 542 case MRT6_ADD_MFC: 543 case MRT6_DEL_MFC: 544 case MRT6_PIM: 545 error = ip6_mrouter_set(so, sopt); 546 break; 547 default: 548 error = ip6_ctloutput(so, sopt); 549 break; 550 } 551 break; 552 } 553 554 return (error); 555} 556 557static int 558rip6_attach(struct socket *so, int proto, struct thread *td) 559{ 560 struct inpcb *inp; 561 int error, s; 562 563 inp = sotoinpcb(so); 564 if (inp) 565 panic("rip6_attach"); 566 if (td && (error = suser(td)) != 0) 567 return error; 568 569 error = soreserve(so, rip_sendspace, rip_recvspace); 570 if (error) 571 return error; 572 s = splnet(); 573 error = in_pcballoc(so, &ripcbinfo, td); 574 splx(s); 575 if (error) 576 return error; 577 inp = (struct inpcb *)so->so_pcb; 578 inp->inp_vflag |= INP_IPV6; 579 inp->in6p_ip6_nxt = (long)proto; 580 inp->in6p_hops = -1; /* use kernel default */ 581 inp->in6p_cksum = -1; 582 MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *, 583 sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); 584 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt); 585 return 0; 586} 587 588static int 589rip6_detach(struct socket *so) 590{ 591 struct inpcb *inp; 592 593 inp = sotoinpcb(so); 594 if (inp == 0) 595 panic("rip6_detach"); 596 /* xxx: RSVP */ 597 if (so == ip6_mrouter) 598 ip6_mrouter_done(); 599 if (inp->in6p_icmp6filt) { 600 FREE(inp->in6p_icmp6filt, M_PCB); 601 inp->in6p_icmp6filt = NULL; 602 } 603 in6_pcbdetach(inp); 604 return 0; 605} 606 607static int 608rip6_abort(struct socket *so) 609{ 610 soisdisconnected(so); 611 return rip6_detach(so); 612} 613 614static int 615rip6_disconnect(struct socket *so) 616{ 617 struct inpcb *inp = sotoinpcb(so); 618 619 if ((so->so_state & SS_ISCONNECTED) == 0) 620 return ENOTCONN; 621 inp->in6p_faddr = in6addr_any; 622 return rip6_abort(so); 623} 624 625static int 626rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 627{ 628 struct inpcb *inp = sotoinpcb(so); 629 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 630 struct ifaddr *ia = NULL; 631 632 if (nam->sa_len != sizeof(*addr)) 633 return EINVAL; 634 if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) 635 return EADDRNOTAVAIL; 636#ifdef ENABLE_DEFAULT_SCOPE 637 if (addr->sin6_scope_id == 0) { /* not change if specified */ 638 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 639 } 640#endif 641 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 642 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) 643 return EADDRNOTAVAIL; 644 if (ia && 645 ((struct in6_ifaddr *)ia)->ia6_flags & 646 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 647 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 648 return (EADDRNOTAVAIL); 649 } 650 inp->in6p_laddr = addr->sin6_addr; 651 return 0; 652} 653 654static int 655rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 656{ 657 struct inpcb *inp = sotoinpcb(so); 658 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; 659 struct in6_addr *in6a = NULL; 660 int error = 0; 661#ifdef ENABLE_DEFAULT_SCOPE 662 struct sockaddr_in6 tmp; 663#endif 664 665 if (nam->sa_len != sizeof(*addr)) 666 return EINVAL; 667 if (TAILQ_EMPTY(&ifnet)) 668 return EADDRNOTAVAIL; 669 if (addr->sin6_family != AF_INET6) 670 return EAFNOSUPPORT; 671#ifdef ENABLE_DEFAULT_SCOPE 672 if (addr->sin6_scope_id == 0) { /* not change if specified */ 673 /* avoid overwrites */ 674 tmp = *addr; 675 addr = &tmp; 676 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); 677 } 678#endif 679 /* Source address selection. XXX: need pcblookup? */ 680 in6a = in6_selectsrc(addr, inp->in6p_outputopts, 681 inp->in6p_moptions, &inp->in6p_route, 682 &inp->in6p_laddr, &error); 683 if (in6a == NULL) 684 return (error ? error : EADDRNOTAVAIL); 685 inp->in6p_laddr = *in6a; 686 inp->in6p_faddr = addr->sin6_addr; 687 soisconnected(so); 688 return 0; 689} 690 691static int 692rip6_shutdown(struct socket *so) 693{ 694 socantsendmore(so); 695 return 0; 696} 697 698static int 699rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 700 struct mbuf *control, struct thread *td) 701{ 702 struct inpcb *inp = sotoinpcb(so); 703 struct sockaddr_in6 tmp; 704 struct sockaddr_in6 *dst; 705 706 /* always copy sockaddr to avoid overwrites */ 707 if (so->so_state & SS_ISCONNECTED) { 708 if (nam) { 709 m_freem(m); 710 return EISCONN; 711 } 712 /* XXX */ 713 bzero(&tmp, sizeof(tmp)); 714 tmp.sin6_family = AF_INET6; 715 tmp.sin6_len = sizeof(struct sockaddr_in6); 716 bcopy(&inp->in6p_faddr, &tmp.sin6_addr, 717 sizeof(struct in6_addr)); 718 dst = &tmp; 719 } else { 720 if (nam == NULL) { 721 m_freem(m); 722 return ENOTCONN; 723 } 724 tmp = *(struct sockaddr_in6 *)nam; 725 dst = &tmp; 726 } 727#ifdef ENABLE_DEFAULT_SCOPE 728 if (dst->sin6_scope_id == 0) { /* not change if specified */ 729 dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr); 730 } 731#endif 732 return rip6_output(m, so, dst, control); 733} 734 735struct pr_usrreqs rip6_usrreqs = { 736 rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect, 737 pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect, 738 pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp, 739 pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown, 740 in6_setsockaddr, sosend, soreceive, sopoll 741}; 742