1139826Simp/*- 253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 353541Sshin * All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. Neither the name of the project nor the names of its contributors 1453541Sshin * may be used to endorse or promote products derived from this software 1553541Sshin * without specific prior written permission. 1653541Sshin * 1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753541Sshin * SUCH DAMAGE. 28174510Sobrien * 29174510Sobrien * $KAME: ip6_output.c,v 1.279 2002/01/26 06:12:30 jinmei Exp $ 3053541Sshin */ 3153541Sshin 32139826Simp/*- 3353541Sshin * Copyright (c) 1982, 1986, 1988, 1990, 1993 3453541Sshin * The Regents of the University of California. All rights reserved. 3553541Sshin * 3653541Sshin * Redistribution and use in source and binary forms, with or without 3753541Sshin * modification, are permitted provided that the following conditions 3853541Sshin * are met: 3953541Sshin * 1. Redistributions of source code must retain the above copyright 4053541Sshin * notice, this list of conditions and the following disclaimer. 4153541Sshin * 2. Redistributions in binary form must reproduce the above copyright 4253541Sshin * notice, this list of conditions and the following disclaimer in the 4353541Sshin * documentation and/or other materials provided with the distribution. 4453541Sshin * 4. Neither the name of the University nor the names of its contributors 4553541Sshin * may be used to endorse or promote products derived from this software 4653541Sshin * without specific prior written permission. 4753541Sshin * 4853541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4953541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5053541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5153541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5253541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5353541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5453541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5553541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5653541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5753541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5853541Sshin * SUCH DAMAGE. 5953541Sshin * 6053541Sshin * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 6153541Sshin */ 6253541Sshin 63174510Sobrien#include <sys/cdefs.h> 64174510Sobrien__FBSDID("$FreeBSD: stable/10/sys/netinet6/ip6_output.c 343139 2019-01-18 08:59:00Z hselasky $"); 65174510Sobrien 6662587Sitojun#include "opt_inet.h" 6762587Sitojun#include "opt_inet6.h" 68225044Sbz#include "opt_ipfw.h" 6955009Sshin#include "opt_ipsec.h" 70205075Srrs#include "opt_sctp.h" 71207828Skmacy#include "opt_route.h" 7253541Sshin 7353541Sshin#include <sys/param.h> 74175892Sbz#include <sys/kernel.h> 7553541Sshin#include <sys/malloc.h> 7653541Sshin#include <sys/mbuf.h> 7753541Sshin#include <sys/errno.h> 78170689Srwatson#include <sys/priv.h> 79175892Sbz#include <sys/proc.h> 8053541Sshin#include <sys/protosw.h> 8153541Sshin#include <sys/socket.h> 8253541Sshin#include <sys/socketvar.h> 83189303Sbz#include <sys/syslog.h> 84175892Sbz#include <sys/ucred.h> 8553541Sshin 86235958Sbz#include <machine/in_cksum.h> 87235958Sbz 8853541Sshin#include <net/if.h> 89145246Sbrooks#include <net/netisr.h> 9053541Sshin#include <net/route.h> 9164060Sdarrenr#include <net/pfil.h> 92185571Sbz#include <net/vnet.h> 9353541Sshin 9453541Sshin#include <netinet/in.h> 9553541Sshin#include <netinet/in_var.h> 96225044Sbz#include <netinet/ip_var.h> 9778064Sume#include <netinet6/in6_var.h> 9862587Sitojun#include <netinet/ip6.h> 9962587Sitojun#include <netinet/icmp6.h> 10062587Sitojun#include <netinet6/ip6_var.h> 10153541Sshin#include <netinet/in_pcb.h> 102122922Sandre#include <netinet/tcp_var.h> 10353541Sshin#include <netinet6/nd6.h> 10453541Sshin 105171167Sgnn#ifdef IPSEC 106105199Ssam#include <netipsec/ipsec.h> 107105199Ssam#include <netipsec/ipsec6.h> 108105199Ssam#include <netipsec/key.h> 109171133Sgnn#include <netinet6/ip6_ipsec.h> 110171167Sgnn#endif /* IPSEC */ 111205075Srrs#ifdef SCTP 112205075Srrs#include <netinet/sctp.h> 113205075Srrs#include <netinet/sctp_crc32.h> 114205075Srrs#endif 115105199Ssam 11664558Sume#include <netinet6/ip6protosw.h> 117148385Sume#include <netinet6/scope6_var.h> 11864558Sume 119207828Skmacy#ifdef FLOWTABLE 120207828Skmacy#include <net/flowtable.h> 121207828Skmacy#endif 122207828Skmacy 123191672Sbmsextern int in6_mcast_loop; 12453541Sshin 12553541Sshinstruct ip6_exthdrs { 12662587Sitojun struct mbuf *ip6e_ip6; 12762587Sitojun struct mbuf *ip6e_hbh; 12862587Sitojun struct mbuf *ip6e_dest1; 12962587Sitojun struct mbuf *ip6e_rthdr; 13062587Sitojun struct mbuf *ip6e_dest2; 13153541Sshin}; 13253541Sshin 133241916Sdelphijstatic int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **, 134241916Sdelphij struct ucred *, int); 135241916Sdelphijstatic int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *, 136241916Sdelphij struct socket *, struct sockopt *); 137175162Sobrienstatic int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *); 138241916Sdelphijstatic int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, 139241916Sdelphij struct ucred *, int, int, int); 140121472Sume 141175162Sobrienstatic int ip6_copyexthdr(struct mbuf **, caddr_t, int); 142241916Sdelphijstatic int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int, 143241916Sdelphij struct ip6_frag **); 144175162Sobrienstatic int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t); 145175162Sobrienstatic int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *); 146241916Sdelphijstatic int ip6_getpmtu(struct route_in6 *, struct route_in6 *, 147241916Sdelphij struct ifnet *, struct in6_addr *, u_long *, int *, u_int); 148175162Sobrienstatic int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int); 14953541Sshin 150120913Sume 15153541Sshin/* 152171133Sgnn * Make an extension header from option data. hp is the source, and 153171133Sgnn * mp is the destination. 154171133Sgnn */ 155171133Sgnn#define MAKE_EXTHDR(hp, mp) \ 156171133Sgnn do { \ 157171133Sgnn if (hp) { \ 158171133Sgnn struct ip6_ext *eh = (struct ip6_ext *)(hp); \ 159171133Sgnn error = ip6_copyexthdr((mp), (caddr_t)(hp), \ 160171133Sgnn ((eh)->ip6e_len + 1) << 3); \ 161171133Sgnn if (error) \ 162171133Sgnn goto freehdrs; \ 163171133Sgnn } \ 164171133Sgnn } while (/*CONSTCOND*/ 0) 165171133Sgnn 166171133Sgnn/* 167171260Sdelphij * Form a chain of extension headers. 168171133Sgnn * m is the extension header mbuf 169171133Sgnn * mp is the previous mbuf in the chain 170171133Sgnn * p is the next header 171171133Sgnn * i is the type of option. 172171133Sgnn */ 173171133Sgnn#define MAKE_CHAIN(m, mp, p, i)\ 174171133Sgnn do {\ 175171133Sgnn if (m) {\ 176171133Sgnn if (!hdrsplit) \ 177171133Sgnn panic("assumption failed: hdr not split"); \ 178171133Sgnn *mtod((m), u_char *) = *(p);\ 179171133Sgnn *(p) = (i);\ 180171133Sgnn p = mtod((m), u_char *);\ 181171133Sgnn (m)->m_next = (mp)->m_next;\ 182171133Sgnn (mp)->m_next = (m);\ 183171133Sgnn (mp) = (m);\ 184171133Sgnn }\ 185171133Sgnn } while (/*CONSTCOND*/ 0) 186171133Sgnn 187274132Saevoid 188235958Sbzin6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset) 189235958Sbz{ 190235958Sbz u_short csum; 191235958Sbz 192236130Sbz csum = in_cksum_skip(m, offset + plen, offset); 193236170Sbz if (m->m_pkthdr.csum_flags & CSUM_UDP_IPV6 && csum == 0) 194235958Sbz csum = 0xffff; 195235958Sbz offset += m->m_pkthdr.csum_data; /* checksum offset */ 196235958Sbz 197235958Sbz if (offset + sizeof(u_short) > m->m_len) { 198238934Sbz printf("%s: delayed m_pullup, m->len: %d plen %u off %u " 199254804Sandre "csum_flags=%b\n", __func__, m->m_len, plen, offset, 200254804Sandre (int)m->m_pkthdr.csum_flags, CSUM_BITS); 201235958Sbz /* 202235958Sbz * XXX this should not happen, but if it does, the correct 203235958Sbz * behavior may be to insert the checksum in the appropriate 204235958Sbz * next mbuf in the chain. 205235958Sbz */ 206235958Sbz return; 207235958Sbz } 208235958Sbz *(u_short *)(m->m_data + offset) = csum; 209235958Sbz} 210235958Sbz 211284570Skpint 212284570Skpip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto, 213284572Skp int mtu, uint32_t id) 214284570Skp{ 215284570Skp struct mbuf *m, **mnext, *m_frgpart; 216284570Skp struct ip6_hdr *ip6, *mhip6; 217284570Skp struct ip6_frag *ip6f; 218284570Skp int off; 219284570Skp int error; 220284570Skp int tlen = m0->m_pkthdr.len; 221284570Skp 222317335Skp KASSERT(( mtu % 8 == 0), ("Fragment length must be a multiple of 8")); 223317335Skp 224284570Skp m = m0; 225284570Skp ip6 = mtod(m, struct ip6_hdr *); 226284570Skp mnext = &m->m_nextpkt; 227284570Skp 228284570Skp for (off = hlen; off < tlen; off += mtu) { 229284570Skp m = m_gethdr(M_NOWAIT, MT_DATA); 230284570Skp if (!m) { 231284570Skp IP6STAT_INC(ip6s_odropped); 232284570Skp return (ENOBUFS); 233284570Skp } 234284570Skp m->m_flags = m0->m_flags & M_COPYFLAGS; 235284570Skp *mnext = m; 236284570Skp mnext = &m->m_nextpkt; 237284570Skp m->m_data += max_linkhdr; 238284570Skp mhip6 = mtod(m, struct ip6_hdr *); 239284570Skp *mhip6 = *ip6; 240284570Skp m->m_len = sizeof(*mhip6); 241284570Skp error = ip6_insertfraghdr(m0, m, hlen, &ip6f); 242284570Skp if (error) { 243284570Skp IP6STAT_INC(ip6s_odropped); 244284570Skp return (error); 245284570Skp } 246284570Skp ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7)); 247284570Skp if (off + mtu >= tlen) 248284570Skp mtu = tlen - off; 249284570Skp else 250284570Skp ip6f->ip6f_offlg |= IP6F_MORE_FRAG; 251284570Skp mhip6->ip6_plen = htons((u_short)(mtu + hlen + 252284570Skp sizeof(*ip6f) - sizeof(struct ip6_hdr))); 253284570Skp if ((m_frgpart = m_copy(m0, off, mtu)) == 0) { 254284570Skp IP6STAT_INC(ip6s_odropped); 255284570Skp return (ENOBUFS); 256284570Skp } 257284570Skp m_cat(m, m_frgpart); 258284570Skp m->m_pkthdr.len = mtu + hlen + sizeof(*ip6f); 259284570Skp m->m_pkthdr.fibnum = m0->m_pkthdr.fibnum; 260284570Skp m->m_pkthdr.rcvif = NULL; 261284570Skp ip6f->ip6f_reserved = 0; 262284570Skp ip6f->ip6f_ident = id; 263284570Skp ip6f->ip6f_nxt = nextproto; 264284570Skp IP6STAT_INC(ip6s_ofragments); 265284570Skp in6_ifstat_inc(ifp, ifs6_out_fragcreat); 266284570Skp } 267284570Skp 268284570Skp return (0); 269284570Skp} 270284570Skp 271171133Sgnn/* 27253541Sshin * IP6 output. The packet in mbuf chain m contains a skeletal IP6 27353541Sshin * header (with pri, len, nxt, hlim, src, dst). 27453541Sshin * This function may modify ver and hlim only. 27553541Sshin * The mbuf chain containing the packet will be freed. 27653541Sshin * The mbuf opt, if present, will not be freed. 277238092Sglebius * If route_in6 ro is present and has ro_rt initialized, route lookup would be 278238092Sglebius * skipped and ro->ro_rt would be used. If ro is present but ro->ro_rt is NULL, 279238092Sglebius * then result of route lookup is stored in ro->ro_rt. 28078064Sume * 281263478Sglebius * type of "mtu": rt_mtu is u_long, ifnet.ifr_mtu is int, and 28278064Sume * nd_ifinfo.linkmtu is u_int32_t. so we use u_long to hold largest one, 283263478Sglebius * which is rt_mtu. 284171259Sdelphij * 285171259Sdelphij * ifpp - XXX: just for statistics 28653541Sshin */ 28753541Sshinint 288171259Sdelphijip6_output(struct mbuf *m0, struct ip6_pktopts *opt, 289171259Sdelphij struct route_in6 *ro, int flags, struct ip6_moptions *im6o, 290171259Sdelphij struct ifnet **ifpp, struct inpcb *inp) 29153541Sshin{ 292284570Skp struct ip6_hdr *ip6; 29362587Sitojun struct ifnet *ifp, *origifp; 29453541Sshin struct mbuf *m = m0; 295171133Sgnn struct mbuf *mprev = NULL; 296284570Skp int hlen, tlen, len; 29753541Sshin struct route_in6 ip6route; 298148385Sume struct rtentry *rt = NULL; 299148385Sume struct sockaddr_in6 *dst, src_sa, dst_sa; 300145246Sbrooks struct in6_addr odst; 30153541Sshin int error = 0; 30267334Sjoe struct in6_ifaddr *ia = NULL; 30353541Sshin u_long mtu; 304121472Sume int alwaysfrag, dontfrag; 30553541Sshin u_int32_t optlen = 0, plen = 0, unfragpartlen = 0; 30653541Sshin struct ip6_exthdrs exthdrs; 307148385Sume struct in6_addr finaldst, src0, dst0; 308148385Sume u_int32_t zone; 30953541Sshin struct route_in6 *ro_pmtu = NULL; 31053541Sshin int hdrsplit = 0; 311235958Sbz int sw_csum, tso; 312244441Sae struct m_tag *fwd_tag = NULL; 313284572Skp uint32_t id; 31453541Sshin 315105199Ssam ip6 = mtod(m, struct ip6_hdr *); 316171133Sgnn if (ip6 == NULL) { 317171133Sgnn printf ("ip6 is NULL"); 318171133Sgnn goto bad; 319171133Sgnn } 320171260Sdelphij 321231852Sbz if (inp != NULL) 322231852Sbz M_SETFIB(m, inp->inp_inc.inc_fibnum); 323231852Sbz 324123587Ssuz finaldst = ip6->ip6_dst; 32553541Sshin bzero(&exthdrs, sizeof(exthdrs)); 32653541Sshin if (opt) { 32753541Sshin /* Hop-by-Hop options header */ 32853541Sshin MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh); 32953541Sshin /* Destination options header(1st part) */ 330121811Sume if (opt->ip6po_rthdr) { 331121811Sume /* 332121811Sume * Destination options header(1st part) 333171133Sgnn * This only makes sense with a routing header. 334121811Sume * See Section 9.2 of RFC 3542. 335121811Sume * Disabling this part just for MIP6 convenience is 336121811Sume * a bad idea. We need to think carefully about a 337121811Sume * way to make the advanced API coexist with MIP6 338121811Sume * options, which might automatically be inserted in 339121811Sume * the kernel. 340121811Sume */ 341121811Sume MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1); 342121811Sume } 34353541Sshin /* Routing header */ 34453541Sshin MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr); 34553541Sshin /* Destination options header(2nd part) */ 34653541Sshin MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2); 34753541Sshin } 34853541Sshin 349238878Sbz#ifdef IPSEC 350171260Sdelphij /* 351171133Sgnn * IPSec checking which handles several cases. 352171133Sgnn * FAST IPSEC: We re-injected the packet. 353171133Sgnn */ 354274132Sae switch(ip6_ipsec_output(&m, inp, &flags, &error, &ifp)) 355171133Sgnn { 356171133Sgnn case 1: /* Bad packet */ 35762587Sitojun goto freehdrs; 358274132Sae case -1: /* IPSec done */ 359274132Sae goto done; 360171133Sgnn case 0: /* No IPSec */ 36153541Sshin default: 362105199Ssam break; 363105199Ssam } 364171167Sgnn#endif /* IPSEC */ 365105199Ssam 36653541Sshin /* 36753541Sshin * Calculate the total length of the extension header chain. 36853541Sshin * Keep the length of the unfragmentable part for fragmentation. 36953541Sshin */ 37053541Sshin optlen = 0; 371171260Sdelphij if (exthdrs.ip6e_hbh) 372171133Sgnn optlen += exthdrs.ip6e_hbh->m_len; 373171260Sdelphij if (exthdrs.ip6e_dest1) 374171133Sgnn optlen += exthdrs.ip6e_dest1->m_len; 375171260Sdelphij if (exthdrs.ip6e_rthdr) 376171133Sgnn optlen += exthdrs.ip6e_rthdr->m_len; 37753541Sshin unfragpartlen = optlen + sizeof(struct ip6_hdr); 378171133Sgnn 379274132Sae /* NOTE: we don't add AH/ESP length here (done in ip6_ipsec_output) */ 380171260Sdelphij if (exthdrs.ip6e_dest2) 381171133Sgnn optlen += exthdrs.ip6e_dest2->m_len; 38253541Sshin 38353541Sshin /* 384274132Sae * If there is at least one extension header, 38553541Sshin * separate IP6 header from the payload. 38653541Sshin */ 387274132Sae if (optlen && !hdrsplit) { 38853541Sshin if ((error = ip6_splithdr(m, &exthdrs)) != 0) { 38953541Sshin m = NULL; 39053541Sshin goto freehdrs; 39153541Sshin } 39253541Sshin m = exthdrs.ip6e_ip6; 39353541Sshin hdrsplit++; 39453541Sshin } 39553541Sshin 39653541Sshin /* adjust pointer */ 39753541Sshin ip6 = mtod(m, struct ip6_hdr *); 39853541Sshin 39953541Sshin /* adjust mbuf packet header length */ 40053541Sshin m->m_pkthdr.len += optlen; 40153541Sshin plen = m->m_pkthdr.len - sizeof(*ip6); 40253541Sshin 40353541Sshin /* If this is a jumbo payload, insert a jumbo payload option. */ 40453541Sshin if (plen > IPV6_MAXPACKET) { 40553541Sshin if (!hdrsplit) { 40653541Sshin if ((error = ip6_splithdr(m, &exthdrs)) != 0) { 40753541Sshin m = NULL; 40853541Sshin goto freehdrs; 40953541Sshin } 41053541Sshin m = exthdrs.ip6e_ip6; 41153541Sshin hdrsplit++; 41253541Sshin } 41353541Sshin /* adjust pointer */ 41453541Sshin ip6 = mtod(m, struct ip6_hdr *); 41553541Sshin if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0) 41653541Sshin goto freehdrs; 41753541Sshin ip6->ip6_plen = 0; 41853541Sshin } else 41953541Sshin ip6->ip6_plen = htons(plen); 42053541Sshin 42153541Sshin /* 42253541Sshin * Concatenate headers and fill in next header fields. 42353541Sshin * Here we have, on "m" 42453541Sshin * IPv6 payload 42553541Sshin * and we insert headers accordingly. Finally, we should be getting: 42653541Sshin * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload] 42753541Sshin * 42853541Sshin * during the header composing process, "m" points to IPv6 header. 42953541Sshin * "mprev" points to an extension header prior to esp. 43053541Sshin */ 431171133Sgnn u_char *nexthdrp = &ip6->ip6_nxt; 432171133Sgnn mprev = m; 433171260Sdelphij 434171133Sgnn /* 435171133Sgnn * we treat dest2 specially. this makes IPsec processing 436171133Sgnn * much easier. the goal here is to make mprev point the 437171133Sgnn * mbuf prior to dest2. 438171133Sgnn * 439171133Sgnn * result: IPv6 dest2 payload 440171133Sgnn * m and mprev will point to IPv6 header. 441171133Sgnn */ 442171133Sgnn if (exthdrs.ip6e_dest2) { 443171133Sgnn if (!hdrsplit) 444171133Sgnn panic("assumption failed: hdr not split"); 445171133Sgnn exthdrs.ip6e_dest2->m_next = m->m_next; 446171133Sgnn m->m_next = exthdrs.ip6e_dest2; 447171133Sgnn *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt; 448171133Sgnn ip6->ip6_nxt = IPPROTO_DSTOPTS; 449171133Sgnn } 450171260Sdelphij 451171133Sgnn /* 452171133Sgnn * result: IPv6 hbh dest1 rthdr dest2 payload 453171133Sgnn * m will point to IPv6 header. mprev will point to the 454171133Sgnn * extension header prior to dest2 (rthdr in the above case). 455171133Sgnn */ 456171133Sgnn MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS); 457171133Sgnn MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp, 458171133Sgnn IPPROTO_DSTOPTS); 459171133Sgnn MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp, 460171133Sgnn IPPROTO_ROUTING); 461171260Sdelphij 462171133Sgnn /* 463191942Simp * If there is a routing header, discard the packet. 46453541Sshin */ 46553541Sshin if (exthdrs.ip6e_rthdr) { 466191942Simp error = EINVAL; 467191942Simp goto bad; 46853541Sshin } 46953541Sshin 47053541Sshin /* Source address validation */ 47153541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && 472151536Ssuz (flags & IPV6_UNSPECSRC) == 0) { 47353541Sshin error = EOPNOTSUPP; 474249294Sae IP6STAT_INC(ip6s_badscope); 47553541Sshin goto bad; 47653541Sshin } 47753541Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) { 47853541Sshin error = EOPNOTSUPP; 479249294Sae IP6STAT_INC(ip6s_badscope); 48053541Sshin goto bad; 48153541Sshin } 48253541Sshin 483249294Sae IP6STAT_INC(ip6s_localout); 48453541Sshin 48553541Sshin /* 48653541Sshin * Route packet. 48753541Sshin */ 48853541Sshin if (ro == 0) { 48953541Sshin ro = &ip6route; 49053541Sshin bzero((caddr_t)ro, sizeof(*ro)); 49153541Sshin } 49253541Sshin ro_pmtu = ro; 49353541Sshin if (opt && opt->ip6po_rthdr) 49453541Sshin ro = &opt->ip6po_route; 49553541Sshin dst = (struct sockaddr_in6 *)&ro->ro_dst; 496207828Skmacy#ifdef FLOWTABLE 497262743Sglebius if (ro->ro_rt == NULL) 498262743Sglebius (void )flowtable_lookup(AF_INET6, m, (struct route *)ro); 499236332Stuexen#endif 500145246Sbrooksagain: 501171260Sdelphij /* 502121472Sume * if specified, try to fill in the traffic class field. 503121472Sume * do not override if a non-zero value is already set. 504121472Sume * we check the diffserv field and the ecn field separately. 505121472Sume */ 506121472Sume if (opt && opt->ip6po_tclass >= 0) { 507121472Sume int mask = 0; 508121472Sume 509121472Sume if ((ip6->ip6_flow & htonl(0xfc << 20)) == 0) 510121472Sume mask |= 0xfc; 511121472Sume if ((ip6->ip6_flow & htonl(0x03 << 20)) == 0) 512121472Sume mask |= 0x03; 513121472Sume if (mask != 0) 514121472Sume ip6->ip6_flow |= htonl((opt->ip6po_tclass & mask) << 20); 515121472Sume } 516121472Sume 517121472Sume /* fill in or override the hop limit field, if necessary. */ 518121472Sume if (opt && opt->ip6po_hlim != -1) 519121472Sume ip6->ip6_hlim = opt->ip6po_hlim & 0xff; 520121472Sume else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 521121472Sume if (im6o != NULL) 522121472Sume ip6->ip6_hlim = im6o->im6o_multicast_hlim; 523121472Sume else 524181803Sbz ip6->ip6_hlim = V_ip6_defmcasthlim; 525121472Sume } 526121472Sume 527148385Sume /* adjust pointer */ 528148385Sume ip6 = mtod(m, struct ip6_hdr *); 52953541Sshin 530244441Sae if (ro->ro_rt && fwd_tag == NULL) { 531207828Skmacy rt = ro->ro_rt; 532207828Skmacy ifp = ro->ro_rt->rt_ifp; 533244440Sae } else { 534244441Sae if (fwd_tag == NULL) { 535244441Sae bzero(&dst_sa, sizeof(dst_sa)); 536244441Sae dst_sa.sin6_family = AF_INET6; 537244441Sae dst_sa.sin6_len = sizeof(dst_sa); 538244441Sae dst_sa.sin6_addr = ip6->ip6_dst; 539244441Sae } 540244440Sae error = in6_selectroute_fib(&dst_sa, opt, im6o, ro, &ifp, 541244440Sae &rt, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m)); 542244440Sae if (error != 0) { 543244440Sae if (ifp != NULL) 544244440Sae in6_ifstat_inc(ifp, ifs6_out_discard); 545244440Sae goto bad; 546244440Sae } 547148385Sume } 548148385Sume if (rt == NULL) { 549148385Sume /* 550148385Sume * If in6_selectroute() does not return a route entry, 551148385Sume * dst may not have been updated. 552148385Sume */ 553148385Sume *dst = dst_sa; /* XXX */ 554148385Sume } 55553541Sshin 556148385Sume /* 557148385Sume * then rt (for unicast) and ifp must be non-NULL valid values. 558148385Sume */ 559148385Sume if ((flags & IPV6_FORWARDING) == 0) { 560148385Sume /* XXX: the FORWARDING flag can be set for mrouting. */ 56153541Sshin in6_ifstat_inc(ifp, ifs6_out_request); 562148385Sume } 563148385Sume if (rt != NULL) { 564148385Sume ia = (struct in6_ifaddr *)(rt->rt_ifa); 565263478Sglebius counter_u64_add(rt->rt_pksent, 1); 566148385Sume } 56753541Sshin 568343139Shselasky /* Setup data structures for scope ID checks. */ 569148385Sume src0 = ip6->ip6_src; 570148385Sume bzero(&src_sa, sizeof(src_sa)); 571148385Sume src_sa.sin6_family = AF_INET6; 572148385Sume src_sa.sin6_len = sizeof(src_sa); 573148385Sume src_sa.sin6_addr = ip6->ip6_src; 57453541Sshin 575148385Sume dst0 = ip6->ip6_dst; 576148385Sume /* re-initialize to be sure */ 577148385Sume bzero(&dst_sa, sizeof(dst_sa)); 578148385Sume dst_sa.sin6_family = AF_INET6; 579148385Sume dst_sa.sin6_len = sizeof(dst_sa); 580148385Sume dst_sa.sin6_addr = ip6->ip6_dst; 58153541Sshin 582343139Shselasky /* Check for valid scope ID. */ 583343139Shselasky if (in6_setscope(&src0, ifp, &zone) == 0 && 584343139Shselasky sa6_recoverscope(&src_sa) == 0 && zone == src_sa.sin6_scope_id && 585343139Shselasky in6_setscope(&dst0, ifp, &zone) == 0 && 586343139Shselasky sa6_recoverscope(&dst_sa) == 0 && zone == dst_sa.sin6_scope_id) { 587343139Shselasky /* 588343139Shselasky * The outgoing interface is in the zone of the source 589343139Shselasky * and destination addresses. 590343139Shselasky * 591343139Shselasky * Because the loopback interface cannot receive 592343139Shselasky * packets with a different scope ID than its own, 593343139Shselasky * there is a trick is to pretend the outgoing packet 594343139Shselasky * was received by the real network interface, by 595343139Shselasky * setting "origifp" different from "ifp". This is 596343139Shselasky * only allowed when "ifp" is a loopback network 597343139Shselasky * interface. Refer to code in nd6_output_ifp() for 598343139Shselasky * more details. 599343139Shselasky */ 600343139Shselasky origifp = ifp; 601343139Shselasky 602343139Shselasky /* 603343139Shselasky * We should use ia_ifp to support the case of sending 604343139Shselasky * packets to an address of our own. 605343139Shselasky */ 606343139Shselasky if (ia != NULL && ia->ia_ifp) 607343139Shselasky ifp = ia->ia_ifp; 608196864Sqingli 609343139Shselasky } else if ((ifp->if_flags & IFF_LOOPBACK) == 0 || 610343139Shselasky sa6_recoverscope(&src_sa) != 0 || 611343139Shselasky sa6_recoverscope(&dst_sa) != 0 || 612343139Shselasky dst_sa.sin6_scope_id == 0 || 613343139Shselasky (src_sa.sin6_scope_id != 0 && 614343139Shselasky src_sa.sin6_scope_id != dst_sa.sin6_scope_id) || 615343139Shselasky (origifp = ifnet_byindex(dst_sa.sin6_scope_id)) == NULL) { 616343139Shselasky /* 617343139Shselasky * If the destination network interface is not a 618343139Shselasky * loopback interface, or the destination network 619343139Shselasky * address has no scope ID, or the source address has 620343139Shselasky * a scope ID set which is different from the 621343139Shselasky * destination address one, or there is no network 622343139Shselasky * interface representing this scope ID, the address 623343139Shselasky * pair is considered invalid. 624343139Shselasky */ 625343139Shselasky IP6STAT_INC(ip6s_badscope); 626343139Shselasky in6_ifstat_inc(ifp, ifs6_out_discard); 627343139Shselasky if (error == 0) 628343139Shselasky error = EHOSTUNREACH; /* XXX */ 629343139Shselasky goto bad; 630343139Shselasky } 63153541Sshin 632343139Shselasky /* All scope ID checks are successful. */ 63353541Sshin 634148385Sume if (rt && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 635148385Sume if (opt && opt->ip6po_nextroute.ro_rt) { 63653541Sshin /* 637148385Sume * The nexthop is explicitly specified by the 638148385Sume * application. We assume the next hop is an IPv6 639148385Sume * address. 64053541Sshin */ 641148385Sume dst = (struct sockaddr_in6 *)opt->ip6po_nexthop; 64253541Sshin } 643148385Sume else if ((rt->rt_flags & RTF_GATEWAY)) 644148385Sume dst = (struct sockaddr_in6 *)rt->rt_gateway; 645148385Sume } 64653541Sshin 647148385Sume if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 648148385Sume m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */ 649148385Sume } else { 650148385Sume m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST; 65153541Sshin in6_ifstat_inc(ifp, ifs6_out_mcast); 65253541Sshin /* 65353541Sshin * Confirm that the outgoing interface supports multicast. 65453541Sshin */ 655148385Sume if (!(ifp->if_flags & IFF_MULTICAST)) { 656249294Sae IP6STAT_INC(ip6s_noroute); 65753541Sshin in6_ifstat_inc(ifp, ifs6_out_discard); 65853541Sshin error = ENETUNREACH; 65953541Sshin goto bad; 66053541Sshin } 661191672Sbms if ((im6o == NULL && in6_mcast_loop) || 662191672Sbms (im6o && im6o->im6o_multicast_loop)) { 66353541Sshin /* 664191672Sbms * Loop back multicast datagram if not expressly 665191672Sbms * forbidden to do so, even if we have not joined 666191672Sbms * the address; protocols will filter it later, 667191672Sbms * thus deferring a hash lookup and lock acquisition 668191672Sbms * at the expense of an m_copym(). 66953541Sshin */ 67053541Sshin ip6_mloopback(ifp, m, dst); 67156723Sshin } else { 67256723Sshin /* 67356723Sshin * If we are acting as a multicast router, perform 67456723Sshin * multicast forwarding as if the packet had just 67556723Sshin * arrived on the interface to which we are about 67656723Sshin * to send. The multicast forwarding function 67756723Sshin * recursively calls this function, using the 67856723Sshin * IPV6_FORWARDING flag to prevent infinite recursion. 67956723Sshin * 68056723Sshin * Multicasts that are looped back by ip6_mloopback(), 68156723Sshin * above, will be forwarded by the ip6_input() routine, 68256723Sshin * if necessary. 68356723Sshin */ 684191672Sbms if (V_ip6_mrouter && (flags & IPV6_FORWARDING) == 0) { 685148385Sume /* 686148385Sume * XXX: ip6_mforward expects that rcvif is NULL 687148385Sume * when it is called from the originating path. 688248321Sglebius * However, it may not always be the case. 689148385Sume */ 690148385Sume m->m_pkthdr.rcvif = NULL; 69162587Sitojun if (ip6_mforward(ip6, ifp, m) != 0) { 69256723Sshin m_freem(m); 69356723Sshin goto done; 69456723Sshin } 69556723Sshin } 69653541Sshin } 69753541Sshin /* 69853541Sshin * Multicasts with a hoplimit of zero may be looped back, 69953541Sshin * above, but must not be transmitted on a network. 70053541Sshin * Also, multicasts addressed to the loopback interface 70153541Sshin * are not sent -- the above call to ip6_mloopback() will 70253541Sshin * loop back a copy if this host actually belongs to the 70353541Sshin * destination group on the loopback interface. 70453541Sshin */ 705121472Sume if (ip6->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK) || 706121472Sume IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)) { 70753541Sshin m_freem(m); 70853541Sshin goto done; 70953541Sshin } 71053541Sshin } 71153541Sshin 71253541Sshin /* 71353541Sshin * Fill the outgoing inteface to tell the upper layer 71453541Sshin * to increment per-interface statistics. 71553541Sshin */ 71653541Sshin if (ifpp) 71753541Sshin *ifpp = ifp; 71853541Sshin 719121283Sume /* Determine path MTU. */ 720121472Sume if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu, 721231852Sbz &alwaysfrag, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m))) != 0) 722121283Sume goto bad; 72353541Sshin 72478064Sume /* 725125595Sume * The caller of this function may specify to use the minimum MTU 726125595Sume * in some cases. 727125595Sume * An advanced API option (IPV6_USE_MIN_MTU) can also override MTU 728125595Sume * setting. The logic is a bit complicated; by default, unicast 729125595Sume * packets will follow path MTU while multicast packets will be sent at 730125595Sume * the minimum MTU. If IP6PO_MINMTU_ALL is specified, all packets 731125595Sume * including unicast ones will be sent at the minimum MTU. Multicast 732125595Sume * packets will always be sent at the minimum MTU unless 733125595Sume * IP6PO_MINMTU_DISABLE is explicitly specified. 734125595Sume * See RFC 3542 for more details. 73578064Sume */ 736125595Sume if (mtu > IPV6_MMTU) { 737125595Sume if ((flags & IPV6_MINMTU)) 738125595Sume mtu = IPV6_MMTU; 739125595Sume else if (opt && opt->ip6po_minmtu == IP6PO_MINMTU_ALL) 740125595Sume mtu = IPV6_MMTU; 741125595Sume else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && 742125595Sume (opt == NULL || 743125595Sume opt->ip6po_minmtu != IP6PO_MINMTU_DISABLE)) { 744125595Sume mtu = IPV6_MMTU; 745125595Sume } 746125595Sume } 74778064Sume 74878064Sume /* 74978064Sume * clear embedded scope identifiers if necessary. 75078064Sume * in6_clearscope will touch the addresses only when necessary. 75178064Sume */ 75278064Sume in6_clearscope(&ip6->ip6_src); 75378064Sume in6_clearscope(&ip6->ip6_dst); 75453541Sshin 75553541Sshin /* 75653541Sshin * If the outgoing packet contains a hop-by-hop options header, 75753541Sshin * it must be examined and processed even by the source node. 75853541Sshin * (RFC 2460, section 4.) 75953541Sshin */ 76053541Sshin if (exthdrs.ip6e_hbh) { 76178064Sume struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *); 762142674Sume u_int32_t dummy; /* XXX unused */ 763142674Sume u_int32_t plen = 0; /* XXX: ip6_process will check the value */ 76453541Sshin 76578064Sume#ifdef DIAGNOSTIC 76678064Sume if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len) 767215956Sbrucec panic("ip6e_hbh is not contiguous"); 76878064Sume#endif 76953541Sshin /* 77053541Sshin * XXX: if we have to send an ICMPv6 error to the sender, 77153541Sshin * we need the M_LOOP flag since icmp6_error() expects 77253541Sshin * the IPv6 and the hop-by-hop options header are 773215956Sbrucec * contiguous unless the flag is set. 77453541Sshin */ 77553541Sshin m->m_flags |= M_LOOP; 77653541Sshin m->m_pkthdr.rcvif = ifp; 777120913Sume if (ip6_process_hopopts(m, (u_int8_t *)(hbh + 1), 778120913Sume ((hbh->ip6h_len + 1) << 3) - sizeof(struct ip6_hbh), 779142674Sume &dummy, &plen) < 0) { 78053541Sshin /* m was already freed at this point */ 78153541Sshin error = EINVAL;/* better error? */ 78253541Sshin goto done; 78353541Sshin } 78453541Sshin m->m_flags &= ~M_LOOP; /* XXX */ 78553541Sshin m->m_pkthdr.rcvif = NULL; 78653541Sshin } 78753541Sshin 788134383Sandre /* Jump over all PFIL processing if hooks are not active. */ 789197952Sjulian if (!PFIL_HOOKED(&V_inet6_pfil_hook)) 790134383Sandre goto passout; 791134383Sandre 792145246Sbrooks odst = ip6->ip6_dst; 793134383Sandre /* Run through list of hooks for output packets. */ 794197952Sjulian error = pfil_run_hooks(&V_inet6_pfil_hook, &m, ifp, PFIL_OUT, inp); 795120593Ssam if (error != 0 || m == NULL) 796120386Ssam goto done; 797120386Ssam ip6 = mtod(m, struct ip6_hdr *); 798120913Sume 799145246Sbrooks /* See if destination IP address was changed by packet filter. */ 800145246Sbrooks if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) { 801145246Sbrooks m->m_flags |= M_SKIP_FIREWALL; 802145246Sbrooks /* If destination is now ourself drop to ip6_input(). */ 803225044Sbz if (in6_localip(&ip6->ip6_dst)) { 804225044Sbz m->m_flags |= M_FASTFWD_OURS; 805145246Sbrooks if (m->m_pkthdr.rcvif == NULL) 806181803Sbz m->m_pkthdr.rcvif = V_loif; 807236170Sbz if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 808145246Sbrooks m->m_pkthdr.csum_flags |= 809236170Sbz CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR; 810145246Sbrooks m->m_pkthdr.csum_data = 0xffff; 811145246Sbrooks } 812205075Srrs#ifdef SCTP 813236332Stuexen if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) 814205075Srrs m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; 815205075Srrs#endif 816145246Sbrooks error = netisr_queue(NETISR_IPV6, m); 817145246Sbrooks goto done; 818145246Sbrooks } else 819145246Sbrooks goto again; /* Redo the routing table lookup. */ 820145246Sbrooks } 821145246Sbrooks 822225044Sbz /* See if local, if yes, send it to netisr. */ 823225044Sbz if (m->m_flags & M_FASTFWD_OURS) { 824225044Sbz if (m->m_pkthdr.rcvif == NULL) 825225044Sbz m->m_pkthdr.rcvif = V_loif; 826236170Sbz if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 827225044Sbz m->m_pkthdr.csum_flags |= 828236170Sbz CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR; 829225044Sbz m->m_pkthdr.csum_data = 0xffff; 830225044Sbz } 831225044Sbz#ifdef SCTP 832236332Stuexen if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) 833235958Sbz m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; 834236332Stuexen#endif 835225044Sbz error = netisr_queue(NETISR_IPV6, m); 836225044Sbz goto done; 837225044Sbz } 838225044Sbz /* Or forward to some other address? */ 839242463Sae if ((m->m_flags & M_IP6_NEXTHOP) && 840242463Sae (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { 841225044Sbz dst = (struct sockaddr_in6 *)&ro->ro_dst; 842244441Sae bcopy((fwd_tag+1), &dst_sa, sizeof(struct sockaddr_in6)); 843225044Sbz m->m_flags |= M_SKIP_FIREWALL; 844242463Sae m->m_flags &= ~M_IP6_NEXTHOP; 845225044Sbz m_tag_delete(m, fwd_tag); 846225044Sbz goto again; 847225044Sbz } 848145246Sbrooks 849134383Sandrepassout: 85064060Sdarrenr /* 85153541Sshin * Send the packet to the outgoing interface. 85253541Sshin * If necessary, do IPv6 fragmentation before sending. 853121472Sume * 854121472Sume * the logic here is rather complex: 855121472Sume * 1: normal case (dontfrag == 0, alwaysfrag == 0) 856121472Sume * 1-a: send as is if tlen <= path mtu 857121472Sume * 1-b: fragment if tlen > path mtu 858121472Sume * 859121472Sume * 2: if user asks us not to fragment (dontfrag == 1) 860121472Sume * 2-a: send as is if tlen <= interface mtu 861121472Sume * 2-b: error if tlen > interface mtu 862121472Sume * 863121472Sume * 3: if we always need to attach fragment header (alwaysfrag == 1) 864121472Sume * always fragment 865121472Sume * 866121472Sume * 4: if dontfrag == 1 && alwaysfrag == 1 867121472Sume * error, as we cannot handle this conflicting request 86853541Sshin */ 869235958Sbz sw_csum = m->m_pkthdr.csum_flags; 870235958Sbz if (!hdrsplit) { 871235958Sbz tso = ((sw_csum & ifp->if_hwassist & CSUM_TSO) != 0) ? 1 : 0; 872235958Sbz sw_csum &= ~ifp->if_hwassist; 873235958Sbz } else 874235958Sbz tso = 0; 875235958Sbz /* 876235958Sbz * If we added extension headers, we will not do TSO and calculate the 877235958Sbz * checksums ourselves for now. 878235958Sbz * XXX-BZ Need a framework to know when the NIC can handle it, even 879235958Sbz * with ext. hdrs. 880235958Sbz */ 881236170Sbz if (sw_csum & CSUM_DELAY_DATA_IPV6) { 882236170Sbz sw_csum &= ~CSUM_DELAY_DATA_IPV6; 883236130Sbz in6_delayed_cksum(m, plen, sizeof(struct ip6_hdr)); 884235958Sbz } 885205075Srrs#ifdef SCTP 886236332Stuexen if (sw_csum & CSUM_SCTP_IPV6) { 887236332Stuexen sw_csum &= ~CSUM_SCTP_IPV6; 888205104Srrs sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); 889205075Srrs } 890205075Srrs#endif 891235958Sbz m->m_pkthdr.csum_flags &= ifp->if_hwassist; 89253541Sshin tlen = m->m_pkthdr.len; 893120913Sume 894235958Sbz if ((opt && (opt->ip6po_flags & IP6PO_DONTFRAG)) || tso) 895121472Sume dontfrag = 1; 896121472Sume else 897121472Sume dontfrag = 0; 898121472Sume if (dontfrag && alwaysfrag) { /* case 4 */ 899121472Sume /* conflicting request - can't transmit */ 900121472Sume error = EMSGSIZE; 901121472Sume goto bad; 902121472Sume } 903235958Sbz if (dontfrag && tlen > IN6_LINKMTU(ifp) && !tso) { /* case 2-b */ 904121472Sume /* 905121472Sume * Even if the DONTFRAG option is specified, we cannot send the 906121472Sume * packet when the data length is larger than the MTU of the 907121472Sume * outgoing interface. 908279911Sae * Notify the error by sending IPV6_PATHMTU ancillary data if 909279911Sae * application wanted to know the MTU value. Also return an 910279911Sae * error code (this is not described in the API spec). 911121472Sume */ 912279911Sae if (inp != NULL) 913279911Sae ip6_notify_pmtu(inp, &dst_sa, (u_int32_t)mtu); 914121472Sume error = EMSGSIZE; 915121472Sume goto bad; 916121472Sume } 917121472Sume 918121472Sume /* 919121472Sume * transmit packet without fragmentation 920121472Sume */ 921121472Sume if (dontfrag || (!alwaysfrag && tlen <= mtu)) { /* case 1-a and 2-a */ 922121472Sume struct in6_ifaddr *ia6; 923121472Sume 924121472Sume ip6 = mtod(m, struct ip6_hdr *); 925121472Sume ia6 = in6_ifawithifp(ifp, &ip6->ip6_src); 926121472Sume if (ia6) { 927121472Sume /* Record statistics for this interface address. */ 928121472Sume ia6->ia_ifa.if_opackets++; 929121472Sume ia6->ia_ifa.if_obytes += m->m_pkthdr.len; 930194760Srwatson ifa_free(&ia6->ia_ifa); 931121472Sume } 93262587Sitojun error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); 93353541Sshin goto done; 934121472Sume } 935121472Sume 936121472Sume /* 937121472Sume * try to fragment the packet. case 1-b and 3 938121472Sume */ 939121472Sume if (mtu < IPV6_MMTU) { 940121472Sume /* path MTU cannot be less than IPV6_MMTU */ 94153541Sshin error = EMSGSIZE; 94253541Sshin in6_ifstat_inc(ifp, ifs6_out_fragfail); 94353541Sshin goto bad; 944120913Sume } else if (ip6->ip6_plen == 0) { 945120913Sume /* jumbo payload cannot be fragmented */ 94653541Sshin error = EMSGSIZE; 94753541Sshin in6_ifstat_inc(ifp, ifs6_out_fragfail); 94853541Sshin goto bad; 94953541Sshin } else { 95053541Sshin u_char nextproto; 951171133Sgnn 952129196Swpaul int qslots = ifp->if_snd.ifq_maxlen - ifp->if_snd.ifq_len; 95353541Sshin 95453541Sshin /* 95553541Sshin * Too large for the destination or interface; 95653541Sshin * fragment if possible. 95753541Sshin * Must be able to put at least 8 bytes per fragment. 95853541Sshin */ 95953541Sshin hlen = unfragpartlen; 96053541Sshin if (mtu > IPV6_MAXPACKET) 96153541Sshin mtu = IPV6_MAXPACKET; 96278064Sume 96353541Sshin len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7; 96453541Sshin if (len < 8) { 96553541Sshin error = EMSGSIZE; 96653541Sshin in6_ifstat_inc(ifp, ifs6_out_fragfail); 96753541Sshin goto bad; 96853541Sshin } 96953541Sshin 970129196Swpaul /* 971129196Swpaul * Verify that we have any chance at all of being able to queue 972129196Swpaul * the packet or packet fragments 973129196Swpaul */ 974129196Swpaul if (qslots <= 0 || ((u_int)qslots * (mtu - hlen) 975129196Swpaul < tlen /* - hlen */)) { 976129196Swpaul error = ENOBUFS; 977249294Sae IP6STAT_INC(ip6s_odropped); 978129196Swpaul goto bad; 979129196Swpaul } 980129196Swpaul 981235958Sbz 982235958Sbz /* 983235958Sbz * If the interface will not calculate checksums on 984235958Sbz * fragmented packets, then do it here. 985235958Sbz * XXX-BZ handle the hw offloading case. Need flags. 986235958Sbz */ 987236170Sbz if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 988236130Sbz in6_delayed_cksum(m, plen, hlen); 989236170Sbz m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; 990235958Sbz } 991235958Sbz#ifdef SCTP 992236332Stuexen if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { 993235958Sbz sctp_delayed_cksum(m, hlen); 994236332Stuexen m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; 995235958Sbz } 996235958Sbz#endif 99753541Sshin /* 99853541Sshin * Change the next header field of the last header in the 99953541Sshin * unfragmentable part. 100053541Sshin */ 100153541Sshin if (exthdrs.ip6e_rthdr) { 100253541Sshin nextproto = *mtod(exthdrs.ip6e_rthdr, u_char *); 100353541Sshin *mtod(exthdrs.ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT; 100453541Sshin } else if (exthdrs.ip6e_dest1) { 100553541Sshin nextproto = *mtod(exthdrs.ip6e_dest1, u_char *); 100653541Sshin *mtod(exthdrs.ip6e_dest1, u_char *) = IPPROTO_FRAGMENT; 100753541Sshin } else if (exthdrs.ip6e_hbh) { 100853541Sshin nextproto = *mtod(exthdrs.ip6e_hbh, u_char *); 100953541Sshin *mtod(exthdrs.ip6e_hbh, u_char *) = IPPROTO_FRAGMENT; 101053541Sshin } else { 101153541Sshin nextproto = ip6->ip6_nxt; 101253541Sshin ip6->ip6_nxt = IPPROTO_FRAGMENT; 101353541Sshin } 101453541Sshin 101553541Sshin /* 101653541Sshin * Loop through length of segment after first fragment, 101795023Ssuz * make new header and copy data of each part and link onto 101895023Ssuz * chain. 101953541Sshin */ 102053541Sshin m0 = m; 1021284572Skp id = htonl(ip6_randomid()); 1022284572Skp if ((error = ip6_fragment(ifp, m, hlen, nextproto, len, id))) 1023284570Skp goto sendorfree; 102453541Sshin 102553541Sshin in6_ifstat_inc(ifp, ifs6_out_fragok); 102653541Sshin } 102753541Sshin 102853541Sshin /* 102953541Sshin * Remove leading garbages. 103053541Sshin */ 103153541Sshinsendorfree: 103253541Sshin m = m0->m_nextpkt; 103353541Sshin m0->m_nextpkt = 0; 103453541Sshin m_freem(m0); 103553541Sshin for (m0 = m; m; m = m0) { 103653541Sshin m0 = m->m_nextpkt; 103753541Sshin m->m_nextpkt = 0; 103853541Sshin if (error == 0) { 1039171260Sdelphij /* Record statistics for this interface address. */ 1040171260Sdelphij if (ia) { 1041171260Sdelphij ia->ia_ifa.if_opackets++; 1042171260Sdelphij ia->ia_ifa.if_obytes += m->m_pkthdr.len; 1043171260Sdelphij } 104462587Sitojun error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); 104553541Sshin } else 104653541Sshin m_freem(m); 104753541Sshin } 104853541Sshin 104953541Sshin if (error == 0) 1050249294Sae IP6STAT_INC(ip6s_fragmented); 105153541Sshin 105253541Sshindone: 1053238092Sglebius if (ro == &ip6route) 1054238092Sglebius RO_RTFREE(ro); 1055238092Sglebius if (ro_pmtu == &ip6route) 1056238092Sglebius RO_RTFREE(ro_pmtu); 1057120856Sume return (error); 105853541Sshin 105953541Sshinfreehdrs: 106053541Sshin m_freem(exthdrs.ip6e_hbh); /* m_freem will check if mbuf is 0 */ 106153541Sshin m_freem(exthdrs.ip6e_dest1); 106253541Sshin m_freem(exthdrs.ip6e_rthdr); 106353541Sshin m_freem(exthdrs.ip6e_dest2); 1064120913Sume /* FALLTHROUGH */ 106553541Sshinbad: 1066171133Sgnn if (m) 1067171133Sgnn m_freem(m); 106853541Sshin goto done; 106953541Sshin} 107053541Sshin 107153541Sshinstatic int 1072171259Sdelphijip6_copyexthdr(struct mbuf **mp, caddr_t hdr, int hlen) 107353541Sshin{ 107453541Sshin struct mbuf *m; 107553541Sshin 107653541Sshin if (hlen > MCLBYTES) 1077120856Sume return (ENOBUFS); /* XXX */ 107853541Sshin 1079248328Sglebius if (hlen > MLEN) 1080248328Sglebius m = m_getcl(M_NOWAIT, MT_DATA, 0); 1081248328Sglebius else 1082248328Sglebius m = m_get(M_NOWAIT, MT_DATA); 1083248328Sglebius if (m == NULL) 1084120856Sume return (ENOBUFS); 108553541Sshin m->m_len = hlen; 108653541Sshin if (hdr) 108753541Sshin bcopy(hdr, mtod(m, caddr_t), hlen); 108853541Sshin 108953541Sshin *mp = m; 1090120856Sume return (0); 109153541Sshin} 109253541Sshin 109353541Sshin/* 109453541Sshin * Insert jumbo payload option. 109553541Sshin */ 109653541Sshinstatic int 1097171259Sdelphijip6_insert_jumboopt(struct ip6_exthdrs *exthdrs, u_int32_t plen) 109853541Sshin{ 109953541Sshin struct mbuf *mopt; 110053541Sshin u_char *optbuf; 110178064Sume u_int32_t v; 110253541Sshin 110353541Sshin#define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */ 110453541Sshin 110553541Sshin /* 110653541Sshin * If there is no hop-by-hop options header, allocate new one. 110753541Sshin * If there is one but it doesn't have enough space to store the 110853541Sshin * jumbo payload option, allocate a cluster to store the whole options. 110953541Sshin * Otherwise, use it to store the options. 111053541Sshin */ 111153541Sshin if (exthdrs->ip6e_hbh == 0) { 1112248328Sglebius mopt = m_get(M_NOWAIT, MT_DATA); 1113248328Sglebius if (mopt == NULL) 1114120856Sume return (ENOBUFS); 111553541Sshin mopt->m_len = JUMBOOPTLEN; 111653541Sshin optbuf = mtod(mopt, u_char *); 111753541Sshin optbuf[1] = 0; /* = ((JUMBOOPTLEN) >> 3) - 1 */ 111853541Sshin exthdrs->ip6e_hbh = mopt; 111953541Sshin } else { 112053541Sshin struct ip6_hbh *hbh; 112153541Sshin 112253541Sshin mopt = exthdrs->ip6e_hbh; 112353541Sshin if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) { 112478064Sume /* 112578064Sume * XXX assumption: 112678064Sume * - exthdrs->ip6e_hbh is not referenced from places 112778064Sume * other than exthdrs. 112878064Sume * - exthdrs->ip6e_hbh is not an mbuf chain. 112978064Sume */ 113053541Sshin int oldoptlen = mopt->m_len; 113178064Sume struct mbuf *n; 113253541Sshin 113378064Sume /* 113478064Sume * XXX: give up if the whole (new) hbh header does 113578064Sume * not fit even in an mbuf cluster. 113678064Sume */ 113778064Sume if (oldoptlen + JUMBOOPTLEN > MCLBYTES) 1138120856Sume return (ENOBUFS); 113953541Sshin 114078064Sume /* 114178064Sume * As a consequence, we must always prepare a cluster 114278064Sume * at this point. 114378064Sume */ 1144248328Sglebius n = m_getcl(M_NOWAIT, MT_DATA, 0); 1145248328Sglebius if (n == NULL) 1146120856Sume return (ENOBUFS); 114778064Sume n->m_len = oldoptlen + JUMBOOPTLEN; 114878064Sume bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t), 1149120913Sume oldoptlen); 115078064Sume optbuf = mtod(n, caddr_t) + oldoptlen; 115178064Sume m_freem(mopt); 115278064Sume mopt = exthdrs->ip6e_hbh = n; 115353541Sshin } else { 115453541Sshin optbuf = mtod(mopt, u_char *) + mopt->m_len; 115553541Sshin mopt->m_len += JUMBOOPTLEN; 115653541Sshin } 115753541Sshin optbuf[0] = IP6OPT_PADN; 115853541Sshin optbuf[1] = 1; 115953541Sshin 116053541Sshin /* 116153541Sshin * Adjust the header length according to the pad and 116253541Sshin * the jumbo payload option. 116353541Sshin */ 116453541Sshin hbh = mtod(mopt, struct ip6_hbh *); 116553541Sshin hbh->ip6h_len += (JUMBOOPTLEN >> 3); 116653541Sshin } 116753541Sshin 116853541Sshin /* fill in the option. */ 116953541Sshin optbuf[2] = IP6OPT_JUMBO; 117053541Sshin optbuf[3] = 4; 117178064Sume v = (u_int32_t)htonl(plen + JUMBOOPTLEN); 117278064Sume bcopy(&v, &optbuf[4], sizeof(u_int32_t)); 117353541Sshin 117453541Sshin /* finally, adjust the packet header length */ 117553541Sshin exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN; 117653541Sshin 1177120856Sume return (0); 117853541Sshin#undef JUMBOOPTLEN 117953541Sshin} 118053541Sshin 118153541Sshin/* 118253541Sshin * Insert fragment header and copy unfragmentable header portions. 118353541Sshin */ 118453541Sshinstatic int 1185171259Sdelphijip6_insertfraghdr(struct mbuf *m0, struct mbuf *m, int hlen, 1186171259Sdelphij struct ip6_frag **frghdrp) 118753541Sshin{ 118853541Sshin struct mbuf *n, *mlast; 118953541Sshin 119053541Sshin if (hlen > sizeof(struct ip6_hdr)) { 119153541Sshin n = m_copym(m0, sizeof(struct ip6_hdr), 1192243882Sglebius hlen - sizeof(struct ip6_hdr), M_NOWAIT); 119353541Sshin if (n == 0) 1194120856Sume return (ENOBUFS); 119553541Sshin m->m_next = n; 119653541Sshin } else 119753541Sshin n = m; 119853541Sshin 119953541Sshin /* Search for the last mbuf of unfragmentable part. */ 120053541Sshin for (mlast = n; mlast->m_next; mlast = mlast->m_next) 120153541Sshin ; 120253541Sshin 120353541Sshin if ((mlast->m_flags & M_EXT) == 0 && 120462587Sitojun M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) { 120553541Sshin /* use the trailing space of the last mbuf for the fragment hdr */ 1206120913Sume *frghdrp = (struct ip6_frag *)(mtod(mlast, caddr_t) + 1207120913Sume mlast->m_len); 120853541Sshin mlast->m_len += sizeof(struct ip6_frag); 120953541Sshin m->m_pkthdr.len += sizeof(struct ip6_frag); 121053541Sshin } else { 121153541Sshin /* allocate a new mbuf for the fragment header */ 121253541Sshin struct mbuf *mfrg; 121353541Sshin 1214248328Sglebius mfrg = m_get(M_NOWAIT, MT_DATA); 1215248328Sglebius if (mfrg == NULL) 1216120856Sume return (ENOBUFS); 121753541Sshin mfrg->m_len = sizeof(struct ip6_frag); 121853541Sshin *frghdrp = mtod(mfrg, struct ip6_frag *); 121953541Sshin mlast->m_next = mfrg; 122053541Sshin } 122153541Sshin 1222120856Sume return (0); 122353541Sshin} 122453541Sshin 1225121283Sumestatic int 1226171259Sdelphijip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro, 1227171259Sdelphij struct ifnet *ifp, struct in6_addr *dst, u_long *mtup, 1228232127Sbz int *alwaysfragp, u_int fibnum) 1229121283Sume{ 1230121283Sume u_int32_t mtu = 0; 1231121472Sume int alwaysfrag = 0; 1232121283Sume int error = 0; 1233121283Sume 1234121283Sume if (ro_pmtu != ro) { 1235121283Sume /* The first hop and the final destination may differ. */ 1236121283Sume struct sockaddr_in6 *sa6_dst = 1237121472Sume (struct sockaddr_in6 *)&ro_pmtu->ro_dst; 1238121283Sume if (ro_pmtu->ro_rt && 1239122846Sume ((ro_pmtu->ro_rt->rt_flags & RTF_UP) == 0 || 1240121283Sume !IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst))) { 1241121283Sume RTFREE(ro_pmtu->ro_rt); 1242121283Sume ro_pmtu->ro_rt = (struct rtentry *)NULL; 1243121283Sume } 1244121283Sume if (ro_pmtu->ro_rt == NULL) { 1245121283Sume bzero(sa6_dst, sizeof(*sa6_dst)); 1246121283Sume sa6_dst->sin6_family = AF_INET6; 1247121283Sume sa6_dst->sin6_len = sizeof(struct sockaddr_in6); 1248121283Sume sa6_dst->sin6_addr = *dst; 1249121283Sume 1250231852Sbz in6_rtalloc(ro_pmtu, fibnum); 1251121283Sume } 1252121283Sume } 1253121283Sume if (ro_pmtu->ro_rt) { 1254121283Sume u_int32_t ifmtu; 1255122922Sandre struct in_conninfo inc; 1256121283Sume 1257122922Sandre bzero(&inc, sizeof(inc)); 1258186222Sbz inc.inc_flags |= INC_ISIPV6; 1259122922Sandre inc.inc6_faddr = *dst; 1260122922Sandre 1261121283Sume if (ifp == NULL) 1262121283Sume ifp = ro_pmtu->ro_rt->rt_ifp; 1263121283Sume ifmtu = IN6_LINKMTU(ifp); 1264122922Sandre mtu = tcp_hc_getmtu(&inc); 1265122922Sandre if (mtu) 1266263478Sglebius mtu = min(mtu, ro_pmtu->ro_rt->rt_mtu); 1267122922Sandre else 1268263478Sglebius mtu = ro_pmtu->ro_rt->rt_mtu; 1269121283Sume if (mtu == 0) 1270121283Sume mtu = ifmtu; 1271121472Sume else if (mtu < IPV6_MMTU) { 1272121283Sume /* 1273121472Sume * RFC2460 section 5, last paragraph: 1274121472Sume * if we record ICMPv6 too big message with 1275121472Sume * mtu < IPV6_MMTU, transmit packets sized IPV6_MMTU 1276121472Sume * or smaller, with framgent header attached. 1277121472Sume * (fragment header is needed regardless from the 1278121472Sume * packet size, for translators to identify packets) 1279121472Sume */ 1280121472Sume alwaysfrag = 1; 1281121472Sume mtu = IPV6_MMTU; 1282121472Sume } else if (mtu > ifmtu) { 1283121472Sume /* 1284121283Sume * The MTU on the route is larger than the MTU on 1285121283Sume * the interface! This shouldn't happen, unless the 1286121283Sume * MTU of the interface has been changed after the 1287121283Sume * interface was brought up. Change the MTU in the 1288121283Sume * route to match the interface MTU (as long as the 1289121283Sume * field isn't locked). 1290121283Sume */ 1291121315Sume mtu = ifmtu; 1292263478Sglebius ro_pmtu->ro_rt->rt_mtu = mtu; 1293121283Sume } 1294121283Sume } else if (ifp) { 1295121283Sume mtu = IN6_LINKMTU(ifp); 1296121283Sume } else 1297121283Sume error = EHOSTUNREACH; /* XXX */ 1298121283Sume 1299121283Sume *mtup = mtu; 1300121472Sume if (alwaysfragp) 1301121472Sume *alwaysfragp = alwaysfrag; 1302121283Sume return (error); 1303121283Sume} 1304121283Sume 130553541Sshin/* 130653541Sshin * IP6 socket option processing. 130753541Sshin */ 130853541Sshinint 1309171259Sdelphijip6_ctloutput(struct socket *so, struct sockopt *sopt) 131053541Sshin{ 1311175630Sbz int optdatalen, uproto; 1312121472Sume void *optdata; 131378064Sume struct inpcb *in6p = sotoinpcb(so); 131453541Sshin int error, optval; 131553541Sshin int level, op, optname; 131653541Sshin int optlen; 131783366Sjulian struct thread *td; 131853541Sshin 1319180957Srwatson level = sopt->sopt_level; 1320180957Srwatson op = sopt->sopt_dir; 1321180957Srwatson optname = sopt->sopt_name; 1322180957Srwatson optlen = sopt->sopt_valsize; 1323180957Srwatson td = sopt->sopt_td; 1324180957Srwatson error = 0; 1325180957Srwatson optval = 0; 1326121472Sume uproto = (int)so->so_proto->pr_protocol; 132753541Sshin 1328227207Strociny if (level != IPPROTO_IPV6) { 1329227207Strociny error = EINVAL; 1330227207Strociny 1331227207Strociny if (sopt->sopt_level == SOL_SOCKET && 1332227207Strociny sopt->sopt_dir == SOPT_SET) { 1333227207Strociny switch (sopt->sopt_name) { 1334227207Strociny case SO_REUSEADDR: 1335227207Strociny INP_WLOCK(in6p); 1336252710Strociny if ((so->so_options & SO_REUSEADDR) != 0) 1337252710Strociny in6p->inp_flags2 |= INP_REUSEADDR; 1338252710Strociny else 1339252710Strociny in6p->inp_flags2 &= ~INP_REUSEADDR; 1340227207Strociny INP_WUNLOCK(in6p); 1341227207Strociny error = 0; 1342227207Strociny break; 1343227207Strociny case SO_REUSEPORT: 1344227207Strociny INP_WLOCK(in6p); 1345227207Strociny if ((so->so_options & SO_REUSEPORT) != 0) 1346227207Strociny in6p->inp_flags2 |= INP_REUSEPORT; 1347227207Strociny else 1348227207Strociny in6p->inp_flags2 &= ~INP_REUSEPORT; 1349227207Strociny INP_WUNLOCK(in6p); 1350227207Strociny error = 0; 1351227207Strociny break; 1352231852Sbz case SO_SETFIB: 1353231852Sbz INP_WLOCK(in6p); 1354231852Sbz in6p->inp_inc.inc_fibnum = so->so_fibnum; 1355231852Sbz INP_WUNLOCK(in6p); 1356231852Sbz error = 0; 1357231852Sbz break; 1358227207Strociny default: 1359227207Strociny break; 1360227207Strociny } 1361227207Strociny } 1362227207Strociny } else { /* level == IPPROTO_IPV6 */ 136353541Sshin switch (op) { 136478064Sume 136553541Sshin case SOPT_SET: 136653541Sshin switch (optname) { 1367121472Sume case IPV6_2292PKTOPTIONS: 1368121472Sume#ifdef IPV6_PKTOPTIONS 136953541Sshin case IPV6_PKTOPTIONS: 1370121472Sume#endif 137178064Sume { 137253541Sshin struct mbuf *m; 137353541Sshin 137453541Sshin error = soopt_getm(sopt, &m); /* XXX */ 1375123740Speter if (error != 0) 137653541Sshin break; 137753541Sshin error = soopt_mcopyin(sopt, m); /* XXX */ 1378123740Speter if (error != 0) 137953541Sshin break; 138078064Sume error = ip6_pcbopts(&in6p->in6p_outputopts, 138178064Sume m, so, sopt); 138278064Sume m_freem(m); /* XXX */ 138378064Sume break; 138478064Sume } 138578064Sume 138678064Sume /* 138778064Sume * Use of some Hop-by-Hop options or some 138878064Sume * Destination options, might require special 138978064Sume * privilege. That is, normal applications 139078064Sume * (without special privilege) might be forbidden 139178064Sume * from setting certain options in outgoing packets, 139278064Sume * and might never see certain options in received 139378064Sume * packets. [RFC 2292 Section 6] 139478064Sume * KAME specific note: 139578064Sume * KAME prevents non-privileged users from sending or 139678064Sume * receiving ANY hbh/dst options in order to avoid 139778064Sume * overhead of parsing options in the kernel. 139878064Sume */ 1399121472Sume case IPV6_RECVHOPOPTS: 1400121472Sume case IPV6_RECVDSTOPTS: 1401121472Sume case IPV6_RECVRTHDRDSTOPTS: 1402175630Sbz if (td != NULL) { 1403175630Sbz error = priv_check(td, 1404175630Sbz PRIV_NETINET_SETHDROPTS); 1405175630Sbz if (error) 1406175630Sbz break; 1407121472Sume } 1408121472Sume /* FALLTHROUGH */ 140953541Sshin case IPV6_UNICAST_HOPS: 1410121472Sume case IPV6_HOPLIMIT: 141153541Sshin case IPV6_FAITH: 141278064Sume 1413121472Sume case IPV6_RECVPKTINFO: 1414121472Sume case IPV6_RECVHOPLIMIT: 1415121472Sume case IPV6_RECVRTHDR: 1416121472Sume case IPV6_RECVPATHMTU: 1417121472Sume case IPV6_RECVTCLASS: 141878064Sume case IPV6_V6ONLY: 1419121472Sume case IPV6_AUTOFLOWLABEL: 1420193217Spjd case IPV6_BINDANY: 1421193217Spjd if (optname == IPV6_BINDANY && td != NULL) { 1422193217Spjd error = priv_check(td, 1423193217Spjd PRIV_NETINET_BINDANY); 1424193217Spjd if (error) 1425193217Spjd break; 1426193217Spjd } 1427193217Spjd 142878064Sume if (optlen != sizeof(int)) { 142953541Sshin error = EINVAL; 143078064Sume break; 143178064Sume } 143278064Sume error = sooptcopyin(sopt, &optval, 143378064Sume sizeof optval, sizeof optval); 143478064Sume if (error) 143578064Sume break; 143678064Sume switch (optname) { 143753541Sshin 143878064Sume case IPV6_UNICAST_HOPS: 143978064Sume if (optval < -1 || optval >= 256) 144078064Sume error = EINVAL; 144178064Sume else { 144278064Sume /* -1 = kernel default */ 144378064Sume in6p->in6p_hops = optval; 1444186141Sbz if ((in6p->inp_vflag & 144578064Sume INP_IPV4) != 0) 144678064Sume in6p->inp_ip_ttl = optval; 144778064Sume } 144878064Sume break; 144953541Sshin#define OPTSET(bit) \ 145078064Sumedo { \ 1451239383Strociny INP_WLOCK(in6p); \ 145253541Sshin if (optval) \ 1453186141Sbz in6p->inp_flags |= (bit); \ 145453541Sshin else \ 1455186141Sbz in6p->inp_flags &= ~(bit); \ 1456239383Strociny INP_WUNLOCK(in6p); \ 1457120913Sume} while (/*CONSTCOND*/ 0) 1458121472Sume#define OPTSET2292(bit) \ 1459121472Sumedo { \ 1460239383Strociny INP_WLOCK(in6p); \ 1461186141Sbz in6p->inp_flags |= IN6P_RFC2292; \ 1462121472Sume if (optval) \ 1463186141Sbz in6p->inp_flags |= (bit); \ 1464121472Sume else \ 1465186141Sbz in6p->inp_flags &= ~(bit); \ 1466239383Strociny INP_WUNLOCK(in6p); \ 1467121472Sume} while (/*CONSTCOND*/ 0) 1468186141Sbz#define OPTBIT(bit) (in6p->inp_flags & (bit) ? 1 : 0) 146953541Sshin 1470121472Sume case IPV6_RECVPKTINFO: 1471121472Sume /* cannot mix with RFC2292 */ 1472121472Sume if (OPTBIT(IN6P_RFC2292)) { 1473121472Sume error = EINVAL; 1474121472Sume break; 1475121472Sume } 1476121472Sume OPTSET(IN6P_PKTINFO); 147778064Sume break; 147853541Sshin 1479121472Sume case IPV6_HOPLIMIT: 1480121472Sume { 1481121472Sume struct ip6_pktopts **optp; 1482121472Sume 1483121472Sume /* cannot mix with RFC2292 */ 1484121472Sume if (OPTBIT(IN6P_RFC2292)) { 1485121472Sume error = EINVAL; 1486121472Sume break; 1487121472Sume } 1488121472Sume optp = &in6p->in6p_outputopts; 1489121472Sume error = ip6_pcbopt(IPV6_HOPLIMIT, 1490175630Sbz (u_char *)&optval, sizeof(optval), 1491175630Sbz optp, (td != NULL) ? td->td_ucred : 1492175630Sbz NULL, uproto); 1493121472Sume break; 1494121472Sume } 1495121472Sume 1496121472Sume case IPV6_RECVHOPLIMIT: 1497121472Sume /* cannot mix with RFC2292 */ 1498121472Sume if (OPTBIT(IN6P_RFC2292)) { 1499121472Sume error = EINVAL; 1500121472Sume break; 1501121472Sume } 1502121472Sume OPTSET(IN6P_HOPLIMIT); 1503121472Sume break; 1504121472Sume 1505121472Sume case IPV6_RECVHOPOPTS: 1506121472Sume /* cannot mix with RFC2292 */ 1507121472Sume if (OPTBIT(IN6P_RFC2292)) { 1508121472Sume error = EINVAL; 1509121472Sume break; 1510121472Sume } 1511121472Sume OPTSET(IN6P_HOPOPTS); 1512121472Sume break; 1513121472Sume 1514121472Sume case IPV6_RECVDSTOPTS: 1515121472Sume /* cannot mix with RFC2292 */ 1516121472Sume if (OPTBIT(IN6P_RFC2292)) { 1517121472Sume error = EINVAL; 1518121472Sume break; 1519121472Sume } 1520121472Sume OPTSET(IN6P_DSTOPTS); 1521121472Sume break; 1522121472Sume 1523121472Sume case IPV6_RECVRTHDRDSTOPTS: 1524121472Sume /* cannot mix with RFC2292 */ 1525121472Sume if (OPTBIT(IN6P_RFC2292)) { 1526121472Sume error = EINVAL; 1527121472Sume break; 1528121472Sume } 1529121472Sume OPTSET(IN6P_RTHDRDSTOPTS); 1530121472Sume break; 1531121472Sume 1532121472Sume case IPV6_RECVRTHDR: 1533121472Sume /* cannot mix with RFC2292 */ 1534121472Sume if (OPTBIT(IN6P_RFC2292)) { 1535121472Sume error = EINVAL; 1536121472Sume break; 1537121472Sume } 1538121472Sume OPTSET(IN6P_RTHDR); 1539121472Sume break; 1540121472Sume 154178064Sume case IPV6_FAITH: 1542186223Sbz OPTSET(INP_FAITH); 154378064Sume break; 154453541Sshin 1545121472Sume case IPV6_RECVPATHMTU: 1546121472Sume /* 1547121472Sume * We ignore this option for TCP 1548121472Sume * sockets. 1549148169Sume * (RFC3542 leaves this case 1550121472Sume * unspecified.) 1551121472Sume */ 1552121472Sume if (uproto != IPPROTO_TCP) 1553121472Sume OPTSET(IN6P_MTU); 1554121472Sume break; 1555121472Sume 155678064Sume case IPV6_V6ONLY: 155778064Sume /* 155878721Sume * make setsockopt(IPV6_V6ONLY) 155978721Sume * available only prior to bind(2). 156078721Sume * see ipng mailing list, Jun 22 2001. 156178721Sume */ 1562186141Sbz if (in6p->inp_lport || 1563120913Sume !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { 156478721Sume error = EINVAL; 156578721Sume break; 156678721Sume } 156778064Sume OPTSET(IN6P_IPV6_V6ONLY); 1568100629Sume if (optval) 1569186141Sbz in6p->inp_vflag &= ~INP_IPV4; 1570100629Sume else 1571186141Sbz in6p->inp_vflag |= INP_IPV4; 157278064Sume break; 1573121472Sume case IPV6_RECVTCLASS: 1574121472Sume /* cannot mix with RFC2292 XXX */ 1575121472Sume if (OPTBIT(IN6P_RFC2292)) { 1576121472Sume error = EINVAL; 1577121472Sume break; 1578121472Sume } 1579121472Sume OPTSET(IN6P_TCLASS); 1580121472Sume break; 1581121472Sume case IPV6_AUTOFLOWLABEL: 1582121472Sume OPTSET(IN6P_AUTOFLOWLABEL); 1583121472Sume break; 1584121472Sume 1585193217Spjd case IPV6_BINDANY: 1586193217Spjd OPTSET(INP_BINDANY); 1587193217Spjd break; 158878064Sume } 158978064Sume break; 159053541Sshin 1591121472Sume case IPV6_TCLASS: 1592121472Sume case IPV6_DONTFRAG: 1593121472Sume case IPV6_USE_MIN_MTU: 1594121472Sume case IPV6_PREFER_TEMPADDR: 1595121472Sume if (optlen != sizeof(optval)) { 1596121472Sume error = EINVAL; 1597121472Sume break; 1598121472Sume } 1599121472Sume error = sooptcopyin(sopt, &optval, 1600121472Sume sizeof optval, sizeof optval); 1601121472Sume if (error) 1602121472Sume break; 1603121472Sume { 1604121472Sume struct ip6_pktopts **optp; 1605121472Sume optp = &in6p->in6p_outputopts; 1606121472Sume error = ip6_pcbopt(optname, 1607175630Sbz (u_char *)&optval, sizeof(optval), 1608175630Sbz optp, (td != NULL) ? td->td_ucred : 1609175630Sbz NULL, uproto); 1610121472Sume break; 1611121472Sume } 1612121472Sume 1613121472Sume case IPV6_2292PKTINFO: 1614121472Sume case IPV6_2292HOPLIMIT: 1615121472Sume case IPV6_2292HOPOPTS: 1616121472Sume case IPV6_2292DSTOPTS: 1617121472Sume case IPV6_2292RTHDR: 161878064Sume /* RFC 2292 */ 161978064Sume if (optlen != sizeof(int)) { 162078064Sume error = EINVAL; 162178064Sume break; 162253541Sshin } 162378064Sume error = sooptcopyin(sopt, &optval, 162478064Sume sizeof optval, sizeof optval); 162578064Sume if (error) 162678064Sume break; 162778064Sume switch (optname) { 1628121472Sume case IPV6_2292PKTINFO: 1629121472Sume OPTSET2292(IN6P_PKTINFO); 163078064Sume break; 1631121472Sume case IPV6_2292HOPLIMIT: 1632121472Sume OPTSET2292(IN6P_HOPLIMIT); 163378064Sume break; 1634121472Sume case IPV6_2292HOPOPTS: 163578064Sume /* 163678064Sume * Check super-user privilege. 163778064Sume * See comments for IPV6_RECVHOPOPTS. 163878064Sume */ 1639175630Sbz if (td != NULL) { 1640175630Sbz error = priv_check(td, 1641175630Sbz PRIV_NETINET_SETHDROPTS); 1642175630Sbz if (error) 1643175630Sbz return (error); 1644175630Sbz } 1645121472Sume OPTSET2292(IN6P_HOPOPTS); 164678064Sume break; 1647121472Sume case IPV6_2292DSTOPTS: 1648175630Sbz if (td != NULL) { 1649175630Sbz error = priv_check(td, 1650175630Sbz PRIV_NETINET_SETHDROPTS); 1651175630Sbz if (error) 1652175630Sbz return (error); 1653175630Sbz } 1654121472Sume OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */ 165578064Sume break; 1656121472Sume case IPV6_2292RTHDR: 1657121472Sume OPTSET2292(IN6P_RTHDR); 165878064Sume break; 165978064Sume } 166053541Sshin break; 1661121472Sume case IPV6_PKTINFO: 1662121472Sume case IPV6_HOPOPTS: 1663121472Sume case IPV6_RTHDR: 1664121472Sume case IPV6_DSTOPTS: 1665121472Sume case IPV6_RTHDRDSTOPTS: 1666121472Sume case IPV6_NEXTHOP: 1667121472Sume { 1668148169Sume /* new advanced API (RFC3542) */ 1669121472Sume u_char *optbuf; 1670148488Sume u_char optbuf_storage[MCLBYTES]; 1671121472Sume int optlen; 1672121472Sume struct ip6_pktopts **optp; 1673121472Sume 1674121472Sume /* cannot mix with RFC2292 */ 1675121472Sume if (OPTBIT(IN6P_RFC2292)) { 1676121472Sume error = EINVAL; 1677121472Sume break; 1678121472Sume } 1679121472Sume 1680148488Sume /* 1681148488Sume * We only ensure valsize is not too large 1682148488Sume * here. Further validation will be done 1683148488Sume * later. 1684148488Sume */ 1685148488Sume error = sooptcopyin(sopt, optbuf_storage, 1686148488Sume sizeof(optbuf_storage), 0); 1687127463Sume if (error) 1688127463Sume break; 1689121472Sume optlen = sopt->sopt_valsize; 1690148488Sume optbuf = optbuf_storage; 1691121472Sume optp = &in6p->in6p_outputopts; 1692175630Sbz error = ip6_pcbopt(optname, optbuf, optlen, 1693175630Sbz optp, (td != NULL) ? td->td_ucred : NULL, 1694175630Sbz uproto); 1695121472Sume break; 1696121472Sume } 169753541Sshin#undef OPTSET 169853541Sshin 169953541Sshin case IPV6_MULTICAST_IF: 170053541Sshin case IPV6_MULTICAST_HOPS: 170153541Sshin case IPV6_MULTICAST_LOOP: 170253541Sshin case IPV6_JOIN_GROUP: 170353541Sshin case IPV6_LEAVE_GROUP: 1704191672Sbms case IPV6_MSFILTER: 1705191672Sbms case MCAST_BLOCK_SOURCE: 1706191672Sbms case MCAST_UNBLOCK_SOURCE: 1707191672Sbms case MCAST_JOIN_GROUP: 1708191672Sbms case MCAST_LEAVE_GROUP: 1709191672Sbms case MCAST_JOIN_SOURCE_GROUP: 1710191672Sbms case MCAST_LEAVE_SOURCE_GROUP: 1711191672Sbms error = ip6_setmoptions(in6p, sopt); 171253541Sshin break; 171353541Sshin 171462587Sitojun case IPV6_PORTRANGE: 171562587Sitojun error = sooptcopyin(sopt, &optval, 171662587Sitojun sizeof optval, sizeof optval); 171762587Sitojun if (error) 171862587Sitojun break; 171953541Sshin 1720239383Strociny INP_WLOCK(in6p); 172162587Sitojun switch (optval) { 172262587Sitojun case IPV6_PORTRANGE_DEFAULT: 1723186223Sbz in6p->inp_flags &= ~(INP_LOWPORT); 1724186223Sbz in6p->inp_flags &= ~(INP_HIGHPORT); 172562587Sitojun break; 172653541Sshin 172762587Sitojun case IPV6_PORTRANGE_HIGH: 1728186223Sbz in6p->inp_flags &= ~(INP_LOWPORT); 1729186223Sbz in6p->inp_flags |= INP_HIGHPORT; 173062587Sitojun break; 173153541Sshin 173262587Sitojun case IPV6_PORTRANGE_LOW: 1733186223Sbz in6p->inp_flags &= ~(INP_HIGHPORT); 1734186223Sbz in6p->inp_flags |= INP_LOWPORT; 173562587Sitojun break; 173653541Sshin 173762587Sitojun default: 173862587Sitojun error = EINVAL; 173962587Sitojun break; 174062587Sitojun } 1741239383Strociny INP_WUNLOCK(in6p); 174253541Sshin break; 174353541Sshin 1744171167Sgnn#ifdef IPSEC 174553541Sshin case IPV6_IPSEC_POLICY: 1746175892Sbz { 1747175892Sbz caddr_t req; 174853541Sshin struct mbuf *m; 174953541Sshin 175062587Sitojun if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */ 175153541Sshin break; 175262587Sitojun if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */ 175353541Sshin break; 1754175892Sbz req = mtod(m, caddr_t); 1755188306Sbz error = ipsec_set_policy(in6p, optname, req, 1756175892Sbz m->m_len, (sopt->sopt_td != NULL) ? 1757175892Sbz sopt->sopt_td->td_ucred : NULL); 175853541Sshin m_freem(m); 175953541Sshin break; 1760175892Sbz } 1761171167Sgnn#endif /* IPSEC */ 176253541Sshin 176353541Sshin default: 176453541Sshin error = ENOPROTOOPT; 176553541Sshin break; 176653541Sshin } 176753541Sshin break; 176853541Sshin 176953541Sshin case SOPT_GET: 177053541Sshin switch (optname) { 177153541Sshin 1772121472Sume case IPV6_2292PKTOPTIONS: 1773121472Sume#ifdef IPV6_PKTOPTIONS 177453541Sshin case IPV6_PKTOPTIONS: 1775121472Sume#endif 1776121472Sume /* 1777121472Sume * RFC3542 (effectively) deprecated the 1778121472Sume * semantics of the 2292-style pktoptions. 1779121472Sume * Since it was not reliable in nature (i.e., 1780121472Sume * applications had to expect the lack of some 1781121472Sume * information after all), it would make sense 1782121472Sume * to simplify this part by always returning 1783121472Sume * empty data. 1784121472Sume */ 1785121472Sume sopt->sopt_valsize = 0; 178653541Sshin break; 178753541Sshin 1788121472Sume case IPV6_RECVHOPOPTS: 1789121472Sume case IPV6_RECVDSTOPTS: 1790121472Sume case IPV6_RECVRTHDRDSTOPTS: 179153541Sshin case IPV6_UNICAST_HOPS: 1792121472Sume case IPV6_RECVPKTINFO: 1793121472Sume case IPV6_RECVHOPLIMIT: 1794121472Sume case IPV6_RECVRTHDR: 1795121472Sume case IPV6_RECVPATHMTU: 179678064Sume 179753541Sshin case IPV6_FAITH: 179878064Sume case IPV6_V6ONLY: 179955872Sshin case IPV6_PORTRANGE: 1800121472Sume case IPV6_RECVTCLASS: 1801121472Sume case IPV6_AUTOFLOWLABEL: 1802213101Sattilio case IPV6_BINDANY: 180353541Sshin switch (optname) { 180453541Sshin 1805121472Sume case IPV6_RECVHOPOPTS: 1806121472Sume optval = OPTBIT(IN6P_HOPOPTS); 1807121472Sume break; 1808121472Sume 1809121472Sume case IPV6_RECVDSTOPTS: 1810121472Sume optval = OPTBIT(IN6P_DSTOPTS); 1811121472Sume break; 1812121472Sume 1813121472Sume case IPV6_RECVRTHDRDSTOPTS: 1814121472Sume optval = OPTBIT(IN6P_RTHDRDSTOPTS); 1815121472Sume break; 1816121472Sume 181753541Sshin case IPV6_UNICAST_HOPS: 181853541Sshin optval = in6p->in6p_hops; 181953541Sshin break; 182053541Sshin 1821121472Sume case IPV6_RECVPKTINFO: 1822121472Sume optval = OPTBIT(IN6P_PKTINFO); 182353541Sshin break; 182453541Sshin 1825121472Sume case IPV6_RECVHOPLIMIT: 1826121472Sume optval = OPTBIT(IN6P_HOPLIMIT); 1827121472Sume break; 1828121472Sume 1829121472Sume case IPV6_RECVRTHDR: 1830121472Sume optval = OPTBIT(IN6P_RTHDR); 1831121472Sume break; 1832121472Sume 1833121472Sume case IPV6_RECVPATHMTU: 1834121472Sume optval = OPTBIT(IN6P_MTU); 1835121472Sume break; 1836121472Sume 183753541Sshin case IPV6_FAITH: 1838186223Sbz optval = OPTBIT(INP_FAITH); 183953541Sshin break; 184053541Sshin 184178064Sume case IPV6_V6ONLY: 1842100508Sume optval = OPTBIT(IN6P_IPV6_V6ONLY); 184353541Sshin break; 184453541Sshin 184553541Sshin case IPV6_PORTRANGE: 184653541Sshin { 184753541Sshin int flags; 1848186141Sbz flags = in6p->inp_flags; 1849186223Sbz if (flags & INP_HIGHPORT) 185053541Sshin optval = IPV6_PORTRANGE_HIGH; 1851186223Sbz else if (flags & INP_LOWPORT) 185253541Sshin optval = IPV6_PORTRANGE_LOW; 185353541Sshin else 185453541Sshin optval = 0; 185553541Sshin break; 185653541Sshin } 1857121472Sume case IPV6_RECVTCLASS: 1858121472Sume optval = OPTBIT(IN6P_TCLASS); 1859121472Sume break; 1860121472Sume 1861121472Sume case IPV6_AUTOFLOWLABEL: 1862121472Sume optval = OPTBIT(IN6P_AUTOFLOWLABEL); 1863121472Sume break; 1864193217Spjd 1865193217Spjd case IPV6_BINDANY: 1866193217Spjd optval = OPTBIT(INP_BINDANY); 1867193217Spjd break; 186853541Sshin } 1869121472Sume if (error) 1870121472Sume break; 187153541Sshin error = sooptcopyout(sopt, &optval, 187253541Sshin sizeof optval); 187353541Sshin break; 187453541Sshin 1875121472Sume case IPV6_PATHMTU: 1876121472Sume { 1877121472Sume u_long pmtu = 0; 1878121472Sume struct ip6_mtuinfo mtuinfo; 1879122922Sandre struct route_in6 sro; 1880121472Sume 1881122922Sandre bzero(&sro, sizeof(sro)); 1882122922Sandre 1883121472Sume if (!(so->so_state & SS_ISCONNECTED)) 1884121472Sume return (ENOTCONN); 1885121472Sume /* 1886121472Sume * XXX: we dot not consider the case of source 1887121472Sume * routing, or optional information to specify 1888121472Sume * the outgoing interface. 1889121472Sume */ 1890122922Sandre error = ip6_getpmtu(&sro, NULL, NULL, 1891231852Sbz &in6p->in6p_faddr, &pmtu, NULL, 1892231852Sbz so->so_fibnum); 1893122922Sandre if (sro.ro_rt) 1894122922Sandre RTFREE(sro.ro_rt); 1895121472Sume if (error) 1896121472Sume break; 1897121472Sume if (pmtu > IPV6_MAXPACKET) 1898121472Sume pmtu = IPV6_MAXPACKET; 1899121472Sume 1900121472Sume bzero(&mtuinfo, sizeof(mtuinfo)); 1901121472Sume mtuinfo.ip6m_mtu = (u_int32_t)pmtu; 1902121472Sume optdata = (void *)&mtuinfo; 1903121472Sume optdatalen = sizeof(mtuinfo); 1904121472Sume error = sooptcopyout(sopt, optdata, 1905121472Sume optdatalen); 1906121472Sume break; 1907121472Sume } 1908121472Sume 1909121472Sume case IPV6_2292PKTINFO: 1910121472Sume case IPV6_2292HOPLIMIT: 1911121472Sume case IPV6_2292HOPOPTS: 1912121472Sume case IPV6_2292RTHDR: 1913121472Sume case IPV6_2292DSTOPTS: 191478064Sume switch (optname) { 1915121472Sume case IPV6_2292PKTINFO: 191678064Sume optval = OPTBIT(IN6P_PKTINFO); 191778064Sume break; 1918121472Sume case IPV6_2292HOPLIMIT: 191978064Sume optval = OPTBIT(IN6P_HOPLIMIT); 192078064Sume break; 1921121472Sume case IPV6_2292HOPOPTS: 192278064Sume optval = OPTBIT(IN6P_HOPOPTS); 192378064Sume break; 1924121472Sume case IPV6_2292RTHDR: 192578064Sume optval = OPTBIT(IN6P_RTHDR); 192678064Sume break; 1927121472Sume case IPV6_2292DSTOPTS: 192878064Sume optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); 192978064Sume break; 193078064Sume } 193178064Sume error = sooptcopyout(sopt, &optval, 1932121472Sume sizeof optval); 193378064Sume break; 1934121472Sume case IPV6_PKTINFO: 1935121472Sume case IPV6_HOPOPTS: 1936121472Sume case IPV6_RTHDR: 1937121472Sume case IPV6_DSTOPTS: 1938121472Sume case IPV6_RTHDRDSTOPTS: 1939121472Sume case IPV6_NEXTHOP: 1940121472Sume case IPV6_TCLASS: 1941121472Sume case IPV6_DONTFRAG: 1942121472Sume case IPV6_USE_MIN_MTU: 1943121472Sume case IPV6_PREFER_TEMPADDR: 1944121472Sume error = ip6_getpcbopt(in6p->in6p_outputopts, 1945121472Sume optname, sopt); 1946121472Sume break; 194778064Sume 194853541Sshin case IPV6_MULTICAST_IF: 194953541Sshin case IPV6_MULTICAST_HOPS: 195053541Sshin case IPV6_MULTICAST_LOOP: 1951191672Sbms case IPV6_MSFILTER: 1952191672Sbms error = ip6_getmoptions(in6p, sopt); 195353541Sshin break; 195453541Sshin 1955171167Sgnn#ifdef IPSEC 195653541Sshin case IPV6_IPSEC_POLICY: 195753541Sshin { 195862587Sitojun caddr_t req = NULL; 195962587Sitojun size_t len = 0; 196057855Sshin struct mbuf *m = NULL; 196162587Sitojun struct mbuf **mp = &m; 1962121472Sume size_t ovalsize = sopt->sopt_valsize; 1963121472Sume caddr_t oval = (caddr_t)sopt->sopt_val; 196453541Sshin 196562587Sitojun error = soopt_getm(sopt, &m); /* XXX */ 1966123760Sume if (error != 0) 196762587Sitojun break; 196862587Sitojun error = soopt_mcopyin(sopt, m); /* XXX */ 1969123760Sume if (error != 0) 197062587Sitojun break; 1971121472Sume sopt->sopt_valsize = ovalsize; 1972121472Sume sopt->sopt_val = oval; 197362587Sitojun if (m) { 197453541Sshin req = mtod(m, caddr_t); 197562587Sitojun len = m->m_len; 197662587Sitojun } 1977188306Sbz error = ipsec_get_policy(in6p, req, len, mp); 197853541Sshin if (error == 0) 1979120913Sume error = soopt_mcopyout(sopt, m); /* XXX */ 198078064Sume if (error == 0 && m) 198178064Sume m_freem(m); 198253541Sshin break; 198353541Sshin } 1984171167Sgnn#endif /* IPSEC */ 198553541Sshin 198653541Sshin default: 198753541Sshin error = ENOPROTOOPT; 198853541Sshin break; 198953541Sshin } 199053541Sshin break; 199153541Sshin } 199253541Sshin } 1993120856Sume return (error); 199453541Sshin} 199553541Sshin 1996121578Sumeint 1997171259Sdelphijip6_raw_ctloutput(struct socket *so, struct sockopt *sopt) 1998121578Sume{ 1999121578Sume int error = 0, optval, optlen; 2000121578Sume const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum); 2001186141Sbz struct inpcb *in6p = sotoinpcb(so); 2002121578Sume int level, op, optname; 2003121578Sume 2004180957Srwatson level = sopt->sopt_level; 2005180957Srwatson op = sopt->sopt_dir; 2006180957Srwatson optname = sopt->sopt_name; 2007180957Srwatson optlen = sopt->sopt_valsize; 2008121578Sume 2009121578Sume if (level != IPPROTO_IPV6) { 2010121578Sume return (EINVAL); 2011121578Sume } 2012121578Sume 2013121578Sume switch (optname) { 2014121578Sume case IPV6_CHECKSUM: 2015121578Sume /* 2016121578Sume * For ICMPv6 sockets, no modification allowed for checksum 2017121578Sume * offset, permit "no change" values to help existing apps. 2018121578Sume * 2019148169Sume * RFC3542 says: "An attempt to set IPV6_CHECKSUM 2020121578Sume * for an ICMPv6 socket will fail." 2021148169Sume * The current behavior does not meet RFC3542. 2022121578Sume */ 2023121578Sume switch (op) { 2024121578Sume case SOPT_SET: 2025121578Sume if (optlen != sizeof(int)) { 2026121578Sume error = EINVAL; 2027121578Sume break; 2028121578Sume } 2029121578Sume error = sooptcopyin(sopt, &optval, sizeof(optval), 2030121578Sume sizeof(optval)); 2031121578Sume if (error) 2032121578Sume break; 2033121578Sume if ((optval % 2) != 0) { 2034121578Sume /* the API assumes even offset values */ 2035121578Sume error = EINVAL; 2036121578Sume } else if (so->so_proto->pr_protocol == 2037121578Sume IPPROTO_ICMPV6) { 2038121578Sume if (optval != icmp6off) 2039121578Sume error = EINVAL; 2040121578Sume } else 2041121578Sume in6p->in6p_cksum = optval; 2042121578Sume break; 2043121578Sume 2044121578Sume case SOPT_GET: 2045121578Sume if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 2046121578Sume optval = icmp6off; 2047121578Sume else 2048121578Sume optval = in6p->in6p_cksum; 2049121578Sume 2050121578Sume error = sooptcopyout(sopt, &optval, sizeof(optval)); 2051121578Sume break; 2052121578Sume 2053121578Sume default: 2054121578Sume error = EINVAL; 2055121578Sume break; 2056121578Sume } 2057121578Sume break; 2058121578Sume 2059121578Sume default: 2060121578Sume error = ENOPROTOOPT; 2061121578Sume break; 2062121578Sume } 2063121578Sume 2064121578Sume return (error); 2065121578Sume} 2066121578Sume 206753541Sshin/* 206878064Sume * Set up IP6 options in pcb for insertion in output packets or 206978064Sume * specifying behavior of outgoing packets. 207053541Sshin */ 207153541Sshinstatic int 2072171259Sdelphijip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, 2073171259Sdelphij struct socket *so, struct sockopt *sopt) 207453541Sshin{ 207578064Sume struct ip6_pktopts *opt = *pktopt; 207653541Sshin int error = 0; 207783366Sjulian struct thread *td = sopt->sopt_td; 207853541Sshin 207953541Sshin /* turn off any old options. */ 208053541Sshin if (opt) { 208178064Sume#ifdef DIAGNOSTIC 208278064Sume if (opt->ip6po_pktinfo || opt->ip6po_nexthop || 208378064Sume opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 || 208478064Sume opt->ip6po_rhinfo.ip6po_rhi_rthdr) 208578064Sume printf("ip6_pcbopts: all specified options are cleared.\n"); 208678064Sume#endif 2087121472Sume ip6_clearpktopts(opt, -1); 208853541Sshin } else 2089111119Simp opt = malloc(sizeof(*opt), M_IP6OPT, M_WAITOK); 209078064Sume *pktopt = NULL; 209153541Sshin 209253541Sshin if (!m || m->m_len == 0) { 209353541Sshin /* 2094106259Sume * Only turning off any previous options, regardless of 2095106259Sume * whether the opt is just created or given. 209653541Sshin */ 2097106259Sume free(opt, M_IP6OPT); 2098120856Sume return (0); 209953541Sshin } 210053541Sshin 210153541Sshin /* set options specified by user. */ 2102175630Sbz if ((error = ip6_setpktopts(m, opt, NULL, (td != NULL) ? 2103175630Sbz td->td_ucred : NULL, so->so_proto->pr_protocol)) != 0) { 2104121472Sume ip6_clearpktopts(opt, -1); /* XXX: discard all options */ 2105106259Sume free(opt, M_IP6OPT); 2106120856Sume return (error); 210753541Sshin } 210853541Sshin *pktopt = opt; 2109120856Sume return (0); 211053541Sshin} 211153541Sshin 211253541Sshin/* 211378064Sume * initialize ip6_pktopts. beware that there are non-zero default values in 211478064Sume * the struct. 211578064Sume */ 211678064Sumevoid 2117171259Sdelphijip6_initpktopts(struct ip6_pktopts *opt) 211878064Sume{ 211978064Sume 212078064Sume bzero(opt, sizeof(*opt)); 212178064Sume opt->ip6po_hlim = -1; /* -1 means default hop limit */ 2122121472Sume opt->ip6po_tclass = -1; /* -1 means default traffic class */ 2123121472Sume opt->ip6po_minmtu = IP6PO_MINMTU_MCASTONLY; 2124121472Sume opt->ip6po_prefer_tempaddr = IP6PO_TEMPADDR_SYSTEM; 212578064Sume} 212678064Sume 2127121472Sumestatic int 2128171259Sdelphijip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt, 2129175630Sbz struct ucred *cred, int uproto) 2130121472Sume{ 2131121472Sume struct ip6_pktopts *opt; 2132121472Sume 2133121472Sume if (*pktopt == NULL) { 2134121472Sume *pktopt = malloc(sizeof(struct ip6_pktopts), M_IP6OPT, 2135121472Sume M_WAITOK); 2136148242Sume ip6_initpktopts(*pktopt); 2137121472Sume } 2138121472Sume opt = *pktopt; 2139121472Sume 2140175630Sbz return (ip6_setpktopt(optname, buf, len, opt, cred, 1, 0, uproto)); 2141121472Sume} 2142121472Sume 2143121472Sumestatic int 2144171259Sdelphijip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt) 2145121472Sume{ 2146121472Sume void *optdata = NULL; 2147121472Sume int optdatalen = 0; 2148121472Sume struct ip6_ext *ip6e; 2149121472Sume int error = 0; 2150121472Sume struct in6_pktinfo null_pktinfo; 2151121472Sume int deftclass = 0, on; 2152121472Sume int defminmtu = IP6PO_MINMTU_MCASTONLY; 2153121472Sume int defpreftemp = IP6PO_TEMPADDR_SYSTEM; 2154121472Sume 2155121472Sume switch (optname) { 2156121472Sume case IPV6_PKTINFO: 2157121472Sume if (pktopt && pktopt->ip6po_pktinfo) 2158121472Sume optdata = (void *)pktopt->ip6po_pktinfo; 2159121472Sume else { 2160121472Sume /* XXX: we don't have to do this every time... */ 2161121472Sume bzero(&null_pktinfo, sizeof(null_pktinfo)); 2162121472Sume optdata = (void *)&null_pktinfo; 2163121472Sume } 2164121472Sume optdatalen = sizeof(struct in6_pktinfo); 2165121472Sume break; 2166121472Sume case IPV6_TCLASS: 2167121472Sume if (pktopt && pktopt->ip6po_tclass >= 0) 2168121472Sume optdata = (void *)&pktopt->ip6po_tclass; 2169121472Sume else 2170121472Sume optdata = (void *)&deftclass; 2171121472Sume optdatalen = sizeof(int); 2172121472Sume break; 2173121472Sume case IPV6_HOPOPTS: 2174121472Sume if (pktopt && pktopt->ip6po_hbh) { 2175121472Sume optdata = (void *)pktopt->ip6po_hbh; 2176121472Sume ip6e = (struct ip6_ext *)pktopt->ip6po_hbh; 2177121472Sume optdatalen = (ip6e->ip6e_len + 1) << 3; 2178121472Sume } 2179121472Sume break; 2180121472Sume case IPV6_RTHDR: 2181121472Sume if (pktopt && pktopt->ip6po_rthdr) { 2182121472Sume optdata = (void *)pktopt->ip6po_rthdr; 2183121472Sume ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr; 2184121472Sume optdatalen = (ip6e->ip6e_len + 1) << 3; 2185121472Sume } 2186121472Sume break; 2187121472Sume case IPV6_RTHDRDSTOPTS: 2188121472Sume if (pktopt && pktopt->ip6po_dest1) { 2189121472Sume optdata = (void *)pktopt->ip6po_dest1; 2190121472Sume ip6e = (struct ip6_ext *)pktopt->ip6po_dest1; 2191121472Sume optdatalen = (ip6e->ip6e_len + 1) << 3; 2192121472Sume } 2193121472Sume break; 2194121472Sume case IPV6_DSTOPTS: 2195121472Sume if (pktopt && pktopt->ip6po_dest2) { 2196121472Sume optdata = (void *)pktopt->ip6po_dest2; 2197121472Sume ip6e = (struct ip6_ext *)pktopt->ip6po_dest2; 2198121472Sume optdatalen = (ip6e->ip6e_len + 1) << 3; 2199121472Sume } 2200121472Sume break; 2201121472Sume case IPV6_NEXTHOP: 2202121472Sume if (pktopt && pktopt->ip6po_nexthop) { 2203121472Sume optdata = (void *)pktopt->ip6po_nexthop; 2204121472Sume optdatalen = pktopt->ip6po_nexthop->sa_len; 2205121472Sume } 2206121472Sume break; 2207121472Sume case IPV6_USE_MIN_MTU: 2208121472Sume if (pktopt) 2209121472Sume optdata = (void *)&pktopt->ip6po_minmtu; 2210121472Sume else 2211121472Sume optdata = (void *)&defminmtu; 2212121472Sume optdatalen = sizeof(int); 2213121472Sume break; 2214121472Sume case IPV6_DONTFRAG: 2215121472Sume if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG)) 2216121472Sume on = 1; 2217121472Sume else 2218121472Sume on = 0; 2219121472Sume optdata = (void *)&on; 2220121472Sume optdatalen = sizeof(on); 2221121472Sume break; 2222121472Sume case IPV6_PREFER_TEMPADDR: 2223121472Sume if (pktopt) 2224121472Sume optdata = (void *)&pktopt->ip6po_prefer_tempaddr; 2225121472Sume else 2226121472Sume optdata = (void *)&defpreftemp; 2227121472Sume optdatalen = sizeof(int); 2228121472Sume break; 2229121472Sume default: /* should not happen */ 2230121472Sume#ifdef DIAGNOSTIC 2231121472Sume panic("ip6_getpcbopt: unexpected option\n"); 2232121472Sume#endif 2233121472Sume return (ENOPROTOOPT); 2234121472Sume } 2235121472Sume 2236121472Sume error = sooptcopyout(sopt, optdata, optdatalen); 2237121472Sume 2238121472Sume return (error); 2239121472Sume} 2240121472Sume 224178064Sumevoid 2242171259Sdelphijip6_clearpktopts(struct ip6_pktopts *pktopt, int optname) 224378064Sume{ 2244122970Sume if (pktopt == NULL) 2245122970Sume return; 2246122970Sume 2247121472Sume if (optname == -1 || optname == IPV6_PKTINFO) { 2248148250Sume if (pktopt->ip6po_pktinfo) 224978064Sume free(pktopt->ip6po_pktinfo, M_IP6OPT); 225078064Sume pktopt->ip6po_pktinfo = NULL; 225178064Sume } 2252121472Sume if (optname == -1 || optname == IPV6_HOPLIMIT) 225378064Sume pktopt->ip6po_hlim = -1; 2254121472Sume if (optname == -1 || optname == IPV6_TCLASS) 2255121472Sume pktopt->ip6po_tclass = -1; 2256121472Sume if (optname == -1 || optname == IPV6_NEXTHOP) { 2257121472Sume if (pktopt->ip6po_nextroute.ro_rt) { 2258121472Sume RTFREE(pktopt->ip6po_nextroute.ro_rt); 2259121472Sume pktopt->ip6po_nextroute.ro_rt = NULL; 2260121472Sume } 2261148250Sume if (pktopt->ip6po_nexthop) 226278064Sume free(pktopt->ip6po_nexthop, M_IP6OPT); 226378064Sume pktopt->ip6po_nexthop = NULL; 226478064Sume } 2265121472Sume if (optname == -1 || optname == IPV6_HOPOPTS) { 2266148250Sume if (pktopt->ip6po_hbh) 226778064Sume free(pktopt->ip6po_hbh, M_IP6OPT); 226878064Sume pktopt->ip6po_hbh = NULL; 226978064Sume } 2270121472Sume if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) { 2271148250Sume if (pktopt->ip6po_dest1) 227278064Sume free(pktopt->ip6po_dest1, M_IP6OPT); 227378064Sume pktopt->ip6po_dest1 = NULL; 227478064Sume } 2275121472Sume if (optname == -1 || optname == IPV6_RTHDR) { 2276148250Sume if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr) 227778064Sume free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT); 227878064Sume pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL; 227978064Sume if (pktopt->ip6po_route.ro_rt) { 228078064Sume RTFREE(pktopt->ip6po_route.ro_rt); 228178064Sume pktopt->ip6po_route.ro_rt = NULL; 228278064Sume } 228378064Sume } 2284121472Sume if (optname == -1 || optname == IPV6_DSTOPTS) { 2285148250Sume if (pktopt->ip6po_dest2) 228678064Sume free(pktopt->ip6po_dest2, M_IP6OPT); 228778064Sume pktopt->ip6po_dest2 = NULL; 228878064Sume } 228978064Sume} 229078064Sume 229178064Sume#define PKTOPT_EXTHDRCPY(type) \ 229278064Sumedo {\ 229378064Sume if (src->type) {\ 2294120913Sume int hlen = (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\ 229578064Sume dst->type = malloc(hlen, M_IP6OPT, canwait);\ 229678064Sume if (dst->type == NULL && canwait == M_NOWAIT)\ 229778064Sume goto bad;\ 229878064Sume bcopy(src->type, dst->type, hlen);\ 229978064Sume }\ 2300120913Sume} while (/*CONSTCOND*/ 0) 230178064Sume 2302148250Sumestatic int 2303171259Sdelphijcopypktopts(struct ip6_pktopts *dst, struct ip6_pktopts *src, int canwait) 230478064Sume{ 2305148250Sume if (dst == NULL || src == NULL) { 230678064Sume printf("ip6_clearpktopts: invalid argument\n"); 2307148250Sume return (EINVAL); 230878064Sume } 230978064Sume 231078064Sume dst->ip6po_hlim = src->ip6po_hlim; 2311121472Sume dst->ip6po_tclass = src->ip6po_tclass; 2312121472Sume dst->ip6po_flags = src->ip6po_flags; 2313225682Shrs dst->ip6po_minmtu = src->ip6po_minmtu; 2314225682Shrs dst->ip6po_prefer_tempaddr = src->ip6po_prefer_tempaddr; 231578064Sume if (src->ip6po_pktinfo) { 231678064Sume dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo), 2317120913Sume M_IP6OPT, canwait); 2318171133Sgnn if (dst->ip6po_pktinfo == NULL) 231978064Sume goto bad; 232078064Sume *dst->ip6po_pktinfo = *src->ip6po_pktinfo; 232178064Sume } 232278064Sume if (src->ip6po_nexthop) { 232378064Sume dst->ip6po_nexthop = malloc(src->ip6po_nexthop->sa_len, 2324120913Sume M_IP6OPT, canwait); 2325146228Sgnn if (dst->ip6po_nexthop == NULL) 232678064Sume goto bad; 232778064Sume bcopy(src->ip6po_nexthop, dst->ip6po_nexthop, 2328120913Sume src->ip6po_nexthop->sa_len); 232978064Sume } 233078064Sume PKTOPT_EXTHDRCPY(ip6po_hbh); 233178064Sume PKTOPT_EXTHDRCPY(ip6po_dest1); 233278064Sume PKTOPT_EXTHDRCPY(ip6po_dest2); 233378064Sume PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */ 2334148250Sume return (0); 233578064Sume 233678064Sume bad: 2337173824Smtm ip6_clearpktopts(dst, -1); 2338148250Sume return (ENOBUFS); 233978064Sume} 234078064Sume#undef PKTOPT_EXTHDRCPY 234178064Sume 2342148250Sumestruct ip6_pktopts * 2343171259Sdelphijip6_copypktopts(struct ip6_pktopts *src, int canwait) 2344148250Sume{ 2345148250Sume int error; 2346148250Sume struct ip6_pktopts *dst; 2347148250Sume 2348148250Sume dst = malloc(sizeof(*dst), M_IP6OPT, canwait); 2349171133Sgnn if (dst == NULL) 2350148250Sume return (NULL); 2351148250Sume ip6_initpktopts(dst); 2352148250Sume 2353148250Sume if ((error = copypktopts(dst, src, canwait)) != 0) { 2354148250Sume free(dst, M_IP6OPT); 2355148250Sume return (NULL); 2356148250Sume } 2357148250Sume 2358148250Sume return (dst); 2359148250Sume} 2360148250Sume 236178064Sumevoid 2362171259Sdelphijip6_freepcbopts(struct ip6_pktopts *pktopt) 236378064Sume{ 236478064Sume if (pktopt == NULL) 236578064Sume return; 236678064Sume 2367121472Sume ip6_clearpktopts(pktopt, -1); 236878064Sume 236978064Sume free(pktopt, M_IP6OPT); 237078064Sume} 237178064Sume 237278064Sume/* 237353541Sshin * Set IPv6 outgoing packet options based on advanced API. 237453541Sshin */ 237553541Sshinint 2376171259Sdelphijip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt, 2377175630Sbz struct ip6_pktopts *stickyopt, struct ucred *cred, int uproto) 237853541Sshin{ 237978064Sume struct cmsghdr *cm = 0; 238053541Sshin 2381148241Sume if (control == NULL || opt == NULL) 2382120856Sume return (EINVAL); 238353541Sshin 2384148250Sume ip6_initpktopts(opt); 2385121472Sume if (stickyopt) { 2386148250Sume int error; 2387148250Sume 2388121472Sume /* 2389121472Sume * If stickyopt is provided, make a local copy of the options 2390121472Sume * for this particular packet, then override them by ancillary 2391121472Sume * objects. 2392148250Sume * XXX: copypktopts() does not copy the cached route to a next 2393148250Sume * hop (if any). This is not very good in terms of efficiency, 2394148250Sume * but we can allow this since this option should be rarely 2395148250Sume * used. 2396121472Sume */ 2397148250Sume if ((error = copypktopts(opt, stickyopt, M_NOWAIT)) != 0) 2398148250Sume return (error); 2399148250Sume } 240053541Sshin 240153541Sshin /* 240253541Sshin * XXX: Currently, we assume all the optional information is stored 240353541Sshin * in a single mbuf. 240453541Sshin */ 240553541Sshin if (control->m_next) 2406120856Sume return (EINVAL); 240753541Sshin 2408183923Sbz for (; control->m_len > 0; control->m_data += CMSG_ALIGN(cm->cmsg_len), 2409120913Sume control->m_len -= CMSG_ALIGN(cm->cmsg_len)) { 2410121472Sume int error; 2411121472Sume 2412121472Sume if (control->m_len < CMSG_LEN(0)) 2413121472Sume return (EINVAL); 2414121472Sume 241553541Sshin cm = mtod(control, struct cmsghdr *); 241653541Sshin if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len) 2417120856Sume return (EINVAL); 241853541Sshin if (cm->cmsg_level != IPPROTO_IPV6) 241953541Sshin continue; 242053541Sshin 2421148242Sume error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm), 2422175630Sbz cm->cmsg_len - CMSG_LEN(0), opt, cred, 0, 1, uproto); 2423121472Sume if (error) 2424121472Sume return (error); 2425121472Sume } 2426121472Sume 2427121472Sume return (0); 2428121472Sume} 2429121472Sume 2430121472Sume/* 2431121472Sume * Set a particular packet option, as a sticky option or an ancillary data 2432121472Sume * item. "len" can be 0 only when it's a sticky option. 2433121472Sume * We have 4 cases of combination of "sticky" and "cmsg": 2434121472Sume * "sticky=0, cmsg=0": impossible 2435148169Sume * "sticky=0, cmsg=1": RFC2292 or RFC3542 ancillary data 2436148169Sume * "sticky=1, cmsg=0": RFC3542 socket option 2437121472Sume * "sticky=1, cmsg=1": RFC2292 socket option 2438121472Sume */ 2439121472Sumestatic int 2440171259Sdelphijip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt, 2441175630Sbz struct ucred *cred, int sticky, int cmsg, int uproto) 2442121472Sume{ 2443121472Sume int minmtupolicy, preftemp; 2444175630Sbz int error; 2445121472Sume 2446121472Sume if (!sticky && !cmsg) { 2447121472Sume#ifdef DIAGNOSTIC 2448148242Sume printf("ip6_setpktopt: impossible case\n"); 2449121472Sume#endif 2450121472Sume return (EINVAL); 2451121472Sume } 2452121472Sume 2453121472Sume /* 2454121472Sume * IPV6_2292xxx is for backward compatibility to RFC2292, and should 2455148169Sume * not be specified in the context of RFC3542. Conversely, 2456148169Sume * RFC3542 types should not be specified in the context of RFC2292. 2457121472Sume */ 2458121472Sume if (!cmsg) { 2459121472Sume switch (optname) { 2460121472Sume case IPV6_2292PKTINFO: 2461121472Sume case IPV6_2292HOPLIMIT: 2462121472Sume case IPV6_2292NEXTHOP: 2463121472Sume case IPV6_2292HOPOPTS: 2464121472Sume case IPV6_2292DSTOPTS: 2465121472Sume case IPV6_2292RTHDR: 2466121472Sume case IPV6_2292PKTOPTIONS: 2467121472Sume return (ENOPROTOOPT); 2468121472Sume } 2469121472Sume } 2470121472Sume if (sticky && cmsg) { 2471121472Sume switch (optname) { 2472121472Sume case IPV6_PKTINFO: 2473121472Sume case IPV6_HOPLIMIT: 2474121472Sume case IPV6_NEXTHOP: 2475121472Sume case IPV6_HOPOPTS: 2476121472Sume case IPV6_DSTOPTS: 2477121472Sume case IPV6_RTHDRDSTOPTS: 2478121472Sume case IPV6_RTHDR: 2479121472Sume case IPV6_USE_MIN_MTU: 2480121472Sume case IPV6_DONTFRAG: 2481121472Sume case IPV6_TCLASS: 2482148169Sume case IPV6_PREFER_TEMPADDR: /* XXX: not an RFC3542 option */ 2483121472Sume return (ENOPROTOOPT); 2484121472Sume } 2485121472Sume } 2486121472Sume 2487121472Sume switch (optname) { 2488121472Sume case IPV6_2292PKTINFO: 2489121472Sume case IPV6_PKTINFO: 2490121472Sume { 2491121472Sume struct ifnet *ifp = NULL; 2492121472Sume struct in6_pktinfo *pktinfo; 2493121472Sume 2494121472Sume if (len != sizeof(struct in6_pktinfo)) 2495121472Sume return (EINVAL); 2496121472Sume 2497121472Sume pktinfo = (struct in6_pktinfo *)buf; 2498121472Sume 249978064Sume /* 2500121472Sume * An application can clear any sticky IPV6_PKTINFO option by 2501121472Sume * doing a "regular" setsockopt with ipi6_addr being 2502121472Sume * in6addr_any and ipi6_ifindex being zero. 2503121472Sume * [RFC 3542, Section 6] 250478064Sume */ 2505121472Sume if (optname == IPV6_PKTINFO && opt->ip6po_pktinfo && 2506121472Sume pktinfo->ipi6_ifindex == 0 && 2507121472Sume IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { 2508121472Sume ip6_clearpktopts(opt, optname); 2509121472Sume break; 2510121472Sume } 251153541Sshin 2512121472Sume if (uproto == IPPROTO_TCP && optname == IPV6_PKTINFO && 2513121472Sume sticky && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { 2514121472Sume return (EINVAL); 2515121472Sume } 2516121472Sume 2517121472Sume /* validate the interface index if specified. */ 2518181803Sbz if (pktinfo->ipi6_ifindex > V_if_index || 2519121472Sume pktinfo->ipi6_ifindex < 0) { 2520121472Sume return (ENXIO); 2521121472Sume } 2522121472Sume if (pktinfo->ipi6_ifindex) { 2523121472Sume ifp = ifnet_byindex(pktinfo->ipi6_ifindex); 2524121472Sume if (ifp == NULL) 2525120856Sume return (ENXIO); 2526121472Sume } 2527121472Sume 2528121472Sume /* 2529121472Sume * We store the address anyway, and let in6_selectsrc() 2530121472Sume * validate the specified address. This is because ipi6_addr 2531121472Sume * may not have enough information about its scope zone, and 2532121472Sume * we may need additional information (such as outgoing 2533121472Sume * interface or the scope zone of a destination address) to 2534121472Sume * disambiguate the scope. 2535121472Sume * XXX: the delay of the validation may confuse the 2536121472Sume * application when it is used as a sticky option. 2537121472Sume */ 2538148250Sume if (opt->ip6po_pktinfo == NULL) { 2539148250Sume opt->ip6po_pktinfo = malloc(sizeof(*pktinfo), 2540148250Sume M_IP6OPT, M_NOWAIT); 2541148250Sume if (opt->ip6po_pktinfo == NULL) 2542148250Sume return (ENOBUFS); 2543148250Sume } 2544148250Sume bcopy(pktinfo, opt->ip6po_pktinfo, sizeof(*pktinfo)); 2545121472Sume break; 2546121472Sume } 254753541Sshin 2548121472Sume case IPV6_2292HOPLIMIT: 2549121472Sume case IPV6_HOPLIMIT: 2550121472Sume { 2551121472Sume int *hlimp; 255253541Sshin 2553121472Sume /* 2554121472Sume * RFC 3542 deprecated the usage of sticky IPV6_HOPLIMIT 2555121472Sume * to simplify the ordering among hoplimit options. 2556121472Sume */ 2557121472Sume if (optname == IPV6_HOPLIMIT && sticky) 2558121472Sume return (ENOPROTOOPT); 255953541Sshin 2560121472Sume if (len != sizeof(int)) 2561121472Sume return (EINVAL); 2562121472Sume hlimp = (int *)buf; 2563121472Sume if (*hlimp < -1 || *hlimp > 255) 2564121472Sume return (EINVAL); 256553541Sshin 2566121472Sume opt->ip6po_hlim = *hlimp; 2567121472Sume break; 2568121472Sume } 256953541Sshin 2570121472Sume case IPV6_TCLASS: 2571121472Sume { 2572121472Sume int tclass; 257378064Sume 2574121472Sume if (len != sizeof(int)) 2575121472Sume return (EINVAL); 2576121472Sume tclass = *(int *)buf; 2577121472Sume if (tclass < -1 || tclass > 255) 2578121472Sume return (EINVAL); 257953541Sshin 2580121472Sume opt->ip6po_tclass = tclass; 2581121472Sume break; 2582121472Sume } 2583121472Sume 2584121472Sume case IPV6_2292NEXTHOP: 2585121472Sume case IPV6_NEXTHOP: 2586175630Sbz if (cred != NULL) { 2587175630Sbz error = priv_check_cred(cred, 2588175630Sbz PRIV_NETINET_SETHDROPTS, 0); 2589175630Sbz if (error) 2590175630Sbz return (error); 2591175630Sbz } 2592121472Sume 2593121472Sume if (len == 0) { /* just remove the option */ 2594121472Sume ip6_clearpktopts(opt, IPV6_NEXTHOP); 259553541Sshin break; 2596121472Sume } 259753541Sshin 2598121472Sume /* check if cmsg_len is large enough for sa_len */ 2599121472Sume if (len < sizeof(struct sockaddr) || len < *buf) 2600121472Sume return (EINVAL); 2601121472Sume 2602121472Sume switch (((struct sockaddr *)buf)->sa_family) { 2603121472Sume case AF_INET6: 260478064Sume { 2605121472Sume struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)buf; 2606121472Sume int error; 260778064Sume 2608121472Sume if (sa6->sin6_len != sizeof(struct sockaddr_in6)) 2609120856Sume return (EINVAL); 2610121472Sume 2611121472Sume if (IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) || 2612121472Sume IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 2613120856Sume return (EINVAL); 2614121472Sume } 2615181803Sbz if ((error = sa6_embedscope(sa6, V_ip6_use_defzone)) 2616121472Sume != 0) { 2617121472Sume return (error); 2618121472Sume } 261953541Sshin break; 262078064Sume } 2621121472Sume case AF_LINK: /* should eventually be supported */ 2622121472Sume default: 2623121472Sume return (EAFNOSUPPORT); 2624121472Sume } 262553541Sshin 2626121472Sume /* turn off the previous option, then set the new option. */ 2627121472Sume ip6_clearpktopts(opt, IPV6_NEXTHOP); 2628151539Ssuz opt->ip6po_nexthop = malloc(*buf, M_IP6OPT, M_NOWAIT); 2629151539Ssuz if (opt->ip6po_nexthop == NULL) 2630151539Ssuz return (ENOBUFS); 2631148250Sume bcopy(buf, opt->ip6po_nexthop, *buf); 2632121472Sume break; 263378064Sume 2634121472Sume case IPV6_2292HOPOPTS: 2635121472Sume case IPV6_HOPOPTS: 2636121472Sume { 2637121472Sume struct ip6_hbh *hbh; 2638121472Sume int hbhlen; 263953541Sshin 2640121472Sume /* 2641121472Sume * XXX: We don't allow a non-privileged user to set ANY HbH 2642121472Sume * options, since per-option restriction has too much 2643121472Sume * overhead. 2644121472Sume */ 2645175630Sbz if (cred != NULL) { 2646175630Sbz error = priv_check_cred(cred, 2647175630Sbz PRIV_NETINET_SETHDROPTS, 0); 2648175630Sbz if (error) 2649175630Sbz return (error); 2650175630Sbz } 2651121472Sume 2652121472Sume if (len == 0) { 2653121472Sume ip6_clearpktopts(opt, IPV6_HOPOPTS); 2654121472Sume break; /* just remove the option */ 2655121472Sume } 2656121472Sume 2657121472Sume /* message length validation */ 2658121472Sume if (len < sizeof(struct ip6_hbh)) 2659121472Sume return (EINVAL); 2660121472Sume hbh = (struct ip6_hbh *)buf; 2661121472Sume hbhlen = (hbh->ip6h_len + 1) << 3; 2662121472Sume if (len != hbhlen) 2663121472Sume return (EINVAL); 2664121472Sume 2665121472Sume /* turn off the previous option, then set the new option. */ 2666121472Sume ip6_clearpktopts(opt, IPV6_HOPOPTS); 2667151539Ssuz opt->ip6po_hbh = malloc(hbhlen, M_IP6OPT, M_NOWAIT); 2668151539Ssuz if (opt->ip6po_hbh == NULL) 2669151539Ssuz return (ENOBUFS); 2670148250Sume bcopy(hbh, opt->ip6po_hbh, hbhlen); 2671121472Sume 2672121472Sume break; 2673121472Sume } 2674121472Sume 2675121472Sume case IPV6_2292DSTOPTS: 2676121472Sume case IPV6_DSTOPTS: 2677121472Sume case IPV6_RTHDRDSTOPTS: 2678121472Sume { 2679121472Sume struct ip6_dest *dest, **newdest = NULL; 2680121472Sume int destlen; 2681121472Sume 2682175630Sbz if (cred != NULL) { /* XXX: see the comment for IPV6_HOPOPTS */ 2683175630Sbz error = priv_check_cred(cred, 2684175630Sbz PRIV_NETINET_SETHDROPTS, 0); 2685175630Sbz if (error) 2686175630Sbz return (error); 2687175630Sbz } 2688121472Sume 2689121472Sume if (len == 0) { 2690121472Sume ip6_clearpktopts(opt, optname); 2691121472Sume break; /* just remove the option */ 2692121472Sume } 2693121472Sume 2694121472Sume /* message length validation */ 2695121472Sume if (len < sizeof(struct ip6_dest)) 2696121472Sume return (EINVAL); 2697121472Sume dest = (struct ip6_dest *)buf; 2698121472Sume destlen = (dest->ip6d_len + 1) << 3; 2699121472Sume if (len != destlen) 2700121472Sume return (EINVAL); 2701121472Sume 2702121472Sume /* 2703121472Sume * Determine the position that the destination options header 2704121472Sume * should be inserted; before or after the routing header. 2705121472Sume */ 2706121472Sume switch (optname) { 2707121472Sume case IPV6_2292DSTOPTS: 2708121472Sume /* 2709121472Sume * The old advacned API is ambiguous on this point. 2710121472Sume * Our approach is to determine the position based 2711121472Sume * according to the existence of a routing header. 2712121472Sume * Note, however, that this depends on the order of the 2713121472Sume * extension headers in the ancillary data; the 1st 2714121472Sume * part of the destination options header must appear 2715121472Sume * before the routing header in the ancillary data, 2716121472Sume * too. 2717148169Sume * RFC3542 solved the ambiguity by introducing 2718121472Sume * separate ancillary data or option types. 271953541Sshin */ 272078064Sume if (opt->ip6po_rthdr == NULL) 272178064Sume newdest = &opt->ip6po_dest1; 272278064Sume else 272378064Sume newdest = &opt->ip6po_dest2; 2724121472Sume break; 2725121472Sume case IPV6_RTHDRDSTOPTS: 2726121472Sume newdest = &opt->ip6po_dest1; 2727121472Sume break; 2728121472Sume case IPV6_DSTOPTS: 2729121472Sume newdest = &opt->ip6po_dest2; 2730121472Sume break; 2731121472Sume } 273278064Sume 2733121472Sume /* turn off the previous option, then set the new option. */ 2734121472Sume ip6_clearpktopts(opt, optname); 2735151539Ssuz *newdest = malloc(destlen, M_IP6OPT, M_NOWAIT); 2736154324Srwatson if (*newdest == NULL) 2737151539Ssuz return (ENOBUFS); 2738148250Sume bcopy(dest, *newdest, destlen); 273978064Sume 2740121472Sume break; 2741121472Sume } 2742121472Sume 2743121472Sume case IPV6_2292RTHDR: 2744121472Sume case IPV6_RTHDR: 2745121472Sume { 2746121472Sume struct ip6_rthdr *rth; 2747121472Sume int rthlen; 2748121472Sume 2749121472Sume if (len == 0) { 2750121472Sume ip6_clearpktopts(opt, IPV6_RTHDR); 2751121472Sume break; /* just remove the option */ 275278064Sume } 275353541Sshin 2754121472Sume /* message length validation */ 2755121472Sume if (len < sizeof(struct ip6_rthdr)) 2756121472Sume return (EINVAL); 2757121472Sume rth = (struct ip6_rthdr *)buf; 2758121472Sume rthlen = (rth->ip6r_len + 1) << 3; 2759121472Sume if (len != rthlen) 2760121472Sume return (EINVAL); 276178064Sume 2762121472Sume switch (rth->ip6r_type) { 2763121472Sume case IPV6_RTHDR_TYPE_0: 2764121472Sume if (rth->ip6r_len == 0) /* must contain one addr */ 2765120856Sume return (EINVAL); 2766121472Sume if (rth->ip6r_len % 2) /* length must be even */ 2767120856Sume return (EINVAL); 2768121472Sume if (rth->ip6r_len / 2 != rth->ip6r_segleft) 2769121472Sume return (EINVAL); 2770121472Sume break; 2771121472Sume default: 2772121472Sume return (EINVAL); /* not supported */ 2773121472Sume } 277478064Sume 2775121472Sume /* turn off the previous option */ 2776121472Sume ip6_clearpktopts(opt, IPV6_RTHDR); 2777151539Ssuz opt->ip6po_rthdr = malloc(rthlen, M_IP6OPT, M_NOWAIT); 2778151539Ssuz if (opt->ip6po_rthdr == NULL) 2779151539Ssuz return (ENOBUFS); 2780148250Sume bcopy(rth, opt->ip6po_rthdr, rthlen); 278178064Sume 2782121472Sume break; 2783121472Sume } 278478064Sume 2785121472Sume case IPV6_USE_MIN_MTU: 2786121472Sume if (len != sizeof(int)) 2787121472Sume return (EINVAL); 2788121472Sume minmtupolicy = *(int *)buf; 2789121472Sume if (minmtupolicy != IP6PO_MINMTU_MCASTONLY && 2790121472Sume minmtupolicy != IP6PO_MINMTU_DISABLE && 2791121472Sume minmtupolicy != IP6PO_MINMTU_ALL) { 2792121472Sume return (EINVAL); 279378064Sume } 2794121472Sume opt->ip6po_minmtu = minmtupolicy; 2795121472Sume break; 279653541Sshin 2797121472Sume case IPV6_DONTFRAG: 2798121472Sume if (len != sizeof(int)) 2799121472Sume return (EINVAL); 2800121472Sume 2801121472Sume if (uproto == IPPROTO_TCP || *(int *)buf == 0) { 2802121472Sume /* 2803121472Sume * we ignore this option for TCP sockets. 2804148169Sume * (RFC3542 leaves this case unspecified.) 2805121472Sume */ 2806121472Sume opt->ip6po_flags &= ~IP6PO_DONTFRAG; 2807121472Sume } else 2808121472Sume opt->ip6po_flags |= IP6PO_DONTFRAG; 2809121472Sume break; 2810121472Sume 2811121472Sume case IPV6_PREFER_TEMPADDR: 2812121472Sume if (len != sizeof(int)) 2813121472Sume return (EINVAL); 2814121472Sume preftemp = *(int *)buf; 2815121472Sume if (preftemp != IP6PO_TEMPADDR_SYSTEM && 2816121472Sume preftemp != IP6PO_TEMPADDR_NOTPREFER && 2817121472Sume preftemp != IP6PO_TEMPADDR_PREFER) { 2818121472Sume return (EINVAL); 281953541Sshin } 2820121472Sume opt->ip6po_prefer_tempaddr = preftemp; 2821121472Sume break; 282253541Sshin 2823121472Sume default: 2824121472Sume return (ENOPROTOOPT); 2825121472Sume } /* end of switch */ 2826121472Sume 2827120856Sume return (0); 282853541Sshin} 282953541Sshin 283053541Sshin/* 283153541Sshin * Routine called from ip6_output() to loop back a copy of an IP6 multicast 283253541Sshin * packet to the input queue of a specified interface. Note that this 283353541Sshin * calls the output routine of the loopback "driver", but with an interface 283453541Sshin * pointer that might NOT be &loif -- easier than replicating that code here. 283553541Sshin */ 283653541Sshinvoid 2837171259Sdelphijip6_mloopback(struct ifnet *ifp, struct mbuf *m, struct sockaddr_in6 *dst) 283853541Sshin{ 283962587Sitojun struct mbuf *copym; 284062587Sitojun struct ip6_hdr *ip6; 284153541Sshin 284253541Sshin copym = m_copy(m, 0, M_COPYALL); 284362587Sitojun if (copym == NULL) 284462587Sitojun return; 284562587Sitojun 284662587Sitojun /* 284762587Sitojun * Make sure to deep-copy IPv6 header portion in case the data 284862587Sitojun * is in an mbuf cluster, so that we can safely override the IPv6 284962587Sitojun * header portion later. 285062587Sitojun */ 285162587Sitojun if ((copym->m_flags & M_EXT) != 0 || 285262587Sitojun copym->m_len < sizeof(struct ip6_hdr)) { 285362587Sitojun copym = m_pullup(copym, sizeof(struct ip6_hdr)); 285462587Sitojun if (copym == NULL) 285562587Sitojun return; 285653541Sshin } 285778064Sume ip6 = mtod(copym, struct ip6_hdr *); 285878064Sume /* 285978064Sume * clear embedded scope identifiers if necessary. 286078064Sume * in6_clearscope will touch the addresses only when necessary. 286178064Sume */ 286278064Sume in6_clearscope(&ip6->ip6_src); 286378064Sume in6_clearscope(&ip6->ip6_dst); 2864282894Sae if (copym->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 2865282894Sae copym->m_pkthdr.csum_flags |= CSUM_DATA_VALID_IPV6 | 2866282894Sae CSUM_PSEUDO_HDR; 2867282894Sae copym->m_pkthdr.csum_data = 0xffff; 2868282894Sae } 2869123740Speter (void)if_simloop(ifp, copym, dst->sin6_family, 0); 287053541Sshin} 287153541Sshin 287253541Sshin/* 287353541Sshin * Chop IPv6 header off from the payload. 287453541Sshin */ 287553541Sshinstatic int 2876171259Sdelphijip6_splithdr(struct mbuf *m, struct ip6_exthdrs *exthdrs) 287753541Sshin{ 287853541Sshin struct mbuf *mh; 287953541Sshin struct ip6_hdr *ip6; 288053541Sshin 288153541Sshin ip6 = mtod(m, struct ip6_hdr *); 288253541Sshin if (m->m_len > sizeof(*ip6)) { 2883248321Sglebius mh = m_gethdr(M_NOWAIT, MT_DATA); 2884248321Sglebius if (mh == NULL) { 288553541Sshin m_freem(m); 288653541Sshin return ENOBUFS; 288753541Sshin } 2888248328Sglebius m_move_pkthdr(mh, m); 288953541Sshin MH_ALIGN(mh, sizeof(*ip6)); 289053541Sshin m->m_len -= sizeof(*ip6); 289153541Sshin m->m_data += sizeof(*ip6); 289253541Sshin mh->m_next = m; 289353541Sshin m = mh; 289453541Sshin m->m_len = sizeof(*ip6); 289553541Sshin bcopy((caddr_t)ip6, mtod(m, caddr_t), sizeof(*ip6)); 289653541Sshin } 289753541Sshin exthdrs->ip6e_ip6 = m; 289853541Sshin return 0; 289953541Sshin} 290053541Sshin 290153541Sshin/* 290253541Sshin * Compute IPv6 extension header length. 290353541Sshin */ 290453541Sshinint 2905186141Sbzip6_optlen(struct inpcb *in6p) 290653541Sshin{ 290753541Sshin int len; 290853541Sshin 290953541Sshin if (!in6p->in6p_outputopts) 291053541Sshin return 0; 291153541Sshin 291253541Sshin len = 0; 291353541Sshin#define elen(x) \ 291453541Sshin (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0) 291553541Sshin 291653541Sshin len += elen(in6p->in6p_outputopts->ip6po_hbh); 291778064Sume if (in6p->in6p_outputopts->ip6po_rthdr) 291878064Sume /* dest1 is valid with rthdr only */ 291978064Sume len += elen(in6p->in6p_outputopts->ip6po_dest1); 292053541Sshin len += elen(in6p->in6p_outputopts->ip6po_rthdr); 292153541Sshin len += elen(in6p->in6p_outputopts->ip6po_dest2); 292253541Sshin return len; 292353541Sshin#undef elen 292453541Sshin} 2925