1caf43b02SWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 482cd038dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 582cd038dSYoshinobu Inoue * All rights reserved. 682cd038dSYoshinobu Inoue * 782cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 882cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 982cd038dSYoshinobu Inoue * are met: 1082cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 1182cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1282cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1382cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1482cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1582cd038dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1682cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 1782cd038dSYoshinobu Inoue * without specific prior written permission. 1882cd038dSYoshinobu Inoue * 1982cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2082cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2182cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2282cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2382cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2482cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2582cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2682cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2782cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2882cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2982cd038dSYoshinobu Inoue * SUCH DAMAGE. 30b48287a3SDavid E. O'Brien * 31b48287a3SDavid E. O'Brien * $KAME: ip6_output.c,v 1.279 2002/01/26 06:12:30 jinmei Exp $ 3282cd038dSYoshinobu Inoue */ 3382cd038dSYoshinobu Inoue 34caf43b02SWarner Losh /*- 3582cd038dSYoshinobu Inoue * Copyright (c) 1982, 1986, 1988, 1990, 1993 3682cd038dSYoshinobu Inoue * The Regents of the University of California. All rights reserved. 3782cd038dSYoshinobu Inoue * 3882cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 3982cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 4082cd038dSYoshinobu Inoue * are met: 4182cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 4282cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 4382cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 4482cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 4582cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 46fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 4782cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 4882cd038dSYoshinobu Inoue * without specific prior written permission. 4982cd038dSYoshinobu Inoue * 5082cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5182cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5282cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5382cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5482cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5582cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5682cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5782cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5882cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5982cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6082cd038dSYoshinobu Inoue * SUCH DAMAGE. 6182cd038dSYoshinobu Inoue */ 6282cd038dSYoshinobu Inoue 63b48287a3SDavid E. O'Brien #include <sys/cdefs.h> 64686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h" 65686cdd19SJun-ichiro itojun Hagino #include "opt_inet6.h" 66686cdd19SJun-ichiro itojun Hagino #include "opt_ipsec.h" 67b2e60773SJohn Baldwin #include "opt_kern_tls.h" 6877a01441SJohn Baldwin #include "opt_ratelimit.h" 6977931dd5SKip Macy #include "opt_route.h" 70c7c0d948SAdrian Chadd #include "opt_rss.h" 7177a01441SJohn Baldwin #include "opt_sctp.h" 7282cd038dSYoshinobu Inoue 7382cd038dSYoshinobu Inoue #include <sys/param.h> 74c26fe973SBjoern A. Zeeb #include <sys/kernel.h> 75b2e60773SJohn Baldwin #include <sys/ktls.h> 7682cd038dSYoshinobu Inoue #include <sys/malloc.h> 7782cd038dSYoshinobu Inoue #include <sys/mbuf.h> 7882cd038dSYoshinobu Inoue #include <sys/errno.h> 79c2259ba4SRobert Watson #include <sys/priv.h> 80c26fe973SBjoern A. Zeeb #include <sys/proc.h> 8182cd038dSYoshinobu Inoue #include <sys/protosw.h> 8282cd038dSYoshinobu Inoue #include <sys/socket.h> 8382cd038dSYoshinobu Inoue #include <sys/socketvar.h> 841263305fSBjoern A. Zeeb #include <sys/syslog.h> 85c26fe973SBjoern A. Zeeb #include <sys/ucred.h> 8682cd038dSYoshinobu Inoue 87e7b92e27SBjoern A. Zeeb #include <machine/in_cksum.h> 88e7b92e27SBjoern A. Zeeb 8982cd038dSYoshinobu Inoue #include <net/if.h> 9076039bc8SGleb Smirnoff #include <net/if_var.h> 913d0d5b21SJustin Hibbits #include <net/if_private.h> 92868aabb4SRichard Scheffenegger #include <net/if_vlan_var.h> 930f5687f2SMike Karels #include <net/if_llatbl.h> 94868aabb4SRichard Scheffenegger #include <net/ethernet.h> 958195404bSBrooks Davis #include <net/netisr.h> 9682cd038dSYoshinobu Inoue #include <net/route.h> 97983066f0SAlexander V. Chernikov #include <net/route/nhop.h> 98c4ac87eaSDarren Reed #include <net/pfil.h> 99b2bdc62aSAdrian Chadd #include <net/rss_config.h> 1004b79449eSBjoern A. Zeeb #include <net/vnet.h> 10182cd038dSYoshinobu Inoue 10282cd038dSYoshinobu Inoue #include <netinet/in.h> 10382cd038dSYoshinobu Inoue #include <netinet/in_var.h> 1048a006adbSBjoern A. Zeeb #include <netinet/ip_var.h> 105bacf6684SAlexander V. Chernikov #include <netinet6/in6_fib.h> 10633841545SHajimu UMEMOTO #include <netinet6/in6_var.h> 107686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 108686cdd19SJun-ichiro itojun Hagino #include <netinet/icmp6.h> 10982cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 110686cdd19SJun-ichiro itojun Hagino #include <netinet/in_pcb.h> 11197d8d152SAndre Oppermann #include <netinet/tcp_var.h> 11282cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 113b2bdc62aSAdrian Chadd #include <netinet6/in6_rss.h> 11482cd038dSYoshinobu Inoue 115fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h> 11695033af9SMark Johnston #if defined(SCTP) || defined(SCTP_SUPPORT) 1179b03990aSRandall Stewart #include <netinet/sctp.h> 1189b03990aSRandall Stewart #include <netinet/sctp_crc32.h> 1199b03990aSRandall Stewart #endif 120b9234fafSSam Leffler 121a1f7e5f8SHajimu UMEMOTO #include <netinet6/scope6_var.h> 1221469c434SHajimu UMEMOTO 12333cde130SBruce M Simpson extern int in6_mcast_loop; 12482cd038dSYoshinobu Inoue 12582cd038dSYoshinobu Inoue struct ip6_exthdrs { 12682cd038dSYoshinobu Inoue struct mbuf *ip6e_ip6; 12782cd038dSYoshinobu Inoue struct mbuf *ip6e_hbh; 12882cd038dSYoshinobu Inoue struct mbuf *ip6e_dest1; 12982cd038dSYoshinobu Inoue struct mbuf *ip6e_rthdr; 13082cd038dSYoshinobu Inoue struct mbuf *ip6e_dest2; 13182cd038dSYoshinobu Inoue }; 13282cd038dSYoshinobu Inoue 1335e0a6f31SMark Johnston static MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options"); 1345e0a6f31SMark Johnston 1356f56329aSXin LI static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **, 1366f56329aSXin LI struct ucred *, int); 1376f56329aSXin LI static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *, 1386f56329aSXin LI struct socket *, struct sockopt *); 13906b479a6SSean Bruno static int ip6_getpcbopt(struct inpcb *, int, struct sockopt *); 1406f56329aSXin LI static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, 1416f56329aSXin LI struct ucred *, int, int, int); 142f95d4633SHajimu UMEMOTO 1439233d8f3SDavid E. O'Brien static int ip6_copyexthdr(struct mbuf **, caddr_t, int); 1446f56329aSXin LI static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int, 1456f56329aSXin LI struct ip6_frag **); 1469233d8f3SDavid E. O'Brien static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t); 1479233d8f3SDavid E. O'Brien static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *); 1480d4df029SAlexander V. Chernikov static int ip6_getpmtu(struct route_in6 *, int, 149d4c22202SAndrew Gallatin struct ifnet *, const struct in6_addr *, u_long *, int *, u_int, 150d4c22202SAndrew Gallatin u_int); 1510d4df029SAlexander V. Chernikov static int ip6_calcmtu(struct ifnet *, const struct in6_addr *, u_long, 152d4c22202SAndrew Gallatin u_long *, int *, u_int); 153f0937b2cSAndrey V. Elsukov static int ip6_getpmtu_ctl(u_int, const struct in6_addr *, u_long *); 1549233d8f3SDavid E. O'Brien static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int); 15582cd038dSYoshinobu Inoue 15682cd038dSYoshinobu Inoue /* 157a1a6c01eSBjoern A. Zeeb * Make an extension header from option data. hp is the source, 158a1a6c01eSBjoern A. Zeeb * mp is the destination, and _ol is the optlen. 1592cb64cb2SGeorge V. Neville-Neil */ 160a1a6c01eSBjoern A. Zeeb #define MAKE_EXTHDR(hp, mp, _ol) \ 1612cb64cb2SGeorge V. Neville-Neil do { \ 1622cb64cb2SGeorge V. Neville-Neil struct ip6_ext *eh = (struct ip6_ext *)(hp); \ 1632cb64cb2SGeorge V. Neville-Neil error = ip6_copyexthdr((mp), (caddr_t)(hp), \ 1642cb64cb2SGeorge V. Neville-Neil ((eh)->ip6e_len + 1) << 3); \ 1652cb64cb2SGeorge V. Neville-Neil if (error) \ 1662cb64cb2SGeorge V. Neville-Neil goto freehdrs; \ 167a1a6c01eSBjoern A. Zeeb (_ol) += (*(mp))->m_len; \ 1682cb64cb2SGeorge V. Neville-Neil } while (/*CONSTCOND*/ 0) 1692cb64cb2SGeorge V. Neville-Neil 1702cb64cb2SGeorge V. Neville-Neil /* 1712cb64cb2SGeorge V. Neville-Neil * Form a chain of extension headers. 1722cb64cb2SGeorge V. Neville-Neil * m is the extension header mbuf 1732cb64cb2SGeorge V. Neville-Neil * mp is the previous mbuf in the chain 1742cb64cb2SGeorge V. Neville-Neil * p is the next header 1752cb64cb2SGeorge V. Neville-Neil * i is the type of option. 1762cb64cb2SGeorge V. Neville-Neil */ 1772cb64cb2SGeorge V. Neville-Neil #define MAKE_CHAIN(m, mp, p, i)\ 1782cb64cb2SGeorge V. Neville-Neil do {\ 1792cb64cb2SGeorge V. Neville-Neil if (m) {\ 1802cb64cb2SGeorge V. Neville-Neil if (!hdrsplit) \ 1817c1daefeSBjoern A. Zeeb panic("%s:%d: assumption failed: "\ 1827c1daefeSBjoern A. Zeeb "hdr not split: hdrsplit %d exthdrs %p",\ 1837c1daefeSBjoern A. Zeeb __func__, __LINE__, hdrsplit, &exthdrs);\ 1842cb64cb2SGeorge V. Neville-Neil *mtod((m), u_char *) = *(p);\ 1852cb64cb2SGeorge V. Neville-Neil *(p) = (i);\ 1862cb64cb2SGeorge V. Neville-Neil p = mtod((m), u_char *);\ 1872cb64cb2SGeorge V. Neville-Neil (m)->m_next = (mp)->m_next;\ 1882cb64cb2SGeorge V. Neville-Neil (mp)->m_next = (m);\ 1892cb64cb2SGeorge V. Neville-Neil (mp) = (m);\ 1902cb64cb2SGeorge V. Neville-Neil }\ 1912cb64cb2SGeorge V. Neville-Neil } while (/*CONSTCOND*/ 0) 1922cb64cb2SGeorge V. Neville-Neil 193aaf2cfc0SVANHULLEBUS Yvan void 194e7b92e27SBjoern A. Zeeb in6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset) 195e7b92e27SBjoern A. Zeeb { 196e7b92e27SBjoern A. Zeeb u_short csum; 197e7b92e27SBjoern A. Zeeb 198c69baa7eSBjoern A. Zeeb csum = in_cksum_skip(m, offset + plen, offset); 199356ab07eSBjoern A. Zeeb if (m->m_pkthdr.csum_flags & CSUM_UDP_IPV6 && csum == 0) 200e7b92e27SBjoern A. Zeeb csum = 0xffff; 201e7b92e27SBjoern A. Zeeb offset += m->m_pkthdr.csum_data; /* checksum offset */ 202e7b92e27SBjoern A. Zeeb 2034a089e6bSAndrey V. Elsukov if (offset + sizeof(csum) > m->m_len) 2044a089e6bSAndrey V. Elsukov m_copyback(m, offset, sizeof(csum), (caddr_t)&csum); 2054a089e6bSAndrey V. Elsukov else 2064a089e6bSAndrey V. Elsukov *(u_short *)mtodo(m, offset) = csum; 207e7b92e27SBjoern A. Zeeb } 208e7b92e27SBjoern A. Zeeb 20944775b16SMark Johnston static void 2103459050cSBjoern A. Zeeb ip6_output_delayed_csum(struct mbuf *m, struct ifnet *ifp, int csum_flags, 21144775b16SMark Johnston int plen, int optlen) 2123459050cSBjoern A. Zeeb { 2133459050cSBjoern A. Zeeb 2143459050cSBjoern A. Zeeb KASSERT((plen >= optlen), ("%s:%d: plen %d < optlen %d, m %p, ifp %p " 21544775b16SMark Johnston "csum_flags %#x", 21644775b16SMark Johnston __func__, __LINE__, plen, optlen, m, ifp, csum_flags)); 2173459050cSBjoern A. Zeeb 2183459050cSBjoern A. Zeeb if (csum_flags & CSUM_DELAY_DATA_IPV6) { 2193459050cSBjoern A. Zeeb in6_delayed_cksum(m, plen - optlen, 2203459050cSBjoern A. Zeeb sizeof(struct ip6_hdr) + optlen); 2213459050cSBjoern A. Zeeb m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; 2223459050cSBjoern A. Zeeb } 22395033af9SMark Johnston #if defined(SCTP) || defined(SCTP_SUPPORT) 2243459050cSBjoern A. Zeeb if (csum_flags & CSUM_SCTP_IPV6) { 2253459050cSBjoern A. Zeeb sctp_delayed_cksum(m, sizeof(struct ip6_hdr) + optlen); 2263459050cSBjoern A. Zeeb m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; 2273459050cSBjoern A. Zeeb } 2283459050cSBjoern A. Zeeb #endif 2293459050cSBjoern A. Zeeb } 2303459050cSBjoern A. Zeeb 2316c269f69SGleb Smirnoff int 2326c269f69SGleb Smirnoff ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto, 233d78c0804SKristof Provost int fraglen , uint32_t id) 2346c269f69SGleb Smirnoff { 2356c269f69SGleb Smirnoff struct mbuf *m, **mnext, *m_frgpart; 2366c269f69SGleb Smirnoff struct ip6_hdr *ip6, *mhip6; 2376c269f69SGleb Smirnoff struct ip6_frag *ip6f; 2386c269f69SGleb Smirnoff int off; 2396c269f69SGleb Smirnoff int error; 2406c269f69SGleb Smirnoff int tlen = m0->m_pkthdr.len; 2416c269f69SGleb Smirnoff 242d78c0804SKristof Provost KASSERT((fraglen % 8 == 0), ("Fragment length must be a multiple of 8")); 24300eab743SKristof Provost 2446c269f69SGleb Smirnoff m = m0; 2456c269f69SGleb Smirnoff ip6 = mtod(m, struct ip6_hdr *); 2466c269f69SGleb Smirnoff mnext = &m->m_nextpkt; 2476c269f69SGleb Smirnoff 248d78c0804SKristof Provost for (off = hlen; off < tlen; off += fraglen) { 2496c269f69SGleb Smirnoff m = m_gethdr(M_NOWAIT, MT_DATA); 2506c269f69SGleb Smirnoff if (!m) { 2516c269f69SGleb Smirnoff IP6STAT_INC(ip6s_odropped); 2526c269f69SGleb Smirnoff return (ENOBUFS); 2536c269f69SGleb Smirnoff } 254c9d33708SJohn Baldwin 255c9d33708SJohn Baldwin /* 256c9d33708SJohn Baldwin * Make sure the complete packet header gets copied 257c9d33708SJohn Baldwin * from the originating mbuf to the newly created 258c9d33708SJohn Baldwin * mbuf. This also ensures that existing firewall 259c9d33708SJohn Baldwin * classification(s), VLAN tags and so on get copied 260c9d33708SJohn Baldwin * to the resulting fragmented packet(s): 261c9d33708SJohn Baldwin */ 262c9d33708SJohn Baldwin if (m_dup_pkthdr(m, m0, M_NOWAIT) == 0) { 263c9d33708SJohn Baldwin m_free(m); 264c9d33708SJohn Baldwin IP6STAT_INC(ip6s_odropped); 265c9d33708SJohn Baldwin return (ENOBUFS); 266c9d33708SJohn Baldwin } 267c9d33708SJohn Baldwin 2686c269f69SGleb Smirnoff *mnext = m; 2696c269f69SGleb Smirnoff mnext = &m->m_nextpkt; 2706c269f69SGleb Smirnoff m->m_data += max_linkhdr; 2716c269f69SGleb Smirnoff mhip6 = mtod(m, struct ip6_hdr *); 2726c269f69SGleb Smirnoff *mhip6 = *ip6; 2736c269f69SGleb Smirnoff m->m_len = sizeof(*mhip6); 2746c269f69SGleb Smirnoff error = ip6_insertfraghdr(m0, m, hlen, &ip6f); 2756c269f69SGleb Smirnoff if (error) { 2766c269f69SGleb Smirnoff IP6STAT_INC(ip6s_odropped); 2776c269f69SGleb Smirnoff return (error); 2786c269f69SGleb Smirnoff } 2796c269f69SGleb Smirnoff ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7)); 280d78c0804SKristof Provost if (off + fraglen >= tlen) 281d78c0804SKristof Provost fraglen = tlen - off; 2826c269f69SGleb Smirnoff else 2836c269f69SGleb Smirnoff ip6f->ip6f_offlg |= IP6F_MORE_FRAG; 284d78c0804SKristof Provost mhip6->ip6_plen = htons((u_short)(fraglen + hlen + 2856c269f69SGleb Smirnoff sizeof(*ip6f) - sizeof(struct ip6_hdr))); 286d78c0804SKristof Provost if ((m_frgpart = m_copym(m0, off, fraglen, M_NOWAIT)) == NULL) { 2876c269f69SGleb Smirnoff IP6STAT_INC(ip6s_odropped); 2886c269f69SGleb Smirnoff return (ENOBUFS); 2896c269f69SGleb Smirnoff } 2906c269f69SGleb Smirnoff m_cat(m, m_frgpart); 291d78c0804SKristof Provost m->m_pkthdr.len = fraglen + hlen + sizeof(*ip6f); 2926c269f69SGleb Smirnoff ip6f->ip6f_reserved = 0; 2936c269f69SGleb Smirnoff ip6f->ip6f_ident = id; 2946c269f69SGleb Smirnoff ip6f->ip6f_nxt = nextproto; 2956c269f69SGleb Smirnoff IP6STAT_INC(ip6s_ofragments); 2966c269f69SGleb Smirnoff in6_ifstat_inc(ifp, ifs6_out_fragcreat); 2976c269f69SGleb Smirnoff } 2986c269f69SGleb Smirnoff 2996c269f69SGleb Smirnoff return (0); 3006c269f69SGleb Smirnoff } 3016c269f69SGleb Smirnoff 302fb3bc596SJohn Baldwin static int 303fb3bc596SJohn Baldwin ip6_output_send(struct inpcb *inp, struct ifnet *ifp, struct ifnet *origifp, 304d7452d89SAndrew Gallatin struct mbuf *m, struct sockaddr_in6 *dst, struct route_in6 *ro, 305d7452d89SAndrew Gallatin bool stamp_tag) 306fb3bc596SJohn Baldwin { 307b2e60773SJohn Baldwin #ifdef KERN_TLS 308b2e60773SJohn Baldwin struct ktls_session *tls = NULL; 309b2e60773SJohn Baldwin #endif 310fb3bc596SJohn Baldwin struct m_snd_tag *mst; 311fb3bc596SJohn Baldwin int error; 312fb3bc596SJohn Baldwin 313fb3bc596SJohn Baldwin MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0); 314fb3bc596SJohn Baldwin mst = NULL; 315fb3bc596SJohn Baldwin 316b2e60773SJohn Baldwin #ifdef KERN_TLS 317b2e60773SJohn Baldwin /* 318b2e60773SJohn Baldwin * If this is an unencrypted TLS record, save a reference to 319b2e60773SJohn Baldwin * the record. This local reference is used to call 320b2e60773SJohn Baldwin * ktls_output_eagain after the mbuf has been freed (thus 321b2e60773SJohn Baldwin * dropping the mbuf's reference) in if_output. 322b2e60773SJohn Baldwin */ 323b2e60773SJohn Baldwin if (m->m_next != NULL && mbuf_has_tls_session(m->m_next)) { 3247b6c99d0SGleb Smirnoff tls = ktls_hold(m->m_next->m_epg_tls); 325b2e60773SJohn Baldwin mst = tls->snd_tag; 326b2e60773SJohn Baldwin 327b2e60773SJohn Baldwin /* 328b2e60773SJohn Baldwin * If a TLS session doesn't have a valid tag, it must 329b2e60773SJohn Baldwin * have had an earlier ifp mismatch, so drop this 330b2e60773SJohn Baldwin * packet. 331b2e60773SJohn Baldwin */ 332b2e60773SJohn Baldwin if (mst == NULL) { 3339ba11796SAndrew Gallatin m_freem(m); 334b2e60773SJohn Baldwin error = EAGAIN; 335b2e60773SJohn Baldwin goto done; 336b2e60773SJohn Baldwin } 337d7452d89SAndrew Gallatin /* 338d7452d89SAndrew Gallatin * Always stamp tags that include NIC ktls. 339d7452d89SAndrew Gallatin */ 340d7452d89SAndrew Gallatin stamp_tag = true; 341b2e60773SJohn Baldwin } 342b2e60773SJohn Baldwin #endif 343fb3bc596SJohn Baldwin #ifdef RATELIMIT 344b2e60773SJohn Baldwin if (inp != NULL && mst == NULL) { 345fb3bc596SJohn Baldwin if ((inp->inp_flags2 & INP_RATE_LIMIT_CHANGED) != 0 || 346fb3bc596SJohn Baldwin (inp->inp_snd_tag != NULL && 347fb3bc596SJohn Baldwin inp->inp_snd_tag->ifp != ifp)) 348fb3bc596SJohn Baldwin in_pcboutput_txrtlmt(inp, ifp, m); 349fb3bc596SJohn Baldwin 350fb3bc596SJohn Baldwin if (inp->inp_snd_tag != NULL) 351fb3bc596SJohn Baldwin mst = inp->inp_snd_tag; 352fb3bc596SJohn Baldwin } 353fb3bc596SJohn Baldwin #endif 354d7452d89SAndrew Gallatin if (stamp_tag && mst != NULL) { 355fb3bc596SJohn Baldwin KASSERT(m->m_pkthdr.rcvif == NULL, 356fb3bc596SJohn Baldwin ("trying to add a send tag to a forwarded packet")); 357fb3bc596SJohn Baldwin if (mst->ifp != ifp) { 3589ba11796SAndrew Gallatin m_freem(m); 359fb3bc596SJohn Baldwin error = EAGAIN; 360fb3bc596SJohn Baldwin goto done; 361fb3bc596SJohn Baldwin } 362fb3bc596SJohn Baldwin 363fb3bc596SJohn Baldwin /* stamp send tag on mbuf */ 364fb3bc596SJohn Baldwin m->m_pkthdr.snd_tag = m_snd_tag_ref(mst); 365fb3bc596SJohn Baldwin m->m_pkthdr.csum_flags |= CSUM_SND_TAG; 366fb3bc596SJohn Baldwin } 367fb3bc596SJohn Baldwin 368fb3bc596SJohn Baldwin error = nd6_output_ifp(ifp, origifp, m, dst, (struct route *)ro); 369fb3bc596SJohn Baldwin 370fb3bc596SJohn Baldwin done: 371fb3bc596SJohn Baldwin /* Check for route change invalidating send tags. */ 372b2e60773SJohn Baldwin #ifdef KERN_TLS 373b2e60773SJohn Baldwin if (tls != NULL) { 374b2e60773SJohn Baldwin if (error == EAGAIN) 375b2e60773SJohn Baldwin error = ktls_output_eagain(inp, tls); 376b2e60773SJohn Baldwin ktls_free(tls); 377b2e60773SJohn Baldwin } 378b2e60773SJohn Baldwin #endif 379fb3bc596SJohn Baldwin #ifdef RATELIMIT 380fb3bc596SJohn Baldwin if (error == EAGAIN) 381fb3bc596SJohn Baldwin in_pcboutput_eagain(inp); 382fb3bc596SJohn Baldwin #endif 383fb3bc596SJohn Baldwin return (error); 384fb3bc596SJohn Baldwin } 385fb3bc596SJohn Baldwin 3862cb64cb2SGeorge V. Neville-Neil /* 3877c1daefeSBjoern A. Zeeb * IP6 output. 3887c1daefeSBjoern A. Zeeb * The packet in mbuf chain m contains a skeletal IP6 header (with pri, len, 3897c1daefeSBjoern A. Zeeb * nxt, hlim, src, dst). 39082cd038dSYoshinobu Inoue * This function may modify ver and hlim only. 39182cd038dSYoshinobu Inoue * The mbuf chain containing the packet will be freed. 39282cd038dSYoshinobu Inoue * The mbuf opt, if present, will not be freed. 393983066f0SAlexander V. Chernikov * If route_in6 ro is present and has ro_nh initialized, route lookup would be 394983066f0SAlexander V. Chernikov * skipped and ro->ro_nh would be used. If ro is present but ro->ro_nh is NULL, 395983066f0SAlexander V. Chernikov * then result of route lookup is stored in ro->ro_nh. 39633841545SHajimu UMEMOTO * 3977c1daefeSBjoern A. Zeeb * Type of "mtu": rt_mtu is u_long, ifnet.ifr_mtu is int, and nd_ifinfo.linkmtu 3987c1daefeSBjoern A. Zeeb * is uint32_t. So we use u_long to hold largest one, which is rt_mtu. 3991272577eSXin LI * 4001272577eSXin LI * ifpp - XXX: just for statistics 40182cd038dSYoshinobu Inoue */ 40282cd038dSYoshinobu Inoue int 4031272577eSXin LI ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, 4041272577eSXin LI struct route_in6 *ro, int flags, struct ip6_moptions *im6o, 4051272577eSXin LI struct ifnet **ifpp, struct inpcb *inp) 40682cd038dSYoshinobu Inoue { 4076c269f69SGleb Smirnoff struct ip6_hdr *ip6; 408686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp, *origifp; 40982cd038dSYoshinobu Inoue struct mbuf *m = m0; 410a1a6c01eSBjoern A. Zeeb struct mbuf *mprev; 411000c42faSBjoern A. Zeeb struct route_in6 *ro_pmtu; 412983066f0SAlexander V. Chernikov struct nhop_object *nh; 413000c42faSBjoern A. Zeeb struct sockaddr_in6 *dst, sin6, src_sa, dst_sa; 4148195404bSBrooks Davis struct in6_addr odst; 415a1a6c01eSBjoern A. Zeeb u_char *nexthdrp; 416000c42faSBjoern A. Zeeb int tlen, len; 41782cd038dSYoshinobu Inoue int error = 0; 418868aabb4SRichard Scheffenegger int vlan_pcp = -1; 4195da9f8faSJosef Karthauser struct in6_ifaddr *ia = NULL; 42082cd038dSYoshinobu Inoue u_long mtu; 421f95d4633SHajimu UMEMOTO int alwaysfrag, dontfrag; 422a1a6c01eSBjoern A. Zeeb u_int32_t optlen, plen = 0, unfragpartlen; 42382cd038dSYoshinobu Inoue struct ip6_exthdrs exthdrs; 424f0937b2cSAndrey V. Elsukov struct in6_addr src0, dst0; 425a1f7e5f8SHajimu UMEMOTO u_int32_t zone; 426a1a6c01eSBjoern A. Zeeb bool hdrsplit; 427e7b92e27SBjoern A. Zeeb int sw_csum, tso; 4289c57a5b6SHiroki Sato int needfiblookup; 4299c57a5b6SHiroki Sato uint32_t fibnum; 430f8fe3dc9SAndrey V. Elsukov struct m_tag *fwd_tag = NULL; 43179831849SKristof Provost uint32_t id; 432530c2c30SAndrew Gallatin uint32_t optvalid; 433b9234fafSSam Leffler 434b9555453SGleb Smirnoff NET_EPOCH_ASSERT(); 4351e4f4e56SGleb Smirnoff 436b174de32SAdrian Chadd if (inp != NULL) { 437ce9ac139SNavdeep Parhar INP_LOCK_ASSERT(inp); 43881d5d46bSBjoern A. Zeeb M_SETFIB(m, inp->inp_inc.inc_fibnum); 439c2529042SHans Petter Selasky if ((flags & IP_NODEFAULTFLOWID) == 0) { 4407c1daefeSBjoern A. Zeeb /* Unconditionally set flowid. */ 441b174de32SAdrian Chadd m->m_pkthdr.flowid = inp->inp_flowid; 442c2529042SHans Petter Selasky M_HASHTYPE_SET(m, inp->inp_flowtype); 443b174de32SAdrian Chadd } 444868aabb4SRichard Scheffenegger if ((inp->inp_flags2 & INP_2PCP_SET) != 0) 445868aabb4SRichard Scheffenegger vlan_pcp = (inp->inp_flags2 & INP_2PCP_MASK) >> 446868aabb4SRichard Scheffenegger INP_2PCP_SHIFT; 44750575ce1SAndrew Gallatin #ifdef NUMA 44850575ce1SAndrew Gallatin m->m_pkthdr.numa_domain = inp->inp_numa_domain; 44950575ce1SAndrew Gallatin #endif 450b174de32SAdrian Chadd } 45181d5d46bSBjoern A. Zeeb 452a1a6c01eSBjoern A. Zeeb /* Source address validation. */ 453a1a6c01eSBjoern A. Zeeb ip6 = mtod(m, struct ip6_hdr *); 454a1a6c01eSBjoern A. Zeeb if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && 455a1a6c01eSBjoern A. Zeeb (flags & IPV6_UNSPECSRC) == 0) { 456a1a6c01eSBjoern A. Zeeb error = EOPNOTSUPP; 457a1a6c01eSBjoern A. Zeeb IP6STAT_INC(ip6s_badscope); 458a1a6c01eSBjoern A. Zeeb goto bad; 459a1a6c01eSBjoern A. Zeeb } 460a1a6c01eSBjoern A. Zeeb if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) { 461a1a6c01eSBjoern A. Zeeb error = EOPNOTSUPP; 462a1a6c01eSBjoern A. Zeeb IP6STAT_INC(ip6s_badscope); 463a1a6c01eSBjoern A. Zeeb goto bad; 464a1a6c01eSBjoern A. Zeeb } 465a1a6c01eSBjoern A. Zeeb 466a1a6c01eSBjoern A. Zeeb /* 467a1a6c01eSBjoern A. Zeeb * If we are given packet options to add extension headers prepare them. 468a1a6c01eSBjoern A. Zeeb * Calculate the total length of the extension header chain. 469a1a6c01eSBjoern A. Zeeb * Keep the length of the unfragmentable part for fragmentation. 470a1a6c01eSBjoern A. Zeeb */ 47182cd038dSYoshinobu Inoue bzero(&exthdrs, sizeof(exthdrs)); 472530c2c30SAndrew Gallatin optlen = optvalid = 0; 4733db60531SBjoern A. Zeeb unfragpartlen = sizeof(struct ip6_hdr); 47482cd038dSYoshinobu Inoue if (opt) { 475530c2c30SAndrew Gallatin optvalid = opt->ip6po_valid; 476530c2c30SAndrew Gallatin 4777c1daefeSBjoern A. Zeeb /* Hop-by-Hop options header. */ 478530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_HBH) != 0) 479a1a6c01eSBjoern A. Zeeb MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh, optlen); 480a1a6c01eSBjoern A. Zeeb 4817c1daefeSBjoern A. Zeeb /* Destination options header (1st part). */ 482530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_RHINFO) != 0) { 483a1a6c01eSBjoern A. Zeeb #ifndef RTHDR_SUPPORT_IMPLEMENTED 484a1a6c01eSBjoern A. Zeeb /* 485a1a6c01eSBjoern A. Zeeb * If there is a routing header, discard the packet 486a1a6c01eSBjoern A. Zeeb * right away here. RH0/1 are obsolete and we do not 487a1a6c01eSBjoern A. Zeeb * currently support RH2/3/4. 488a1a6c01eSBjoern A. Zeeb * People trying to use RH253/254 may want to disable 489a1a6c01eSBjoern A. Zeeb * this check. 490a1a6c01eSBjoern A. Zeeb * The moment we do support any routing header (again) 491a1a6c01eSBjoern A. Zeeb * this block should check the routing type more 492a1a6c01eSBjoern A. Zeeb * selectively. 493a1a6c01eSBjoern A. Zeeb */ 494a1a6c01eSBjoern A. Zeeb error = EINVAL; 495a1a6c01eSBjoern A. Zeeb goto bad; 496a1a6c01eSBjoern A. Zeeb #endif 497a1a6c01eSBjoern A. Zeeb 49829bc2c48SHajimu UMEMOTO /* 4997c1daefeSBjoern A. Zeeb * Destination options header (1st part). 5002cb64cb2SGeorge V. Neville-Neil * This only makes sense with a routing header. 50129bc2c48SHajimu UMEMOTO * See Section 9.2 of RFC 3542. 50229bc2c48SHajimu UMEMOTO * Disabling this part just for MIP6 convenience is 50329bc2c48SHajimu UMEMOTO * a bad idea. We need to think carefully about a 50429bc2c48SHajimu UMEMOTO * way to make the advanced API coexist with MIP6 50529bc2c48SHajimu UMEMOTO * options, which might automatically be inserted in 50629bc2c48SHajimu UMEMOTO * the kernel. 50729bc2c48SHajimu UMEMOTO */ 508530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_DEST1) != 0) 509a1a6c01eSBjoern A. Zeeb MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1, 510a1a6c01eSBjoern A. Zeeb optlen); 51129bc2c48SHajimu UMEMOTO } 5127c1daefeSBjoern A. Zeeb /* Routing header. */ 513530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_RHINFO) != 0) 514a1a6c01eSBjoern A. Zeeb MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr, optlen); 51582cd038dSYoshinobu Inoue 5163db60531SBjoern A. Zeeb unfragpartlen += optlen; 5172cb64cb2SGeorge V. Neville-Neil 518a1a6c01eSBjoern A. Zeeb /* 519a1a6c01eSBjoern A. Zeeb * NOTE: we don't add AH/ESP length here (done in 520a1a6c01eSBjoern A. Zeeb * ip6_ipsec_output()). 521a1a6c01eSBjoern A. Zeeb */ 522a1a6c01eSBjoern A. Zeeb 523a1a6c01eSBjoern A. Zeeb /* Destination options header (2nd part). */ 524530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_DEST2) != 0) 525a1a6c01eSBjoern A. Zeeb MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2, optlen); 526a1a6c01eSBjoern A. Zeeb } 52782cd038dSYoshinobu Inoue 52882cd038dSYoshinobu Inoue /* 529aaf2cfc0SVANHULLEBUS Yvan * If there is at least one extension header, 53082cd038dSYoshinobu Inoue * separate IP6 header from the payload. 53182cd038dSYoshinobu Inoue */ 532a1a6c01eSBjoern A. Zeeb hdrsplit = false; 533a1a6c01eSBjoern A. Zeeb if (optlen) { 53482cd038dSYoshinobu Inoue if ((error = ip6_splithdr(m, &exthdrs)) != 0) { 53582cd038dSYoshinobu Inoue m = NULL; 53682cd038dSYoshinobu Inoue goto freehdrs; 53782cd038dSYoshinobu Inoue } 53882cd038dSYoshinobu Inoue m = exthdrs.ip6e_ip6; 53982cd038dSYoshinobu Inoue ip6 = mtod(m, struct ip6_hdr *); 540a1a6c01eSBjoern A. Zeeb hdrsplit = true; 541a1a6c01eSBjoern A. Zeeb } 54282cd038dSYoshinobu Inoue 5437c1daefeSBjoern A. Zeeb /* Adjust mbuf packet header length. */ 54482cd038dSYoshinobu Inoue m->m_pkthdr.len += optlen; 54582cd038dSYoshinobu Inoue plen = m->m_pkthdr.len - sizeof(*ip6); 54682cd038dSYoshinobu Inoue 54782cd038dSYoshinobu Inoue /* If this is a jumbo payload, insert a jumbo payload option. */ 54882cd038dSYoshinobu Inoue if (plen > IPV6_MAXPACKET) { 54982cd038dSYoshinobu Inoue if (!hdrsplit) { 55082cd038dSYoshinobu Inoue if ((error = ip6_splithdr(m, &exthdrs)) != 0) { 55182cd038dSYoshinobu Inoue m = NULL; 55282cd038dSYoshinobu Inoue goto freehdrs; 55382cd038dSYoshinobu Inoue } 55482cd038dSYoshinobu Inoue m = exthdrs.ip6e_ip6; 55582cd038dSYoshinobu Inoue ip6 = mtod(m, struct ip6_hdr *); 556a1a6c01eSBjoern A. Zeeb hdrsplit = true; 557a1a6c01eSBjoern A. Zeeb } 55882cd038dSYoshinobu Inoue if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0) 55982cd038dSYoshinobu Inoue goto freehdrs; 56082cd038dSYoshinobu Inoue ip6->ip6_plen = 0; 56182cd038dSYoshinobu Inoue } else 56282cd038dSYoshinobu Inoue ip6->ip6_plen = htons(plen); 563a1a6c01eSBjoern A. Zeeb nexthdrp = &ip6->ip6_nxt; 56482cd038dSYoshinobu Inoue 565a1a6c01eSBjoern A. Zeeb if (optlen) { 56682cd038dSYoshinobu Inoue /* 56782cd038dSYoshinobu Inoue * Concatenate headers and fill in next header fields. 56882cd038dSYoshinobu Inoue * Here we have, on "m" 56982cd038dSYoshinobu Inoue * IPv6 payload 5707c1daefeSBjoern A. Zeeb * and we insert headers accordingly. 5717c1daefeSBjoern A. Zeeb * Finally, we should be getting: 5727c1daefeSBjoern A. Zeeb * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]. 57382cd038dSYoshinobu Inoue * 5747c1daefeSBjoern A. Zeeb * During the header composing process "m" points to IPv6 5757c1daefeSBjoern A. Zeeb * header. "mprev" points to an extension header prior to esp. 57682cd038dSYoshinobu Inoue */ 5772cb64cb2SGeorge V. Neville-Neil mprev = m; 57882cd038dSYoshinobu Inoue 57982cd038dSYoshinobu Inoue /* 5807c1daefeSBjoern A. Zeeb * We treat dest2 specially. This makes IPsec processing 5817c1daefeSBjoern A. Zeeb * much easier. The goal here is to make mprev point the 58288ff5695SSUZUKI Shinsuke * mbuf prior to dest2. 58382cd038dSYoshinobu Inoue * 5847c1daefeSBjoern A. Zeeb * Result: IPv6 dest2 payload. 58582cd038dSYoshinobu Inoue * m and mprev will point to IPv6 header. 58682cd038dSYoshinobu Inoue */ 58782cd038dSYoshinobu Inoue if (exthdrs.ip6e_dest2) { 58882cd038dSYoshinobu Inoue if (!hdrsplit) 5897c1daefeSBjoern A. Zeeb panic("%s:%d: assumption failed: " 5907c1daefeSBjoern A. Zeeb "hdr not split: hdrsplit %d exthdrs %p", 5917c1daefeSBjoern A. Zeeb __func__, __LINE__, hdrsplit, &exthdrs); 59282cd038dSYoshinobu Inoue exthdrs.ip6e_dest2->m_next = m->m_next; 59382cd038dSYoshinobu Inoue m->m_next = exthdrs.ip6e_dest2; 59482cd038dSYoshinobu Inoue *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt; 59582cd038dSYoshinobu Inoue ip6->ip6_nxt = IPPROTO_DSTOPTS; 59682cd038dSYoshinobu Inoue } 59782cd038dSYoshinobu Inoue 59882cd038dSYoshinobu Inoue /* 5997c1daefeSBjoern A. Zeeb * Result: IPv6 hbh dest1 rthdr dest2 payload. 60082cd038dSYoshinobu Inoue * m will point to IPv6 header. mprev will point to the 60182cd038dSYoshinobu Inoue * extension header prior to dest2 (rthdr in the above case). 60282cd038dSYoshinobu Inoue */ 6037efe5d92SHajimu UMEMOTO MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS); 6047efe5d92SHajimu UMEMOTO MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp, 6057efe5d92SHajimu UMEMOTO IPPROTO_DSTOPTS); 6067efe5d92SHajimu UMEMOTO MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp, 6077efe5d92SHajimu UMEMOTO IPPROTO_ROUTING); 60882cd038dSYoshinobu Inoue } 60982cd038dSYoshinobu Inoue 6109cb8d207SAndrey V. Elsukov IP6STAT_INC(ip6s_localout); 61182cd038dSYoshinobu Inoue 6127c1daefeSBjoern A. Zeeb /* Route packet. */ 61382cd038dSYoshinobu Inoue ro_pmtu = ro; 614530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_RHINFO) != 0) 61582cd038dSYoshinobu Inoue ro = &opt->ip6po_route; 616000c42faSBjoern A. Zeeb if (ro != NULL) 61782cd038dSYoshinobu Inoue dst = (struct sockaddr_in6 *)&ro->ro_dst; 618000c42faSBjoern A. Zeeb else 619000c42faSBjoern A. Zeeb dst = &sin6; 6209c57a5b6SHiroki Sato fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : M_GETFIB(m); 621000c42faSBjoern A. Zeeb 6228195404bSBrooks Davis again: 62382cd038dSYoshinobu Inoue /* 6247c1daefeSBjoern A. Zeeb * If specified, try to fill in the traffic class field. 6257c1daefeSBjoern A. Zeeb * Do not override if a non-zero value is already set. 6267c1daefeSBjoern A. Zeeb * We check the diffserv field and the ECN field separately. 627f95d4633SHajimu UMEMOTO */ 628530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_TC) != 0){ 629f95d4633SHajimu UMEMOTO int mask = 0; 630f95d4633SHajimu UMEMOTO 631bb4a7d94SKristof Provost if (IPV6_DSCP(ip6) == 0) 632f95d4633SHajimu UMEMOTO mask |= 0xfc; 633bb4a7d94SKristof Provost if (IPV6_ECN(ip6) == 0) 634f95d4633SHajimu UMEMOTO mask |= 0x03; 635f95d4633SHajimu UMEMOTO if (mask != 0) 636f95d4633SHajimu UMEMOTO ip6->ip6_flow |= htonl((opt->ip6po_tclass & mask) << 20); 637f95d4633SHajimu UMEMOTO } 638f95d4633SHajimu UMEMOTO 6397c1daefeSBjoern A. Zeeb /* Fill in or override the hop limit field, if necessary. */ 640530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_HLIM) != 0) 641f95d4633SHajimu UMEMOTO ip6->ip6_hlim = opt->ip6po_hlim & 0xff; 642f95d4633SHajimu UMEMOTO else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 643f95d4633SHajimu UMEMOTO if (im6o != NULL) 644f95d4633SHajimu UMEMOTO ip6->ip6_hlim = im6o->im6o_multicast_hlim; 645f95d4633SHajimu UMEMOTO else 646603724d3SBjoern A. Zeeb ip6->ip6_hlim = V_ip6_defmcasthlim; 647f95d4633SHajimu UMEMOTO } 648000c42faSBjoern A. Zeeb 649983066f0SAlexander V. Chernikov if (ro == NULL || ro->ro_nh == NULL) { 650000c42faSBjoern A. Zeeb bzero(dst, sizeof(*dst)); 651000c42faSBjoern A. Zeeb dst->sin6_family = AF_INET6; 652000c42faSBjoern A. Zeeb dst->sin6_len = sizeof(*dst); 653000c42faSBjoern A. Zeeb dst->sin6_addr = ip6->ip6_dst; 654000c42faSBjoern A. Zeeb } 65584cc0778SGeorge V. Neville-Neil /* 656000c42faSBjoern A. Zeeb * Validate route against routing table changes. 6577c1daefeSBjoern A. Zeeb * Make sure that the address family is set in route. 65884cc0778SGeorge V. Neville-Neil */ 659983066f0SAlexander V. Chernikov nh = NULL; 660000c42faSBjoern A. Zeeb ifp = NULL; 661000c42faSBjoern A. Zeeb mtu = 0; 662000c42faSBjoern A. Zeeb if (ro != NULL) { 663983066f0SAlexander V. Chernikov if (ro->ro_nh != NULL && inp != NULL) { 664000c42faSBjoern A. Zeeb ro->ro_dst.sin6_family = AF_INET6; /* XXX KASSERT? */ 665983066f0SAlexander V. Chernikov NH_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, 666000c42faSBjoern A. Zeeb fibnum); 66784cc0778SGeorge V. Neville-Neil } 668983066f0SAlexander V. Chernikov if (ro->ro_nh != NULL && fwd_tag == NULL && 669983066f0SAlexander V. Chernikov (!NH_IS_VALID(ro->ro_nh) || 670000c42faSBjoern A. Zeeb ro->ro_dst.sin6_family != AF_INET6 || 671000c42faSBjoern A. Zeeb !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst))) 672000c42faSBjoern A. Zeeb RO_INVALIDATE_CACHE(ro); 673000c42faSBjoern A. Zeeb 674983066f0SAlexander V. Chernikov if (ro->ro_nh != NULL && fwd_tag == NULL && 67584cc0778SGeorge V. Neville-Neil ro->ro_dst.sin6_family == AF_INET6 && 67684cc0778SGeorge V. Neville-Neil IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) { 67750fa27e7SAlexander V. Chernikov /* Nexthop is valid and contains valid ifp */ 678983066f0SAlexander V. Chernikov nh = ro->ro_nh; 67916607317SAndrey V. Elsukov } else { 6800f5687f2SMike Karels if (ro->ro_lle) 6810f5687f2SMike Karels LLE_FREE(ro->ro_lle); /* zeros ro_lle */ 6820f5687f2SMike Karels ro->ro_lle = NULL; 683f8fe3dc9SAndrey V. Elsukov if (fwd_tag == NULL) { 684a1f7e5f8SHajimu UMEMOTO bzero(&dst_sa, sizeof(dst_sa)); 685a1f7e5f8SHajimu UMEMOTO dst_sa.sin6_family = AF_INET6; 686a1f7e5f8SHajimu UMEMOTO dst_sa.sin6_len = sizeof(dst_sa); 687a1f7e5f8SHajimu UMEMOTO dst_sa.sin6_addr = ip6->ip6_dst; 688f8fe3dc9SAndrey V. Elsukov } 6898483fce6SBjoern A. Zeeb error = in6_selectroute(&dst_sa, opt, im6o, ro, &ifp, 690983066f0SAlexander V. Chernikov &nh, fibnum, m->m_pkthdr.flowid); 69116607317SAndrey V. Elsukov if (error != 0) { 692000c42faSBjoern A. Zeeb IP6STAT_INC(ip6s_noroute); 693a1f7e5f8SHajimu UMEMOTO if (ifp != NULL) 69482cd038dSYoshinobu Inoue in6_ifstat_inc(ifp, ifs6_out_discard); 69582cd038dSYoshinobu Inoue goto bad; 69682cd038dSYoshinobu Inoue } 69750fa27e7SAlexander V. Chernikov /* 69850fa27e7SAlexander V. Chernikov * At this point at least @ifp is not NULL 69950fa27e7SAlexander V. Chernikov * Can be the case when dst is multicast, link-local or 70050fa27e7SAlexander V. Chernikov * interface is explicitly specificed by the caller. 70150fa27e7SAlexander V. Chernikov */ 70216607317SAndrey V. Elsukov } 703983066f0SAlexander V. Chernikov if (nh == NULL) { 704a1f7e5f8SHajimu UMEMOTO /* 705983066f0SAlexander V. Chernikov * If in6_selectroute() does not return a nexthop 706a1f7e5f8SHajimu UMEMOTO * dst may not have been updated. 707a1f7e5f8SHajimu UMEMOTO */ 708a1f7e5f8SHajimu UMEMOTO *dst = dst_sa; /* XXX */ 70950fa27e7SAlexander V. Chernikov origifp = ifp; 71050fa27e7SAlexander V. Chernikov mtu = ifp->if_mtu; 711000c42faSBjoern A. Zeeb } else { 71250fa27e7SAlexander V. Chernikov ifp = nh->nh_ifp; 71350fa27e7SAlexander V. Chernikov origifp = nh->nh_aifp; 714983066f0SAlexander V. Chernikov ia = (struct in6_ifaddr *)(nh->nh_ifa); 715983066f0SAlexander V. Chernikov counter_u64_add(nh->nh_pksent, 1); 716000c42faSBjoern A. Zeeb } 717000c42faSBjoern A. Zeeb } else { 7181483c1c5SAlexander V. Chernikov struct nhop_object *nh; 719000c42faSBjoern A. Zeeb struct in6_addr kdst; 720000c42faSBjoern A. Zeeb uint32_t scopeid; 721000c42faSBjoern A. Zeeb 722000c42faSBjoern A. Zeeb if (fwd_tag == NULL) { 723000c42faSBjoern A. Zeeb bzero(&dst_sa, sizeof(dst_sa)); 724000c42faSBjoern A. Zeeb dst_sa.sin6_family = AF_INET6; 725000c42faSBjoern A. Zeeb dst_sa.sin6_len = sizeof(dst_sa); 726000c42faSBjoern A. Zeeb dst_sa.sin6_addr = ip6->ip6_dst; 727000c42faSBjoern A. Zeeb } 728000c42faSBjoern A. Zeeb 729000c42faSBjoern A. Zeeb if (IN6_IS_ADDR_MULTICAST(&dst_sa.sin6_addr) && 730000c42faSBjoern A. Zeeb im6o != NULL && 731000c42faSBjoern A. Zeeb (ifp = im6o->im6o_multicast_ifp) != NULL) { 732000c42faSBjoern A. Zeeb /* We do not need a route lookup. */ 733000c42faSBjoern A. Zeeb *dst = dst_sa; /* XXX */ 73450fa27e7SAlexander V. Chernikov origifp = ifp; 735000c42faSBjoern A. Zeeb goto nonh6lookup; 736000c42faSBjoern A. Zeeb } 737000c42faSBjoern A. Zeeb 738000c42faSBjoern A. Zeeb in6_splitscope(&dst_sa.sin6_addr, &kdst, &scopeid); 739000c42faSBjoern A. Zeeb 740000c42faSBjoern A. Zeeb if (IN6_IS_ADDR_MC_LINKLOCAL(&dst_sa.sin6_addr) || 741000c42faSBjoern A. Zeeb IN6_IS_ADDR_MC_NODELOCAL(&dst_sa.sin6_addr)) { 742000c42faSBjoern A. Zeeb if (scopeid > 0) { 743000c42faSBjoern A. Zeeb ifp = in6_getlinkifnet(scopeid); 74419afc65aSMark Johnston if (ifp == NULL) { 74519afc65aSMark Johnston error = EHOSTUNREACH; 74619afc65aSMark Johnston goto bad; 74719afc65aSMark Johnston } 748000c42faSBjoern A. Zeeb *dst = dst_sa; /* XXX */ 74950fa27e7SAlexander V. Chernikov origifp = ifp; 750000c42faSBjoern A. Zeeb goto nonh6lookup; 751000c42faSBjoern A. Zeeb } 752000c42faSBjoern A. Zeeb } 753000c42faSBjoern A. Zeeb 7540c325f53SAlexander V. Chernikov nh = fib6_lookup(fibnum, &kdst, scopeid, NHR_NONE, 7550c325f53SAlexander V. Chernikov m->m_pkthdr.flowid); 7561483c1c5SAlexander V. Chernikov if (nh == NULL) { 757000c42faSBjoern A. Zeeb IP6STAT_INC(ip6s_noroute); 758000c42faSBjoern A. Zeeb /* No ifp in6_ifstat_inc(ifp, ifs6_out_discard); */ 75921cc0918SElliott Mitchell error = EHOSTUNREACH; 760000c42faSBjoern A. Zeeb goto bad; 761000c42faSBjoern A. Zeeb } 762000c42faSBjoern A. Zeeb 7631483c1c5SAlexander V. Chernikov ifp = nh->nh_ifp; 76450fa27e7SAlexander V. Chernikov origifp = nh->nh_aifp; 7651483c1c5SAlexander V. Chernikov ia = ifatoia6(nh->nh_ifa); 7661483c1c5SAlexander V. Chernikov if (nh->nh_flags & NHF_GATEWAY) 7671483c1c5SAlexander V. Chernikov dst->sin6_addr = nh->gw6_sa.sin6_addr; 7687d98cc09SAndrey V. Elsukov else if (fwd_tag != NULL) 7697d98cc09SAndrey V. Elsukov dst->sin6_addr = dst_sa.sin6_addr; 770000c42faSBjoern A. Zeeb nonh6lookup: 771000c42faSBjoern A. Zeeb ; 77282cd038dSYoshinobu Inoue } 77350fa27e7SAlexander V. Chernikov /* 77450fa27e7SAlexander V. Chernikov * At this point ifp MUST be pointing to the valid transmit ifp. 77550fa27e7SAlexander V. Chernikov * origifp MUST be valid and pointing to either the same ifp or, 77650fa27e7SAlexander V. Chernikov * in case of loopback output, to the interface which ip6_src 77750fa27e7SAlexander V. Chernikov * belongs to. 77850fa27e7SAlexander V. Chernikov * Examples: 77950fa27e7SAlexander V. Chernikov * fe80::1%em0 -> fe80::2%em0 -> ifp=em0, origifp=em0 78050fa27e7SAlexander V. Chernikov * fe80::1%em0 -> fe80::1%em0 -> ifp=lo0, origifp=em0 78150fa27e7SAlexander V. Chernikov * ::1 -> ::1 -> ifp=lo0, origifp=lo0 78250fa27e7SAlexander V. Chernikov * 78350fa27e7SAlexander V. Chernikov * mtu can be 0 and will be refined later. 78450fa27e7SAlexander V. Chernikov */ 78550fa27e7SAlexander V. Chernikov KASSERT((ifp != NULL), ("output interface must not be NULL")); 78650fa27e7SAlexander V. Chernikov KASSERT((origifp != NULL), ("output address interface must not be NULL")); 78782cd038dSYoshinobu Inoue 788da0efbdbSKonstantin Belousov #if defined(IPSEC) || defined(IPSEC_SUPPORT) 789da0efbdbSKonstantin Belousov /* 790da0efbdbSKonstantin Belousov * IPSec checking which handles several cases. 791da0efbdbSKonstantin Belousov * FAST IPSEC: We re-injected the packet. 792da0efbdbSKonstantin Belousov * XXX: need scope argument. 793da0efbdbSKonstantin Belousov */ 794da0efbdbSKonstantin Belousov if (IPSEC_ENABLED(ipv6)) { 795*b0e02076SKonstantin Belousov struct mbuf *m1; 796*b0e02076SKonstantin Belousov 797*b0e02076SKonstantin Belousov error = mb_unmapped_to_ext(m, &m1); 798*b0e02076SKonstantin Belousov if (error != 0) { 799*b0e02076SKonstantin Belousov if (error == ENOMEM) { 800da0efbdbSKonstantin Belousov IP6STAT_INC(ip6s_odropped); 801da0efbdbSKonstantin Belousov error = ENOBUFS; 802da0efbdbSKonstantin Belousov goto bad; 803da0efbdbSKonstantin Belousov } 804*b0e02076SKonstantin Belousov /* XXXKIB */ 805*b0e02076SKonstantin Belousov goto no_ipsec; 806*b0e02076SKonstantin Belousov } 807*b0e02076SKonstantin Belousov m = m1; 808f8707400SKonstantin Belousov if ((error = IPSEC_OUTPUT(ipv6, ifp, m, inp, mtu == 0 ? 809f8707400SKonstantin Belousov ifp->if_mtu : mtu)) != 0) { 810da0efbdbSKonstantin Belousov if (error == EINPROGRESS) 811da0efbdbSKonstantin Belousov error = 0; 812da0efbdbSKonstantin Belousov goto done; 813da0efbdbSKonstantin Belousov } 814*b0e02076SKonstantin Belousov no_ipsec:; 815da0efbdbSKonstantin Belousov } 816da0efbdbSKonstantin Belousov #endif /* IPSEC */ 817da0efbdbSKonstantin Belousov 818a1f7e5f8SHajimu UMEMOTO if ((flags & IPV6_FORWARDING) == 0) { 819a1f7e5f8SHajimu UMEMOTO /* XXX: the FORWARDING flag can be set for mrouting. */ 820a1f7e5f8SHajimu UMEMOTO in6_ifstat_inc(ifp, ifs6_out_request); 821a1f7e5f8SHajimu UMEMOTO } 822a1f7e5f8SHajimu UMEMOTO 823ef0111fdSHans Petter Selasky /* Setup data structures for scope ID checks. */ 824a1f7e5f8SHajimu UMEMOTO src0 = ip6->ip6_src; 825a1f7e5f8SHajimu UMEMOTO bzero(&src_sa, sizeof(src_sa)); 826a1f7e5f8SHajimu UMEMOTO src_sa.sin6_family = AF_INET6; 827a1f7e5f8SHajimu UMEMOTO src_sa.sin6_len = sizeof(src_sa); 828a1f7e5f8SHajimu UMEMOTO src_sa.sin6_addr = ip6->ip6_src; 829a1f7e5f8SHajimu UMEMOTO 830a1f7e5f8SHajimu UMEMOTO dst0 = ip6->ip6_dst; 8317c1daefeSBjoern A. Zeeb /* Re-initialize to be sure. */ 832a1f7e5f8SHajimu UMEMOTO bzero(&dst_sa, sizeof(dst_sa)); 833a1f7e5f8SHajimu UMEMOTO dst_sa.sin6_family = AF_INET6; 834a1f7e5f8SHajimu UMEMOTO dst_sa.sin6_len = sizeof(dst_sa); 835a1f7e5f8SHajimu UMEMOTO dst_sa.sin6_addr = ip6->ip6_dst; 836a1f7e5f8SHajimu UMEMOTO 837ef0111fdSHans Petter Selasky /* Check for valid scope ID. */ 83850fa27e7SAlexander V. Chernikov if (in6_setscope(&src0, origifp, &zone) == 0 && 839ef0111fdSHans Petter Selasky sa6_recoverscope(&src_sa) == 0 && zone == src_sa.sin6_scope_id && 84050fa27e7SAlexander V. Chernikov in6_setscope(&dst0, origifp, &zone) == 0 && 841ef0111fdSHans Petter Selasky sa6_recoverscope(&dst_sa) == 0 && zone == dst_sa.sin6_scope_id) { 842ef0111fdSHans Petter Selasky /* 843ef0111fdSHans Petter Selasky * The outgoing interface is in the zone of the source 844ef0111fdSHans Petter Selasky * and destination addresses. 845ef0111fdSHans Petter Selasky * 846ef0111fdSHans Petter Selasky */ 84750fa27e7SAlexander V. Chernikov } else if ((origifp->if_flags & IFF_LOOPBACK) == 0 || 848ef0111fdSHans Petter Selasky sa6_recoverscope(&src_sa) != 0 || 849ef0111fdSHans Petter Selasky sa6_recoverscope(&dst_sa) != 0 || 850ef0111fdSHans Petter Selasky dst_sa.sin6_scope_id == 0 || 851ef0111fdSHans Petter Selasky (src_sa.sin6_scope_id != 0 && 852ef0111fdSHans Petter Selasky src_sa.sin6_scope_id != dst_sa.sin6_scope_id) || 85350fa27e7SAlexander V. Chernikov ifnet_byindex(dst_sa.sin6_scope_id) == NULL) { 854ef0111fdSHans Petter Selasky /* 855ef0111fdSHans Petter Selasky * If the destination network interface is not a 856ef0111fdSHans Petter Selasky * loopback interface, or the destination network 857ef0111fdSHans Petter Selasky * address has no scope ID, or the source address has 858ef0111fdSHans Petter Selasky * a scope ID set which is different from the 859ef0111fdSHans Petter Selasky * destination address one, or there is no network 860ef0111fdSHans Petter Selasky * interface representing this scope ID, the address 861ef0111fdSHans Petter Selasky * pair is considered invalid. 862ef0111fdSHans Petter Selasky */ 8639cb8d207SAndrey V. Elsukov IP6STAT_INC(ip6s_badscope); 86450fa27e7SAlexander V. Chernikov in6_ifstat_inc(origifp, ifs6_out_discard); 865a1f7e5f8SHajimu UMEMOTO if (error == 0) 866a1f7e5f8SHajimu UMEMOTO error = EHOSTUNREACH; /* XXX */ 867a1f7e5f8SHajimu UMEMOTO goto bad; 868ef0111fdSHans Petter Selasky } 869ef0111fdSHans Petter Selasky /* All scope ID checks are successful. */ 870ef0111fdSHans Petter Selasky 871983066f0SAlexander V. Chernikov if (nh && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 872530c2c30SAndrew Gallatin if ((optvalid & IP6PO_VALID_NHINFO) != 0) { 873a1f7e5f8SHajimu UMEMOTO /* 874a1f7e5f8SHajimu UMEMOTO * The nexthop is explicitly specified by the 875a1f7e5f8SHajimu UMEMOTO * application. We assume the next hop is an IPv6 876a1f7e5f8SHajimu UMEMOTO * address. 877a1f7e5f8SHajimu UMEMOTO */ 878a1f7e5f8SHajimu UMEMOTO dst = (struct sockaddr_in6 *)opt->ip6po_nexthop; 879a1f7e5f8SHajimu UMEMOTO } 880983066f0SAlexander V. Chernikov else if ((nh->nh_flags & NHF_GATEWAY)) 881983066f0SAlexander V. Chernikov dst = &nh->gw6_sa; 882a1f7e5f8SHajimu UMEMOTO } 883a1f7e5f8SHajimu UMEMOTO 884a1f7e5f8SHajimu UMEMOTO if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 8857c1daefeSBjoern A. Zeeb m->m_flags &= ~(M_BCAST | M_MCAST); /* Just in case. */ 88682cd038dSYoshinobu Inoue } else { 88782cd038dSYoshinobu Inoue m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST; 88882cd038dSYoshinobu Inoue in6_ifstat_inc(ifp, ifs6_out_mcast); 8897c1daefeSBjoern A. Zeeb 8907c1daefeSBjoern A. Zeeb /* Confirm that the outgoing interface supports multicast. */ 891a1f7e5f8SHajimu UMEMOTO if (!(ifp->if_flags & IFF_MULTICAST)) { 8929cb8d207SAndrey V. Elsukov IP6STAT_INC(ip6s_noroute); 89382cd038dSYoshinobu Inoue in6_ifstat_inc(ifp, ifs6_out_discard); 89482cd038dSYoshinobu Inoue error = ENETUNREACH; 89582cd038dSYoshinobu Inoue goto bad; 89682cd038dSYoshinobu Inoue } 89733cde130SBruce M Simpson if ((im6o == NULL && in6_mcast_loop) || 89833cde130SBruce M Simpson (im6o && im6o->im6o_multicast_loop)) { 89982cd038dSYoshinobu Inoue /* 90033cde130SBruce M Simpson * Loop back multicast datagram if not expressly 90133cde130SBruce M Simpson * forbidden to do so, even if we have not joined 90233cde130SBruce M Simpson * the address; protocols will filter it later, 90333cde130SBruce M Simpson * thus deferring a hash lookup and lock acquisition 90433cde130SBruce M Simpson * at the expense of an m_copym(). 90582cd038dSYoshinobu Inoue */ 906331dff07SAlexander V. Chernikov ip6_mloopback(ifp, m); 90791ec0a1eSYoshinobu Inoue } else { 90891ec0a1eSYoshinobu Inoue /* 90991ec0a1eSYoshinobu Inoue * If we are acting as a multicast router, perform 91091ec0a1eSYoshinobu Inoue * multicast forwarding as if the packet had just 91191ec0a1eSYoshinobu Inoue * arrived on the interface to which we are about 91291ec0a1eSYoshinobu Inoue * to send. The multicast forwarding function 91391ec0a1eSYoshinobu Inoue * recursively calls this function, using the 91491ec0a1eSYoshinobu Inoue * IPV6_FORWARDING flag to prevent infinite recursion. 91591ec0a1eSYoshinobu Inoue * 91691ec0a1eSYoshinobu Inoue * Multicasts that are looped back by ip6_mloopback(), 91791ec0a1eSYoshinobu Inoue * above, will be forwarded by the ip6_input() routine, 91891ec0a1eSYoshinobu Inoue * if necessary. 91991ec0a1eSYoshinobu Inoue */ 92033cde130SBruce M Simpson if (V_ip6_mrouter && (flags & IPV6_FORWARDING) == 0) { 921a1f7e5f8SHajimu UMEMOTO /* 922a1f7e5f8SHajimu UMEMOTO * XXX: ip6_mforward expects that rcvif is NULL 923a1f7e5f8SHajimu UMEMOTO * when it is called from the originating path. 9247b07d1beSGleb Smirnoff * However, it may not always be the case. 925a1f7e5f8SHajimu UMEMOTO */ 926a1f7e5f8SHajimu UMEMOTO m->m_pkthdr.rcvif = NULL; 927686cdd19SJun-ichiro itojun Hagino if (ip6_mforward(ip6, ifp, m) != 0) { 92891ec0a1eSYoshinobu Inoue m_freem(m); 92991ec0a1eSYoshinobu Inoue goto done; 93091ec0a1eSYoshinobu Inoue } 93191ec0a1eSYoshinobu Inoue } 93282cd038dSYoshinobu Inoue } 93382cd038dSYoshinobu Inoue /* 93482cd038dSYoshinobu Inoue * Multicasts with a hoplimit of zero may be looped back, 93582cd038dSYoshinobu Inoue * above, but must not be transmitted on a network. 93682cd038dSYoshinobu Inoue * Also, multicasts addressed to the loopback interface 93782cd038dSYoshinobu Inoue * are not sent -- the above call to ip6_mloopback() will 93882cd038dSYoshinobu Inoue * loop back a copy if this host actually belongs to the 93982cd038dSYoshinobu Inoue * destination group on the loopback interface. 94082cd038dSYoshinobu Inoue */ 941f95d4633SHajimu UMEMOTO if (ip6->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK) || 942f95d4633SHajimu UMEMOTO IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)) { 94382cd038dSYoshinobu Inoue m_freem(m); 94482cd038dSYoshinobu Inoue goto done; 94582cd038dSYoshinobu Inoue } 94682cd038dSYoshinobu Inoue } 94782cd038dSYoshinobu Inoue 94882cd038dSYoshinobu Inoue /* 94982cd038dSYoshinobu Inoue * Fill the outgoing inteface to tell the upper layer 95082cd038dSYoshinobu Inoue * to increment per-interface statistics. 95182cd038dSYoshinobu Inoue */ 95282cd038dSYoshinobu Inoue if (ifpp) 95382cd038dSYoshinobu Inoue *ifpp = ifp; 95482cd038dSYoshinobu Inoue 95531b3783cSHajimu UMEMOTO /* Determine path MTU. */ 956f0937b2cSAndrey V. Elsukov if ((error = ip6_getpmtu(ro_pmtu, ro != ro_pmtu, ifp, &ip6->ip6_dst, 957d4c22202SAndrew Gallatin &mtu, &alwaysfrag, fibnum, *nexthdrp)) != 0) 95831b3783cSHajimu UMEMOTO goto bad; 959000c42faSBjoern A. Zeeb KASSERT(mtu > 0, ("%s:%d: mtu %ld, ro_pmtu %p ro %p ifp %p " 960000c42faSBjoern A. Zeeb "alwaysfrag %d fibnum %u\n", __func__, __LINE__, mtu, ro_pmtu, ro, 961000c42faSBjoern A. Zeeb ifp, alwaysfrag, fibnum)); 96282cd038dSYoshinobu Inoue 96333841545SHajimu UMEMOTO /* 9648b00e59dSHajimu UMEMOTO * The caller of this function may specify to use the minimum MTU 9658b00e59dSHajimu UMEMOTO * in some cases. 9668b00e59dSHajimu UMEMOTO * An advanced API option (IPV6_USE_MIN_MTU) can also override MTU 9678b00e59dSHajimu UMEMOTO * setting. The logic is a bit complicated; by default, unicast 9688b00e59dSHajimu UMEMOTO * packets will follow path MTU while multicast packets will be sent at 9698b00e59dSHajimu UMEMOTO * the minimum MTU. If IP6PO_MINMTU_ALL is specified, all packets 9708b00e59dSHajimu UMEMOTO * including unicast ones will be sent at the minimum MTU. Multicast 9718b00e59dSHajimu UMEMOTO * packets will always be sent at the minimum MTU unless 9728b00e59dSHajimu UMEMOTO * IP6PO_MINMTU_DISABLE is explicitly specified. 9738b00e59dSHajimu UMEMOTO * See RFC 3542 for more details. 97433841545SHajimu UMEMOTO */ 9758b00e59dSHajimu UMEMOTO if (mtu > IPV6_MMTU) { 9768b00e59dSHajimu UMEMOTO if ((flags & IPV6_MINMTU)) 97733841545SHajimu UMEMOTO mtu = IPV6_MMTU; 9788b00e59dSHajimu UMEMOTO else if (opt && opt->ip6po_minmtu == IP6PO_MINMTU_ALL) 9798b00e59dSHajimu UMEMOTO mtu = IPV6_MMTU; 9808b00e59dSHajimu UMEMOTO else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && 9818b00e59dSHajimu UMEMOTO (opt == NULL || 9828b00e59dSHajimu UMEMOTO opt->ip6po_minmtu != IP6PO_MINMTU_DISABLE)) { 9838b00e59dSHajimu UMEMOTO mtu = IPV6_MMTU; 9848b00e59dSHajimu UMEMOTO } 9858b00e59dSHajimu UMEMOTO } 98633841545SHajimu UMEMOTO 98733841545SHajimu UMEMOTO /* 9887c1daefeSBjoern A. Zeeb * Clear embedded scope identifiers if necessary. 9897c1daefeSBjoern A. Zeeb * in6_clearscope() will touch the addresses only when necessary. 99033841545SHajimu UMEMOTO */ 99133841545SHajimu UMEMOTO in6_clearscope(&ip6->ip6_src); 99233841545SHajimu UMEMOTO in6_clearscope(&ip6->ip6_dst); 99382cd038dSYoshinobu Inoue 99482cd038dSYoshinobu Inoue /* 99582cd038dSYoshinobu Inoue * If the outgoing packet contains a hop-by-hop options header, 99682cd038dSYoshinobu Inoue * it must be examined and processed even by the source node. 99782cd038dSYoshinobu Inoue * (RFC 2460, section 4.) 99882cd038dSYoshinobu Inoue */ 99982cd038dSYoshinobu Inoue if (exthdrs.ip6e_hbh) { 100033841545SHajimu UMEMOTO struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *); 1001283f9f8aSHajimu UMEMOTO u_int32_t dummy; /* XXX unused */ 1002283f9f8aSHajimu UMEMOTO u_int32_t plen = 0; /* XXX: ip6_process will check the value */ 100382cd038dSYoshinobu Inoue 100433841545SHajimu UMEMOTO #ifdef DIAGNOSTIC 100533841545SHajimu UMEMOTO if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len) 10066d79f3f6SRebecca Cran panic("ip6e_hbh is not contiguous"); 100733841545SHajimu UMEMOTO #endif 100882cd038dSYoshinobu Inoue /* 100982cd038dSYoshinobu Inoue * XXX: if we have to send an ICMPv6 error to the sender, 101082cd038dSYoshinobu Inoue * we need the M_LOOP flag since icmp6_error() expects 101182cd038dSYoshinobu Inoue * the IPv6 and the hop-by-hop options header are 10126d79f3f6SRebecca Cran * contiguous unless the flag is set. 101382cd038dSYoshinobu Inoue */ 101482cd038dSYoshinobu Inoue m->m_flags |= M_LOOP; 101582cd038dSYoshinobu Inoue m->m_pkthdr.rcvif = ifp; 10167efe5d92SHajimu UMEMOTO if (ip6_process_hopopts(m, (u_int8_t *)(hbh + 1), 10177efe5d92SHajimu UMEMOTO ((hbh->ip6h_len + 1) << 3) - sizeof(struct ip6_hbh), 1018283f9f8aSHajimu UMEMOTO &dummy, &plen) < 0) { 10197c1daefeSBjoern A. Zeeb /* m was already freed at this point. */ 102082cd038dSYoshinobu Inoue error = EINVAL;/* better error? */ 102182cd038dSYoshinobu Inoue goto done; 102282cd038dSYoshinobu Inoue } 102382cd038dSYoshinobu Inoue m->m_flags &= ~M_LOOP; /* XXX */ 102482cd038dSYoshinobu Inoue m->m_pkthdr.rcvif = NULL; 102582cd038dSYoshinobu Inoue } 102682cd038dSYoshinobu Inoue 1027c21fd232SAndre Oppermann /* Jump over all PFIL processing if hooks are not active. */ 1028b252313fSGleb Smirnoff if (!PFIL_HOOKED_OUT(V_inet6_pfil_head)) 1029c21fd232SAndre Oppermann goto passout; 1030c21fd232SAndre Oppermann 10318195404bSBrooks Davis odst = ip6->ip6_dst; 1032c21fd232SAndre Oppermann /* Run through list of hooks for output packets. */ 1033dda6376bSMateusz Guzik switch (pfil_mbuf_out(V_inet6_pfil_head, &m, ifp, inp)) { 1034b252313fSGleb Smirnoff case PFIL_PASS: 1035c4ac87eaSDarren Reed ip6 = mtod(m, struct ip6_hdr *); 1036b252313fSGleb Smirnoff break; 1037b252313fSGleb Smirnoff case PFIL_DROPPED: 1038e00ee1a9SGleb Smirnoff error = EACCES; 1039b252313fSGleb Smirnoff /* FALLTHROUGH */ 1040b252313fSGleb Smirnoff case PFIL_CONSUMED: 1041b252313fSGleb Smirnoff goto done; 1042b252313fSGleb Smirnoff } 10437efe5d92SHajimu UMEMOTO 10449c57a5b6SHiroki Sato needfiblookup = 0; 10458195404bSBrooks Davis /* See if destination IP address was changed by packet filter. */ 10468195404bSBrooks Davis if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) { 10478195404bSBrooks Davis m->m_flags |= M_SKIP_FIREWALL; 10488195404bSBrooks Davis /* If destination is now ourself drop to ip6_input(). */ 10498a006adbSBjoern A. Zeeb if (in6_localip(&ip6->ip6_dst)) { 10508a006adbSBjoern A. Zeeb m->m_flags |= M_FASTFWD_OURS; 10518195404bSBrooks Davis if (m->m_pkthdr.rcvif == NULL) 1052603724d3SBjoern A. Zeeb m->m_pkthdr.rcvif = V_loif; 1053356ab07eSBjoern A. Zeeb if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 10548195404bSBrooks Davis m->m_pkthdr.csum_flags |= 1055356ab07eSBjoern A. Zeeb CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR; 10568195404bSBrooks Davis m->m_pkthdr.csum_data = 0xffff; 10578195404bSBrooks Davis } 105895033af9SMark Johnston #if defined(SCTP) || defined(SCTP_SUPPORT) 1059a6cff10fSMichael Tuexen if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) 10609b03990aSRandall Stewart m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; 10619b03990aSRandall Stewart #endif 10628195404bSBrooks Davis error = netisr_queue(NETISR_IPV6, m); 10638195404bSBrooks Davis goto done; 10644ee7e5a6SAndrey V. Elsukov } else { 1065000c42faSBjoern A. Zeeb if (ro != NULL) 1066ec86402eSBjoern A. Zeeb RO_INVALIDATE_CACHE(ro); 10679c57a5b6SHiroki Sato needfiblookup = 1; /* Redo the routing table lookup. */ 10688195404bSBrooks Davis } 10694ee7e5a6SAndrey V. Elsukov } 10709c57a5b6SHiroki Sato /* See if fib was changed by packet filter. */ 10719c57a5b6SHiroki Sato if (fibnum != M_GETFIB(m)) { 10729c57a5b6SHiroki Sato m->m_flags |= M_SKIP_FIREWALL; 10739c57a5b6SHiroki Sato fibnum = M_GETFIB(m); 1074000c42faSBjoern A. Zeeb if (ro != NULL) 1075ec86402eSBjoern A. Zeeb RO_INVALIDATE_CACHE(ro); 10769c57a5b6SHiroki Sato needfiblookup = 1; 10779c57a5b6SHiroki Sato } 10789c57a5b6SHiroki Sato if (needfiblookup) 10799c57a5b6SHiroki Sato goto again; 10808195404bSBrooks Davis 10818a006adbSBjoern A. Zeeb /* See if local, if yes, send it to netisr. */ 10828a006adbSBjoern A. Zeeb if (m->m_flags & M_FASTFWD_OURS) { 10838a006adbSBjoern A. Zeeb if (m->m_pkthdr.rcvif == NULL) 10848a006adbSBjoern A. Zeeb m->m_pkthdr.rcvif = V_loif; 1085356ab07eSBjoern A. Zeeb if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 10868a006adbSBjoern A. Zeeb m->m_pkthdr.csum_flags |= 1087356ab07eSBjoern A. Zeeb CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR; 10888a006adbSBjoern A. Zeeb m->m_pkthdr.csum_data = 0xffff; 10898a006adbSBjoern A. Zeeb } 109095033af9SMark Johnston #if defined(SCTP) || defined(SCTP_SUPPORT) 1091a6cff10fSMichael Tuexen if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) 10928a006adbSBjoern A. Zeeb m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; 10938a006adbSBjoern A. Zeeb #endif 10948a006adbSBjoern A. Zeeb error = netisr_queue(NETISR_IPV6, m); 10958a006adbSBjoern A. Zeeb goto done; 10968a006adbSBjoern A. Zeeb } 10978a006adbSBjoern A. Zeeb /* Or forward to some other address? */ 1098ffdbf9daSAndrey V. Elsukov if ((m->m_flags & M_IP6_NEXTHOP) && 1099ffdbf9daSAndrey V. Elsukov (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { 1100000c42faSBjoern A. Zeeb if (ro != NULL) 11018a006adbSBjoern A. Zeeb dst = (struct sockaddr_in6 *)&ro->ro_dst; 1102000c42faSBjoern A. Zeeb else 1103000c42faSBjoern A. Zeeb dst = &sin6; 1104f8fe3dc9SAndrey V. Elsukov bcopy((fwd_tag+1), &dst_sa, sizeof(struct sockaddr_in6)); 11058a006adbSBjoern A. Zeeb m->m_flags |= M_SKIP_FIREWALL; 1106ffdbf9daSAndrey V. Elsukov m->m_flags &= ~M_IP6_NEXTHOP; 11078a006adbSBjoern A. Zeeb m_tag_delete(m, fwd_tag); 11088a006adbSBjoern A. Zeeb goto again; 11098a006adbSBjoern A. Zeeb } 11108195404bSBrooks Davis 1111c21fd232SAndre Oppermann passout: 1112868aabb4SRichard Scheffenegger if (vlan_pcp > -1) 1113868aabb4SRichard Scheffenegger EVL_APPLY_PRI(m, vlan_pcp); 111444775b16SMark Johnston 111544775b16SMark Johnston /* Ensure the packet data is mapped if the interface requires it. */ 111644775b16SMark Johnston if ((ifp->if_capenable & IFCAP_MEXTPG) == 0) { 1117*b0e02076SKonstantin Belousov struct mbuf *m1; 1118*b0e02076SKonstantin Belousov 1119*b0e02076SKonstantin Belousov error = mb_unmapped_to_ext(m, &m1); 1120*b0e02076SKonstantin Belousov if (error != 0) { 1121*b0e02076SKonstantin Belousov if (error == EINVAL) { 1122*b0e02076SKonstantin Belousov if_printf(ifp, "TLS packet\n"); 1123*b0e02076SKonstantin Belousov /* XXXKIB */ 1124*b0e02076SKonstantin Belousov } else if (error == ENOMEM) { 1125*b0e02076SKonstantin Belousov error = ENOBUFS; 1126*b0e02076SKonstantin Belousov } 112744775b16SMark Johnston IP6STAT_INC(ip6s_odropped); 1128*b0e02076SKonstantin Belousov return (error); 1129*b0e02076SKonstantin Belousov } else { 1130*b0e02076SKonstantin Belousov m = m1; 113144775b16SMark Johnston } 113244775b16SMark Johnston } 113344775b16SMark Johnston 113482cd038dSYoshinobu Inoue /* 113582cd038dSYoshinobu Inoue * Send the packet to the outgoing interface. 113682cd038dSYoshinobu Inoue * If necessary, do IPv6 fragmentation before sending. 1137f95d4633SHajimu UMEMOTO * 11387c1daefeSBjoern A. Zeeb * The logic here is rather complex: 1139f95d4633SHajimu UMEMOTO * 1: normal case (dontfrag == 0, alwaysfrag == 0) 1140f95d4633SHajimu UMEMOTO * 1-a: send as is if tlen <= path mtu 1141f95d4633SHajimu UMEMOTO * 1-b: fragment if tlen > path mtu 1142f95d4633SHajimu UMEMOTO * 1143f95d4633SHajimu UMEMOTO * 2: if user asks us not to fragment (dontfrag == 1) 1144f95d4633SHajimu UMEMOTO * 2-a: send as is if tlen <= interface mtu 1145f95d4633SHajimu UMEMOTO * 2-b: error if tlen > interface mtu 1146f95d4633SHajimu UMEMOTO * 1147f95d4633SHajimu UMEMOTO * 3: if we always need to attach fragment header (alwaysfrag == 1) 1148f95d4633SHajimu UMEMOTO * always fragment 1149f95d4633SHajimu UMEMOTO * 1150f95d4633SHajimu UMEMOTO * 4: if dontfrag == 1 && alwaysfrag == 1 11517c1daefeSBjoern A. Zeeb * error, as we cannot handle this conflicting request. 115282cd038dSYoshinobu Inoue */ 1153e7b92e27SBjoern A. Zeeb sw_csum = m->m_pkthdr.csum_flags; 1154e7b92e27SBjoern A. Zeeb if (!hdrsplit) { 1155b092fd6cSNavdeep Parhar tso = ((sw_csum & ifp->if_hwassist & 1156b092fd6cSNavdeep Parhar (CSUM_TSO | CSUM_INNER_TSO)) != 0) ? 1 : 0; 1157e7b92e27SBjoern A. Zeeb sw_csum &= ~ifp->if_hwassist; 1158e7b92e27SBjoern A. Zeeb } else 1159e7b92e27SBjoern A. Zeeb tso = 0; 1160e7b92e27SBjoern A. Zeeb /* 1161e7b92e27SBjoern A. Zeeb * If we added extension headers, we will not do TSO and calculate the 1162e7b92e27SBjoern A. Zeeb * checksums ourselves for now. 1163e7b92e27SBjoern A. Zeeb * XXX-BZ Need a framework to know when the NIC can handle it, even 1164e7b92e27SBjoern A. Zeeb * with ext. hdrs. 1165e7b92e27SBjoern A. Zeeb */ 116644775b16SMark Johnston ip6_output_delayed_csum(m, ifp, sw_csum, plen, optlen); 11673459050cSBjoern A. Zeeb /* XXX-BZ m->m_pkthdr.csum_flags &= ~ifp->if_hwassist; */ 116882cd038dSYoshinobu Inoue tlen = m->m_pkthdr.len; 116982cd038dSYoshinobu Inoue 1170e7b92e27SBjoern A. Zeeb if ((opt && (opt->ip6po_flags & IP6PO_DONTFRAG)) || tso) 1171f95d4633SHajimu UMEMOTO dontfrag = 1; 1172f95d4633SHajimu UMEMOTO else 1173f95d4633SHajimu UMEMOTO dontfrag = 0; 11747c1daefeSBjoern A. Zeeb if (dontfrag && alwaysfrag) { /* Case 4. */ 11757c1daefeSBjoern A. Zeeb /* Conflicting request - can't transmit. */ 1176f95d4633SHajimu UMEMOTO error = EMSGSIZE; 1177f95d4633SHajimu UMEMOTO goto bad; 1178f95d4633SHajimu UMEMOTO } 11797c1daefeSBjoern A. Zeeb if (dontfrag && tlen > IN6_LINKMTU(ifp) && !tso) { /* Case 2-b. */ 1180f95d4633SHajimu UMEMOTO /* 1181f95d4633SHajimu UMEMOTO * Even if the DONTFRAG option is specified, we cannot send the 1182f95d4633SHajimu UMEMOTO * packet when the data length is larger than the MTU of the 1183f95d4633SHajimu UMEMOTO * outgoing interface. 11848f1beb88SAndrey V. Elsukov * Notify the error by sending IPV6_PATHMTU ancillary data if 11858f1beb88SAndrey V. Elsukov * application wanted to know the MTU value. Also return an 11868f1beb88SAndrey V. Elsukov * error code (this is not described in the API spec). 1187f95d4633SHajimu UMEMOTO */ 11888f1beb88SAndrey V. Elsukov if (inp != NULL) 11898f1beb88SAndrey V. Elsukov ip6_notify_pmtu(inp, &dst_sa, (u_int32_t)mtu); 1190f95d4633SHajimu UMEMOTO error = EMSGSIZE; 1191f95d4633SHajimu UMEMOTO goto bad; 1192f95d4633SHajimu UMEMOTO } 1193f95d4633SHajimu UMEMOTO 11947c1daefeSBjoern A. Zeeb /* Transmit packet without fragmentation. */ 11957c1daefeSBjoern A. Zeeb if (dontfrag || (!alwaysfrag && tlen <= mtu)) { /* Cases 1-a and 2-a. */ 1196f95d4633SHajimu UMEMOTO struct in6_ifaddr *ia6; 1197f95d4633SHajimu UMEMOTO 1198f95d4633SHajimu UMEMOTO ip6 = mtod(m, struct ip6_hdr *); 1199f95d4633SHajimu UMEMOTO ia6 = in6_ifawithifp(ifp, &ip6->ip6_src); 1200f95d4633SHajimu UMEMOTO if (ia6) { 12015da9f8faSJosef Karthauser /* Record statistics for this interface address. */ 12027caf4ab7SGleb Smirnoff counter_u64_add(ia6->ia_ifa.ifa_opackets, 1); 12037caf4ab7SGleb Smirnoff counter_u64_add(ia6->ia_ifa.ifa_obytes, 12047caf4ab7SGleb Smirnoff m->m_pkthdr.len); 12055da9f8faSJosef Karthauser } 1206d7452d89SAndrew Gallatin error = ip6_output_send(inp, ifp, origifp, m, dst, ro, 1207d7452d89SAndrew Gallatin (flags & IP_NO_SND_TAG_RL) ? false : true); 120882cd038dSYoshinobu Inoue goto done; 1209f95d4633SHajimu UMEMOTO } 1210f95d4633SHajimu UMEMOTO 12117c1daefeSBjoern A. Zeeb /* Try to fragment the packet. Cases 1-b and 3. */ 1212f95d4633SHajimu UMEMOTO if (mtu < IPV6_MMTU) { 12137c1daefeSBjoern A. Zeeb /* Path MTU cannot be less than IPV6_MMTU. */ 121482cd038dSYoshinobu Inoue error = EMSGSIZE; 121582cd038dSYoshinobu Inoue in6_ifstat_inc(ifp, ifs6_out_fragfail); 121682cd038dSYoshinobu Inoue goto bad; 12177efe5d92SHajimu UMEMOTO } else if (ip6->ip6_plen == 0) { 12187c1daefeSBjoern A. Zeeb /* Jumbo payload cannot be fragmented. */ 121982cd038dSYoshinobu Inoue error = EMSGSIZE; 122082cd038dSYoshinobu Inoue in6_ifstat_inc(ifp, ifs6_out_fragfail); 122182cd038dSYoshinobu Inoue goto bad; 122282cd038dSYoshinobu Inoue } else { 122382cd038dSYoshinobu Inoue u_char nextproto; 12242cb64cb2SGeorge V. Neville-Neil 122582cd038dSYoshinobu Inoue /* 122682cd038dSYoshinobu Inoue * Too large for the destination or interface; 122782cd038dSYoshinobu Inoue * fragment if possible. 122882cd038dSYoshinobu Inoue * Must be able to put at least 8 bytes per fragment. 122982cd038dSYoshinobu Inoue */ 123082cd038dSYoshinobu Inoue if (mtu > IPV6_MAXPACKET) 123182cd038dSYoshinobu Inoue mtu = IPV6_MAXPACKET; 123233841545SHajimu UMEMOTO 12333459050cSBjoern A. Zeeb len = (mtu - unfragpartlen - sizeof(struct ip6_frag)) & ~7; 123482cd038dSYoshinobu Inoue if (len < 8) { 123582cd038dSYoshinobu Inoue error = EMSGSIZE; 123682cd038dSYoshinobu Inoue in6_ifstat_inc(ifp, ifs6_out_fragfail); 123782cd038dSYoshinobu Inoue goto bad; 123882cd038dSYoshinobu Inoue } 123982cd038dSYoshinobu Inoue 12406f8aee22SBill Paul /* 1241e7b92e27SBjoern A. Zeeb * If the interface will not calculate checksums on 1242e7b92e27SBjoern A. Zeeb * fragmented packets, then do it here. 1243e7b92e27SBjoern A. Zeeb * XXX-BZ handle the hw offloading case. Need flags. 1244e7b92e27SBjoern A. Zeeb */ 124544775b16SMark Johnston ip6_output_delayed_csum(m, ifp, m->m_pkthdr.csum_flags, plen, 124644775b16SMark Johnston optlen); 12473459050cSBjoern A. Zeeb 124882cd038dSYoshinobu Inoue /* 124982cd038dSYoshinobu Inoue * Change the next header field of the last header in the 125082cd038dSYoshinobu Inoue * unfragmentable part. 125182cd038dSYoshinobu Inoue */ 125282cd038dSYoshinobu Inoue if (exthdrs.ip6e_rthdr) { 125382cd038dSYoshinobu Inoue nextproto = *mtod(exthdrs.ip6e_rthdr, u_char *); 125482cd038dSYoshinobu Inoue *mtod(exthdrs.ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT; 125582cd038dSYoshinobu Inoue } else if (exthdrs.ip6e_dest1) { 125682cd038dSYoshinobu Inoue nextproto = *mtod(exthdrs.ip6e_dest1, u_char *); 125782cd038dSYoshinobu Inoue *mtod(exthdrs.ip6e_dest1, u_char *) = IPPROTO_FRAGMENT; 125882cd038dSYoshinobu Inoue } else if (exthdrs.ip6e_hbh) { 125982cd038dSYoshinobu Inoue nextproto = *mtod(exthdrs.ip6e_hbh, u_char *); 126082cd038dSYoshinobu Inoue *mtod(exthdrs.ip6e_hbh, u_char *) = IPPROTO_FRAGMENT; 126182cd038dSYoshinobu Inoue } else { 12623459050cSBjoern A. Zeeb ip6 = mtod(m, struct ip6_hdr *); 126382cd038dSYoshinobu Inoue nextproto = ip6->ip6_nxt; 126482cd038dSYoshinobu Inoue ip6->ip6_nxt = IPPROTO_FRAGMENT; 126582cd038dSYoshinobu Inoue } 126682cd038dSYoshinobu Inoue 126782cd038dSYoshinobu Inoue /* 126882cd038dSYoshinobu Inoue * Loop through length of segment after first fragment, 126988ff5695SSUZUKI Shinsuke * make new header and copy data of each part and link onto 127088ff5695SSUZUKI Shinsuke * chain. 127182cd038dSYoshinobu Inoue */ 127282cd038dSYoshinobu Inoue m0 = m; 127379831849SKristof Provost id = htonl(ip6_randomid()); 12743459050cSBjoern A. Zeeb error = ip6_fragment(ifp, m, unfragpartlen, nextproto,len, id); 12753459050cSBjoern A. Zeeb if (error != 0) 127682cd038dSYoshinobu Inoue goto sendorfree; 127782cd038dSYoshinobu Inoue 127882cd038dSYoshinobu Inoue in6_ifstat_inc(ifp, ifs6_out_fragok); 127982cd038dSYoshinobu Inoue } 128082cd038dSYoshinobu Inoue 12817c1daefeSBjoern A. Zeeb /* Remove leading garbage. */ 128282cd038dSYoshinobu Inoue sendorfree: 128382cd038dSYoshinobu Inoue m = m0->m_nextpkt; 128482cd038dSYoshinobu Inoue m0->m_nextpkt = 0; 128582cd038dSYoshinobu Inoue m_freem(m0); 1286c187c034SJonathan T. Looney for (; m; m = m0) { 128782cd038dSYoshinobu Inoue m0 = m->m_nextpkt; 128882cd038dSYoshinobu Inoue m->m_nextpkt = 0; 128982cd038dSYoshinobu Inoue if (error == 0) { 1290fe937674SJosef Karthauser /* Record statistics for this interface address. */ 1291fe937674SJosef Karthauser if (ia) { 12927caf4ab7SGleb Smirnoff counter_u64_add(ia->ia_ifa.ifa_opackets, 1); 12937caf4ab7SGleb Smirnoff counter_u64_add(ia->ia_ifa.ifa_obytes, 12947caf4ab7SGleb Smirnoff m->m_pkthdr.len); 1295fe937674SJosef Karthauser } 1296868aabb4SRichard Scheffenegger if (vlan_pcp > -1) 1297868aabb4SRichard Scheffenegger EVL_APPLY_PRI(m, vlan_pcp); 1298d7452d89SAndrew Gallatin error = ip6_output_send(inp, ifp, origifp, m, dst, ro, 1299d7452d89SAndrew Gallatin true); 130082cd038dSYoshinobu Inoue } else 130182cd038dSYoshinobu Inoue m_freem(m); 130282cd038dSYoshinobu Inoue } 130382cd038dSYoshinobu Inoue 130482cd038dSYoshinobu Inoue if (error == 0) 13059cb8d207SAndrey V. Elsukov IP6STAT_INC(ip6s_fragmented); 130682cd038dSYoshinobu Inoue 130782cd038dSYoshinobu Inoue done: 130882cd038dSYoshinobu Inoue return (error); 130982cd038dSYoshinobu Inoue 131082cd038dSYoshinobu Inoue freehdrs: 13117c1daefeSBjoern A. Zeeb m_freem(exthdrs.ip6e_hbh); /* m_freem() checks if mbuf is NULL. */ 131282cd038dSYoshinobu Inoue m_freem(exthdrs.ip6e_dest1); 131382cd038dSYoshinobu Inoue m_freem(exthdrs.ip6e_rthdr); 131482cd038dSYoshinobu Inoue m_freem(exthdrs.ip6e_dest2); 13157efe5d92SHajimu UMEMOTO /* FALLTHROUGH */ 131682cd038dSYoshinobu Inoue bad: 13172cb64cb2SGeorge V. Neville-Neil if (m) 131882cd038dSYoshinobu Inoue m_freem(m); 131982cd038dSYoshinobu Inoue goto done; 132082cd038dSYoshinobu Inoue } 132182cd038dSYoshinobu Inoue 132282cd038dSYoshinobu Inoue static int 13231272577eSXin LI ip6_copyexthdr(struct mbuf **mp, caddr_t hdr, int hlen) 132482cd038dSYoshinobu Inoue { 132582cd038dSYoshinobu Inoue struct mbuf *m; 132682cd038dSYoshinobu Inoue 132782cd038dSYoshinobu Inoue if (hlen > MCLBYTES) 132882cd038dSYoshinobu Inoue return (ENOBUFS); /* XXX */ 132982cd038dSYoshinobu Inoue 133010e5acc3SGleb Smirnoff if (hlen > MLEN) 133110e5acc3SGleb Smirnoff m = m_getcl(M_NOWAIT, MT_DATA, 0); 133210e5acc3SGleb Smirnoff else 133310e5acc3SGleb Smirnoff m = m_get(M_NOWAIT, MT_DATA); 133410e5acc3SGleb Smirnoff if (m == NULL) 133582cd038dSYoshinobu Inoue return (ENOBUFS); 133682cd038dSYoshinobu Inoue m->m_len = hlen; 133782cd038dSYoshinobu Inoue if (hdr) 133882cd038dSYoshinobu Inoue bcopy(hdr, mtod(m, caddr_t), hlen); 133982cd038dSYoshinobu Inoue 134082cd038dSYoshinobu Inoue *mp = m; 134182cd038dSYoshinobu Inoue return (0); 134282cd038dSYoshinobu Inoue } 134382cd038dSYoshinobu Inoue 134482cd038dSYoshinobu Inoue /* 134582cd038dSYoshinobu Inoue * Insert jumbo payload option. 134682cd038dSYoshinobu Inoue */ 134782cd038dSYoshinobu Inoue static int 13481272577eSXin LI ip6_insert_jumboopt(struct ip6_exthdrs *exthdrs, u_int32_t plen) 134982cd038dSYoshinobu Inoue { 135082cd038dSYoshinobu Inoue struct mbuf *mopt; 135182cd038dSYoshinobu Inoue u_char *optbuf; 135233841545SHajimu UMEMOTO u_int32_t v; 135382cd038dSYoshinobu Inoue 135482cd038dSYoshinobu Inoue #define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */ 135582cd038dSYoshinobu Inoue 135682cd038dSYoshinobu Inoue /* 135782cd038dSYoshinobu Inoue * If there is no hop-by-hop options header, allocate new one. 135882cd038dSYoshinobu Inoue * If there is one but it doesn't have enough space to store the 135982cd038dSYoshinobu Inoue * jumbo payload option, allocate a cluster to store the whole options. 136082cd038dSYoshinobu Inoue * Otherwise, use it to store the options. 136182cd038dSYoshinobu Inoue */ 1362155d72c4SPedro F. Giffuni if (exthdrs->ip6e_hbh == NULL) { 136310e5acc3SGleb Smirnoff mopt = m_get(M_NOWAIT, MT_DATA); 136410e5acc3SGleb Smirnoff if (mopt == NULL) 136582cd038dSYoshinobu Inoue return (ENOBUFS); 136682cd038dSYoshinobu Inoue mopt->m_len = JUMBOOPTLEN; 136782cd038dSYoshinobu Inoue optbuf = mtod(mopt, u_char *); 136882cd038dSYoshinobu Inoue optbuf[1] = 0; /* = ((JUMBOOPTLEN) >> 3) - 1 */ 136982cd038dSYoshinobu Inoue exthdrs->ip6e_hbh = mopt; 137082cd038dSYoshinobu Inoue } else { 137182cd038dSYoshinobu Inoue struct ip6_hbh *hbh; 137282cd038dSYoshinobu Inoue 137382cd038dSYoshinobu Inoue mopt = exthdrs->ip6e_hbh; 137482cd038dSYoshinobu Inoue if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) { 137533841545SHajimu UMEMOTO /* 137633841545SHajimu UMEMOTO * XXX assumption: 137733841545SHajimu UMEMOTO * - exthdrs->ip6e_hbh is not referenced from places 137833841545SHajimu UMEMOTO * other than exthdrs. 137933841545SHajimu UMEMOTO * - exthdrs->ip6e_hbh is not an mbuf chain. 138033841545SHajimu UMEMOTO */ 138182cd038dSYoshinobu Inoue int oldoptlen = mopt->m_len; 138233841545SHajimu UMEMOTO struct mbuf *n; 138382cd038dSYoshinobu Inoue 138433841545SHajimu UMEMOTO /* 138533841545SHajimu UMEMOTO * XXX: give up if the whole (new) hbh header does 138633841545SHajimu UMEMOTO * not fit even in an mbuf cluster. 138733841545SHajimu UMEMOTO */ 138833841545SHajimu UMEMOTO if (oldoptlen + JUMBOOPTLEN > MCLBYTES) 138982cd038dSYoshinobu Inoue return (ENOBUFS); 139082cd038dSYoshinobu Inoue 139133841545SHajimu UMEMOTO /* 139233841545SHajimu UMEMOTO * As a consequence, we must always prepare a cluster 139333841545SHajimu UMEMOTO * at this point. 139433841545SHajimu UMEMOTO */ 139510e5acc3SGleb Smirnoff n = m_getcl(M_NOWAIT, MT_DATA, 0); 139610e5acc3SGleb Smirnoff if (n == NULL) 139733841545SHajimu UMEMOTO return (ENOBUFS); 139833841545SHajimu UMEMOTO n->m_len = oldoptlen + JUMBOOPTLEN; 139933841545SHajimu UMEMOTO bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t), 140033841545SHajimu UMEMOTO oldoptlen); 140133841545SHajimu UMEMOTO optbuf = mtod(n, caddr_t) + oldoptlen; 140233841545SHajimu UMEMOTO m_freem(mopt); 140333841545SHajimu UMEMOTO mopt = exthdrs->ip6e_hbh = n; 140482cd038dSYoshinobu Inoue } else { 140582cd038dSYoshinobu Inoue optbuf = mtod(mopt, u_char *) + mopt->m_len; 140682cd038dSYoshinobu Inoue mopt->m_len += JUMBOOPTLEN; 140782cd038dSYoshinobu Inoue } 140882cd038dSYoshinobu Inoue optbuf[0] = IP6OPT_PADN; 140982cd038dSYoshinobu Inoue optbuf[1] = 1; 141082cd038dSYoshinobu Inoue 141182cd038dSYoshinobu Inoue /* 141282cd038dSYoshinobu Inoue * Adjust the header length according to the pad and 141382cd038dSYoshinobu Inoue * the jumbo payload option. 141482cd038dSYoshinobu Inoue */ 141582cd038dSYoshinobu Inoue hbh = mtod(mopt, struct ip6_hbh *); 141682cd038dSYoshinobu Inoue hbh->ip6h_len += (JUMBOOPTLEN >> 3); 141782cd038dSYoshinobu Inoue } 141882cd038dSYoshinobu Inoue 141982cd038dSYoshinobu Inoue /* fill in the option. */ 142082cd038dSYoshinobu Inoue optbuf[2] = IP6OPT_JUMBO; 142182cd038dSYoshinobu Inoue optbuf[3] = 4; 142233841545SHajimu UMEMOTO v = (u_int32_t)htonl(plen + JUMBOOPTLEN); 142333841545SHajimu UMEMOTO bcopy(&v, &optbuf[4], sizeof(u_int32_t)); 142482cd038dSYoshinobu Inoue 142582cd038dSYoshinobu Inoue /* finally, adjust the packet header length */ 142682cd038dSYoshinobu Inoue exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN; 142782cd038dSYoshinobu Inoue 142882cd038dSYoshinobu Inoue return (0); 142982cd038dSYoshinobu Inoue #undef JUMBOOPTLEN 143082cd038dSYoshinobu Inoue } 143182cd038dSYoshinobu Inoue 143282cd038dSYoshinobu Inoue /* 143382cd038dSYoshinobu Inoue * Insert fragment header and copy unfragmentable header portions. 143482cd038dSYoshinobu Inoue */ 143582cd038dSYoshinobu Inoue static int 14361272577eSXin LI ip6_insertfraghdr(struct mbuf *m0, struct mbuf *m, int hlen, 14371272577eSXin LI struct ip6_frag **frghdrp) 143882cd038dSYoshinobu Inoue { 143982cd038dSYoshinobu Inoue struct mbuf *n, *mlast; 144082cd038dSYoshinobu Inoue 144182cd038dSYoshinobu Inoue if (hlen > sizeof(struct ip6_hdr)) { 144282cd038dSYoshinobu Inoue n = m_copym(m0, sizeof(struct ip6_hdr), 1443eb1b1807SGleb Smirnoff hlen - sizeof(struct ip6_hdr), M_NOWAIT); 1444155d72c4SPedro F. Giffuni if (n == NULL) 144582cd038dSYoshinobu Inoue return (ENOBUFS); 144682cd038dSYoshinobu Inoue m->m_next = n; 144782cd038dSYoshinobu Inoue } else 144882cd038dSYoshinobu Inoue n = m; 144982cd038dSYoshinobu Inoue 145082cd038dSYoshinobu Inoue /* Search for the last mbuf of unfragmentable part. */ 145182cd038dSYoshinobu Inoue for (mlast = n; mlast->m_next; mlast = mlast->m_next) 145282cd038dSYoshinobu Inoue ; 145382cd038dSYoshinobu Inoue 1454f0cace5dSRobert Watson if (M_WRITABLE(mlast) && 1455686cdd19SJun-ichiro itojun Hagino M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) { 145682cd038dSYoshinobu Inoue /* use the trailing space of the last mbuf for the fragment hdr */ 14577efe5d92SHajimu UMEMOTO *frghdrp = (struct ip6_frag *)(mtod(mlast, caddr_t) + 14587efe5d92SHajimu UMEMOTO mlast->m_len); 145982cd038dSYoshinobu Inoue mlast->m_len += sizeof(struct ip6_frag); 146082cd038dSYoshinobu Inoue m->m_pkthdr.len += sizeof(struct ip6_frag); 146182cd038dSYoshinobu Inoue } else { 146282cd038dSYoshinobu Inoue /* allocate a new mbuf for the fragment header */ 146382cd038dSYoshinobu Inoue struct mbuf *mfrg; 146482cd038dSYoshinobu Inoue 146510e5acc3SGleb Smirnoff mfrg = m_get(M_NOWAIT, MT_DATA); 146610e5acc3SGleb Smirnoff if (mfrg == NULL) 146782cd038dSYoshinobu Inoue return (ENOBUFS); 146882cd038dSYoshinobu Inoue mfrg->m_len = sizeof(struct ip6_frag); 146982cd038dSYoshinobu Inoue *frghdrp = mtod(mfrg, struct ip6_frag *); 147082cd038dSYoshinobu Inoue mlast->m_next = mfrg; 147182cd038dSYoshinobu Inoue } 147282cd038dSYoshinobu Inoue 147382cd038dSYoshinobu Inoue return (0); 147482cd038dSYoshinobu Inoue } 147582cd038dSYoshinobu Inoue 14760d4df029SAlexander V. Chernikov /* 14770d4df029SAlexander V. Chernikov * Calculates IPv6 path mtu for destination @dst. 14780d4df029SAlexander V. Chernikov * Resulting MTU is stored in @mtup. 14790d4df029SAlexander V. Chernikov * 14800d4df029SAlexander V. Chernikov * Returns 0 on success. 14810d4df029SAlexander V. Chernikov */ 148231b3783cSHajimu UMEMOTO static int 1483f0937b2cSAndrey V. Elsukov ip6_getpmtu_ctl(u_int fibnum, const struct in6_addr *dst, u_long *mtup) 14840d4df029SAlexander V. Chernikov { 14851483c1c5SAlexander V. Chernikov struct epoch_tracker et; 14861483c1c5SAlexander V. Chernikov struct nhop_object *nh; 1487bacf6684SAlexander V. Chernikov struct in6_addr kdst; 1488bacf6684SAlexander V. Chernikov uint32_t scopeid; 1489bacf6684SAlexander V. Chernikov int error; 14900d4df029SAlexander V. Chernikov 1491bacf6684SAlexander V. Chernikov in6_splitscope(dst, &kdst, &scopeid); 14920d4df029SAlexander V. Chernikov 14931483c1c5SAlexander V. Chernikov NET_EPOCH_ENTER(et); 14941483c1c5SAlexander V. Chernikov nh = fib6_lookup(fibnum, &kdst, scopeid, NHR_NONE, 0); 14951483c1c5SAlexander V. Chernikov if (nh != NULL) 14961483c1c5SAlexander V. Chernikov error = ip6_calcmtu(nh->nh_ifp, dst, nh->nh_mtu, mtup, NULL, 0); 14971483c1c5SAlexander V. Chernikov else 14981483c1c5SAlexander V. Chernikov error = EHOSTUNREACH; 14991483c1c5SAlexander V. Chernikov NET_EPOCH_EXIT(et); 1500bacf6684SAlexander V. Chernikov 1501bacf6684SAlexander V. Chernikov return (error); 15020d4df029SAlexander V. Chernikov } 15030d4df029SAlexander V. Chernikov 15040d4df029SAlexander V. Chernikov /* 15050d4df029SAlexander V. Chernikov * Calculates IPv6 path MTU for @dst based on transmit @ifp, 15060d4df029SAlexander V. Chernikov * and cached data in @ro_pmtu. 15070d4df029SAlexander V. Chernikov * MTU from (successful) route lookup is saved (along with dst) 15080d4df029SAlexander V. Chernikov * inside @ro_pmtu to avoid subsequent route lookups after packet 15090d4df029SAlexander V. Chernikov * filter processing. 15100d4df029SAlexander V. Chernikov * 15110d4df029SAlexander V. Chernikov * Stores mtu and always-frag value into @mtup and @alwaysfragp. 15120d4df029SAlexander V. Chernikov * Returns 0 on success. 15130d4df029SAlexander V. Chernikov */ 15140d4df029SAlexander V. Chernikov static int 15150d4df029SAlexander V. Chernikov ip6_getpmtu(struct route_in6 *ro_pmtu, int do_lookup, 1516f0937b2cSAndrey V. Elsukov struct ifnet *ifp, const struct in6_addr *dst, u_long *mtup, 1517d4c22202SAndrew Gallatin int *alwaysfragp, u_int fibnum, u_int proto) 151831b3783cSHajimu UMEMOTO { 15191483c1c5SAlexander V. Chernikov struct nhop_object *nh; 1520bacf6684SAlexander V. Chernikov struct in6_addr kdst; 1521bacf6684SAlexander V. Chernikov uint32_t scopeid; 1522000c42faSBjoern A. Zeeb struct sockaddr_in6 *sa6_dst, sin6; 15230d4df029SAlexander V. Chernikov u_long mtu; 152431b3783cSHajimu UMEMOTO 15251483c1c5SAlexander V. Chernikov NET_EPOCH_ASSERT(); 15261483c1c5SAlexander V. Chernikov 15270d4df029SAlexander V. Chernikov mtu = 0; 1528000c42faSBjoern A. Zeeb if (ro_pmtu == NULL || do_lookup) { 15290d4df029SAlexander V. Chernikov /* 15300d4df029SAlexander V. Chernikov * Here ro_pmtu has final destination address, while 15310d4df029SAlexander V. Chernikov * ro might represent immediate destination. 15320d4df029SAlexander V. Chernikov * Use ro_pmtu destination since mtu might differ. 15330d4df029SAlexander V. Chernikov */ 1534000c42faSBjoern A. Zeeb if (ro_pmtu != NULL) { 15350d4df029SAlexander V. Chernikov sa6_dst = (struct sockaddr_in6 *)&ro_pmtu->ro_dst; 15360d4df029SAlexander V. Chernikov if (!IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst)) 15370d4df029SAlexander V. Chernikov ro_pmtu->ro_mtu = 0; 1538000c42faSBjoern A. Zeeb } else 1539000c42faSBjoern A. Zeeb sa6_dst = &sin6; 15400d4df029SAlexander V. Chernikov 1541000c42faSBjoern A. Zeeb if (ro_pmtu == NULL || ro_pmtu->ro_mtu == 0) { 154231b3783cSHajimu UMEMOTO bzero(sa6_dst, sizeof(*sa6_dst)); 154331b3783cSHajimu UMEMOTO sa6_dst->sin6_family = AF_INET6; 154431b3783cSHajimu UMEMOTO sa6_dst->sin6_len = sizeof(struct sockaddr_in6); 154531b3783cSHajimu UMEMOTO sa6_dst->sin6_addr = *dst; 154631b3783cSHajimu UMEMOTO 1547bacf6684SAlexander V. Chernikov in6_splitscope(dst, &kdst, &scopeid); 15481483c1c5SAlexander V. Chernikov nh = fib6_lookup(fibnum, &kdst, scopeid, NHR_NONE, 0); 15491483c1c5SAlexander V. Chernikov if (nh != NULL) { 15501483c1c5SAlexander V. Chernikov mtu = nh->nh_mtu; 1551000c42faSBjoern A. Zeeb if (ro_pmtu != NULL) 1552000c42faSBjoern A. Zeeb ro_pmtu->ro_mtu = mtu; 15530d4df029SAlexander V. Chernikov } 1554000c42faSBjoern A. Zeeb } else 1555bacf6684SAlexander V. Chernikov mtu = ro_pmtu->ro_mtu; 15560d4df029SAlexander V. Chernikov } 15570d4df029SAlexander V. Chernikov 1558983066f0SAlexander V. Chernikov if (ro_pmtu != NULL && ro_pmtu->ro_nh != NULL) 1559983066f0SAlexander V. Chernikov mtu = ro_pmtu->ro_nh->nh_mtu; 15600d4df029SAlexander V. Chernikov 1561d4c22202SAndrew Gallatin return (ip6_calcmtu(ifp, dst, mtu, mtup, alwaysfragp, proto)); 15620d4df029SAlexander V. Chernikov } 15630d4df029SAlexander V. Chernikov 15640d4df029SAlexander V. Chernikov /* 15650d4df029SAlexander V. Chernikov * Calculate MTU based on transmit @ifp, route mtu @rt_mtu and 15660d4df029SAlexander V. Chernikov * hostcache data for @dst. 15670d4df029SAlexander V. Chernikov * Stores mtu and always-frag value into @mtup and @alwaysfragp. 15680d4df029SAlexander V. Chernikov * 15690d4df029SAlexander V. Chernikov * Returns 0 on success. 15700d4df029SAlexander V. Chernikov */ 15710d4df029SAlexander V. Chernikov static int 15720d4df029SAlexander V. Chernikov ip6_calcmtu(struct ifnet *ifp, const struct in6_addr *dst, u_long rt_mtu, 1573d4c22202SAndrew Gallatin u_long *mtup, int *alwaysfragp, u_int proto) 15740d4df029SAlexander V. Chernikov { 15750d4df029SAlexander V. Chernikov u_long mtu = 0; 15760d4df029SAlexander V. Chernikov int alwaysfrag = 0; 15770d4df029SAlexander V. Chernikov int error = 0; 15780d4df029SAlexander V. Chernikov 15790d4df029SAlexander V. Chernikov if (rt_mtu > 0) { 158031b3783cSHajimu UMEMOTO u_int32_t ifmtu; 158197d8d152SAndre Oppermann struct in_conninfo inc; 158297d8d152SAndre Oppermann 158397d8d152SAndre Oppermann bzero(&inc, sizeof(inc)); 1584dcdb4371SBjoern A. Zeeb inc.inc_flags |= INC_ISIPV6; 158597d8d152SAndre Oppermann inc.inc6_faddr = *dst; 158631b3783cSHajimu UMEMOTO 158731b3783cSHajimu UMEMOTO ifmtu = IN6_LINKMTU(ifp); 1588d4c22202SAndrew Gallatin 1589d4c22202SAndrew Gallatin /* TCP is known to react to pmtu changes so skip hc */ 1590d4c22202SAndrew Gallatin if (proto != IPPROTO_TCP) 159197d8d152SAndre Oppermann mtu = tcp_hc_getmtu(&inc); 1592d4c22202SAndrew Gallatin 159397d8d152SAndre Oppermann if (mtu) 15940d4df029SAlexander V. Chernikov mtu = min(mtu, rt_mtu); 159597d8d152SAndre Oppermann else 15960d4df029SAlexander V. Chernikov mtu = rt_mtu; 159731b3783cSHajimu UMEMOTO if (mtu == 0) 159831b3783cSHajimu UMEMOTO mtu = ifmtu; 1599f95d4633SHajimu UMEMOTO else if (mtu < IPV6_MMTU) { 1600f95d4633SHajimu UMEMOTO /* 1601f95d4633SHajimu UMEMOTO * RFC2460 section 5, last paragraph: 1602f95d4633SHajimu UMEMOTO * if we record ICMPv6 too big message with 1603f95d4633SHajimu UMEMOTO * mtu < IPV6_MMTU, transmit packets sized IPV6_MMTU 1604f95d4633SHajimu UMEMOTO * or smaller, with framgent header attached. 1605f95d4633SHajimu UMEMOTO * (fragment header is needed regardless from the 1606f95d4633SHajimu UMEMOTO * packet size, for translators to identify packets) 1607f95d4633SHajimu UMEMOTO */ 1608f95d4633SHajimu UMEMOTO alwaysfrag = 1; 1609f95d4633SHajimu UMEMOTO mtu = IPV6_MMTU; 161031b3783cSHajimu UMEMOTO } 161131b3783cSHajimu UMEMOTO } else if (ifp) { 161231b3783cSHajimu UMEMOTO mtu = IN6_LINKMTU(ifp); 161331b3783cSHajimu UMEMOTO } else 161431b3783cSHajimu UMEMOTO error = EHOSTUNREACH; /* XXX */ 161531b3783cSHajimu UMEMOTO 161631b3783cSHajimu UMEMOTO *mtup = mtu; 1617f95d4633SHajimu UMEMOTO if (alwaysfragp) 1618f95d4633SHajimu UMEMOTO *alwaysfragp = alwaysfrag; 161931b3783cSHajimu UMEMOTO return (error); 162031b3783cSHajimu UMEMOTO } 162131b3783cSHajimu UMEMOTO 162282cd038dSYoshinobu Inoue /* 162382cd038dSYoshinobu Inoue * IP6 socket option processing. 162482cd038dSYoshinobu Inoue */ 162582cd038dSYoshinobu Inoue int 16261272577eSXin LI ip6_ctloutput(struct socket *so, struct sockopt *sopt) 162782cd038dSYoshinobu Inoue { 162879ba3952SBjoern A. Zeeb int optdatalen, uproto; 1629f95d4633SHajimu UMEMOTO void *optdata; 16300ecd976eSBjoern A. Zeeb struct inpcb *inp = sotoinpcb(so); 163182cd038dSYoshinobu Inoue int error, optval; 163282cd038dSYoshinobu Inoue int level, op, optname; 163382cd038dSYoshinobu Inoue int optlen; 1634b40ce416SJulian Elischer struct thread *td; 1635c7c0d948SAdrian Chadd #ifdef RSS 1636c7c0d948SAdrian Chadd uint32_t rss_bucket; 1637c7c0d948SAdrian Chadd int retval; 1638c7c0d948SAdrian Chadd #endif 163982cd038dSYoshinobu Inoue 1640aec9c8d5SGeorge V. Neville-Neil /* 1641aec9c8d5SGeorge V. Neville-Neil * Don't use more than a quarter of mbuf clusters. N.B.: 1642aec9c8d5SGeorge V. Neville-Neil * nmbclusters is an int, but nmbclusters * MCLBYTES may overflow 1643aec9c8d5SGeorge V. Neville-Neil * on LP64 architectures, so cast to u_long to avoid undefined 1644aec9c8d5SGeorge V. Neville-Neil * behavior. ILP32 architectures cannot have nmbclusters 1645aec9c8d5SGeorge V. Neville-Neil * large enough to overflow for other reasons. 1646aec9c8d5SGeorge V. Neville-Neil */ 1647aec9c8d5SGeorge V. Neville-Neil #define IPV6_PKTOPTIONS_MBUF_LIMIT ((u_long)nmbclusters * MCLBYTES / 4) 1648aec9c8d5SGeorge V. Neville-Neil 164982cd038dSYoshinobu Inoue level = sopt->sopt_level; 165082cd038dSYoshinobu Inoue op = sopt->sopt_dir; 165182cd038dSYoshinobu Inoue optname = sopt->sopt_name; 165282cd038dSYoshinobu Inoue optlen = sopt->sopt_valsize; 1653b40ce416SJulian Elischer td = sopt->sopt_td; 1654cc29ac7dSRobert Watson error = 0; 1655cc29ac7dSRobert Watson optval = 0; 1656f95d4633SHajimu UMEMOTO uproto = (int)so->so_proto->pr_protocol; 165782cd038dSYoshinobu Inoue 1658fc06cd42SMikolaj Golub if (level != IPPROTO_IPV6) { 1659fc06cd42SMikolaj Golub error = EINVAL; 1660fc06cd42SMikolaj Golub 1661fc06cd42SMikolaj Golub if (sopt->sopt_level == SOL_SOCKET && 1662fc06cd42SMikolaj Golub sopt->sopt_dir == SOPT_SET) { 1663fc06cd42SMikolaj Golub switch (sopt->sopt_name) { 1664ee799639SBjoern A. Zeeb case SO_SETFIB: 16650ecd976eSBjoern A. Zeeb INP_WLOCK(inp); 16660ecd976eSBjoern A. Zeeb inp->inp_inc.inc_fibnum = so->so_fibnum; 16670ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 1668ee799639SBjoern A. Zeeb error = 0; 1669ee799639SBjoern A. Zeeb break; 1670f3e7afe2SHans Petter Selasky case SO_MAX_PACING_RATE: 1671f3e7afe2SHans Petter Selasky #ifdef RATELIMIT 16720ecd976eSBjoern A. Zeeb INP_WLOCK(inp); 16730ecd976eSBjoern A. Zeeb inp->inp_flags2 |= INP_RATE_LIMIT_CHANGED; 16740ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 1675f3e7afe2SHans Petter Selasky error = 0; 1676f3e7afe2SHans Petter Selasky #else 1677f3e7afe2SHans Petter Selasky error = EOPNOTSUPP; 1678f3e7afe2SHans Petter Selasky #endif 1679f3e7afe2SHans Petter Selasky break; 1680fc06cd42SMikolaj Golub default: 1681fc06cd42SMikolaj Golub break; 1682fc06cd42SMikolaj Golub } 1683fc06cd42SMikolaj Golub } 1684fc06cd42SMikolaj Golub } else { /* level == IPPROTO_IPV6 */ 168582cd038dSYoshinobu Inoue switch (op) { 168682cd038dSYoshinobu Inoue case SOPT_SET: 168782cd038dSYoshinobu Inoue switch (optname) { 1688f95d4633SHajimu UMEMOTO case IPV6_2292PKTOPTIONS: 1689f95d4633SHajimu UMEMOTO #ifdef IPV6_PKTOPTIONS 169082cd038dSYoshinobu Inoue case IPV6_PKTOPTIONS: 1691f95d4633SHajimu UMEMOTO #endif 169282cd038dSYoshinobu Inoue { 169382cd038dSYoshinobu Inoue struct mbuf *m; 169482cd038dSYoshinobu Inoue 1695aec9c8d5SGeorge V. Neville-Neil if (optlen > IPV6_PKTOPTIONS_MBUF_LIMIT) { 1696aec9c8d5SGeorge V. Neville-Neil printf("ip6_ctloutput: mbuf limit hit\n"); 1697aec9c8d5SGeorge V. Neville-Neil error = ENOBUFS; 1698aec9c8d5SGeorge V. Neville-Neil break; 1699aec9c8d5SGeorge V. Neville-Neil } 1700aec9c8d5SGeorge V. Neville-Neil 170182cd038dSYoshinobu Inoue error = soopt_getm(sopt, &m); /* XXX */ 1702a89ec05eSPeter Wemm if (error != 0) 170382cd038dSYoshinobu Inoue break; 170482cd038dSYoshinobu Inoue error = soopt_mcopyin(sopt, m); /* XXX */ 1705a89ec05eSPeter Wemm if (error != 0) 170682cd038dSYoshinobu Inoue break; 1707e02582d1SMark Johnston INP_WLOCK(inp); 1708e02582d1SMark Johnston error = ip6_pcbopts(&inp->in6p_outputopts, m, 1709e02582d1SMark Johnston so, sopt); 1710e02582d1SMark Johnston INP_WUNLOCK(inp); 171133841545SHajimu UMEMOTO m_freem(m); /* XXX */ 171282cd038dSYoshinobu Inoue break; 171382cd038dSYoshinobu Inoue } 171433841545SHajimu UMEMOTO 171533841545SHajimu UMEMOTO /* 171633841545SHajimu UMEMOTO * Use of some Hop-by-Hop options or some 171733841545SHajimu UMEMOTO * Destination options, might require special 171833841545SHajimu UMEMOTO * privilege. That is, normal applications 171933841545SHajimu UMEMOTO * (without special privilege) might be forbidden 172033841545SHajimu UMEMOTO * from setting certain options in outgoing packets, 172133841545SHajimu UMEMOTO * and might never see certain options in received 172233841545SHajimu UMEMOTO * packets. [RFC 2292 Section 6] 172333841545SHajimu UMEMOTO * KAME specific note: 172433841545SHajimu UMEMOTO * KAME prevents non-privileged users from sending or 172533841545SHajimu UMEMOTO * receiving ANY hbh/dst options in order to avoid 172633841545SHajimu UMEMOTO * overhead of parsing options in the kernel. 172733841545SHajimu UMEMOTO */ 1728f95d4633SHajimu UMEMOTO case IPV6_RECVHOPOPTS: 1729f95d4633SHajimu UMEMOTO case IPV6_RECVDSTOPTS: 1730f95d4633SHajimu UMEMOTO case IPV6_RECVRTHDRDSTOPTS: 173179ba3952SBjoern A. Zeeb if (td != NULL) { 173279ba3952SBjoern A. Zeeb error = priv_check(td, 173379ba3952SBjoern A. Zeeb PRIV_NETINET_SETHDROPTS); 173479ba3952SBjoern A. Zeeb if (error) 1735f95d4633SHajimu UMEMOTO break; 1736f95d4633SHajimu UMEMOTO } 1737f95d4633SHajimu UMEMOTO /* FALLTHROUGH */ 173882cd038dSYoshinobu Inoue case IPV6_UNICAST_HOPS: 1739f95d4633SHajimu UMEMOTO case IPV6_HOPLIMIT: 174033841545SHajimu UMEMOTO 1741f95d4633SHajimu UMEMOTO case IPV6_RECVPKTINFO: 1742f95d4633SHajimu UMEMOTO case IPV6_RECVHOPLIMIT: 1743f95d4633SHajimu UMEMOTO case IPV6_RECVRTHDR: 1744f95d4633SHajimu UMEMOTO case IPV6_RECVPATHMTU: 1745f95d4633SHajimu UMEMOTO case IPV6_RECVTCLASS: 174668bb8d62SAdrian Chadd case IPV6_RECVFLOWID: 174768bb8d62SAdrian Chadd #ifdef RSS 174868bb8d62SAdrian Chadd case IPV6_RECVRSSBUCKETID: 174968bb8d62SAdrian Chadd #endif 175033841545SHajimu UMEMOTO case IPV6_V6ONLY: 1751f95d4633SHajimu UMEMOTO case IPV6_AUTOFLOWLABEL: 1752dce33a45SErmal Luçi case IPV6_ORIGDSTADDR: 1753f44270e7SPawel Jakub Dawidek case IPV6_BINDANY: 1754868aabb4SRichard Scheffenegger case IPV6_VLAN_PCP: 1755f44270e7SPawel Jakub Dawidek if (optname == IPV6_BINDANY && td != NULL) { 1756f44270e7SPawel Jakub Dawidek error = priv_check(td, 1757f44270e7SPawel Jakub Dawidek PRIV_NETINET_BINDANY); 1758f44270e7SPawel Jakub Dawidek if (error) 1759f44270e7SPawel Jakub Dawidek break; 1760f44270e7SPawel Jakub Dawidek } 1761f44270e7SPawel Jakub Dawidek 176233841545SHajimu UMEMOTO if (optlen != sizeof(int)) { 176382cd038dSYoshinobu Inoue error = EINVAL; 176433841545SHajimu UMEMOTO break; 176533841545SHajimu UMEMOTO } 176682cd038dSYoshinobu Inoue error = sooptcopyin(sopt, &optval, 176782cd038dSYoshinobu Inoue sizeof optval, sizeof optval); 176882cd038dSYoshinobu Inoue if (error) 176982cd038dSYoshinobu Inoue break; 177082cd038dSYoshinobu Inoue switch (optname) { 177182cd038dSYoshinobu Inoue case IPV6_UNICAST_HOPS: 177282cd038dSYoshinobu Inoue if (optval < -1 || optval >= 256) 177382cd038dSYoshinobu Inoue error = EINVAL; 177482cd038dSYoshinobu Inoue else { 177582cd038dSYoshinobu Inoue /* -1 = kernel default */ 17760ecd976eSBjoern A. Zeeb inp->in6p_hops = optval; 17770ecd976eSBjoern A. Zeeb if ((inp->inp_vflag & 177882cd038dSYoshinobu Inoue INP_IPV4) != 0) 17790ecd976eSBjoern A. Zeeb inp->inp_ip_ttl = optval; 178082cd038dSYoshinobu Inoue } 178182cd038dSYoshinobu Inoue break; 178282cd038dSYoshinobu Inoue #define OPTSET(bit) \ 178333841545SHajimu UMEMOTO do { \ 17840ecd976eSBjoern A. Zeeb INP_WLOCK(inp); \ 178582cd038dSYoshinobu Inoue if (optval) \ 17860ecd976eSBjoern A. Zeeb inp->inp_flags |= (bit); \ 178782cd038dSYoshinobu Inoue else \ 17880ecd976eSBjoern A. Zeeb inp->inp_flags &= ~(bit); \ 17890ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); \ 17907efe5d92SHajimu UMEMOTO } while (/*CONSTCOND*/ 0) 1791f95d4633SHajimu UMEMOTO #define OPTSET2292(bit) \ 1792f95d4633SHajimu UMEMOTO do { \ 17930ecd976eSBjoern A. Zeeb INP_WLOCK(inp); \ 17940ecd976eSBjoern A. Zeeb inp->inp_flags |= IN6P_RFC2292; \ 1795f95d4633SHajimu UMEMOTO if (optval) \ 17960ecd976eSBjoern A. Zeeb inp->inp_flags |= (bit); \ 1797f95d4633SHajimu UMEMOTO else \ 17980ecd976eSBjoern A. Zeeb inp->inp_flags &= ~(bit); \ 17990ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); \ 1800f95d4633SHajimu UMEMOTO } while (/*CONSTCOND*/ 0) 18010ecd976eSBjoern A. Zeeb #define OPTBIT(bit) (inp->inp_flags & (bit) ? 1 : 0) 180282cd038dSYoshinobu Inoue 180337d4fc1eSSean Bruno #define OPTSET2_N(bit, val) do { \ 1804c7c0d948SAdrian Chadd if (val) \ 18050ecd976eSBjoern A. Zeeb inp->inp_flags2 |= bit; \ 1806c7c0d948SAdrian Chadd else \ 18070ecd976eSBjoern A. Zeeb inp->inp_flags2 &= ~bit; \ 180837d4fc1eSSean Bruno } while (0) 180937d4fc1eSSean Bruno #define OPTSET2(bit, val) do { \ 18100ecd976eSBjoern A. Zeeb INP_WLOCK(inp); \ 181137d4fc1eSSean Bruno OPTSET2_N(bit, val); \ 18120ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); \ 1813c7c0d948SAdrian Chadd } while (0) 18140ecd976eSBjoern A. Zeeb #define OPTBIT2(bit) (inp->inp_flags2 & (bit) ? 1 : 0) 181537d4fc1eSSean Bruno #define OPTSET2292_EXCLUSIVE(bit) \ 181637d4fc1eSSean Bruno do { \ 18170ecd976eSBjoern A. Zeeb INP_WLOCK(inp); \ 181837d4fc1eSSean Bruno if (OPTBIT(IN6P_RFC2292)) { \ 181937d4fc1eSSean Bruno error = EINVAL; \ 182037d4fc1eSSean Bruno } else { \ 182137d4fc1eSSean Bruno if (optval) \ 18220ecd976eSBjoern A. Zeeb inp->inp_flags |= (bit); \ 182337d4fc1eSSean Bruno else \ 18240ecd976eSBjoern A. Zeeb inp->inp_flags &= ~(bit); \ 182537d4fc1eSSean Bruno } \ 18260ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); \ 182737d4fc1eSSean Bruno } while (/*CONSTCOND*/ 0) 1828c7c0d948SAdrian Chadd 1829f95d4633SHajimu UMEMOTO case IPV6_RECVPKTINFO: 183037d4fc1eSSean Bruno OPTSET2292_EXCLUSIVE(IN6P_PKTINFO); 1831f95d4633SHajimu UMEMOTO break; 1832f95d4633SHajimu UMEMOTO 1833f95d4633SHajimu UMEMOTO case IPV6_HOPLIMIT: 1834f95d4633SHajimu UMEMOTO { 1835f95d4633SHajimu UMEMOTO struct ip6_pktopts **optp; 1836f95d4633SHajimu UMEMOTO 1837f95d4633SHajimu UMEMOTO /* cannot mix with RFC2292 */ 1838f95d4633SHajimu UMEMOTO if (OPTBIT(IN6P_RFC2292)) { 1839f95d4633SHajimu UMEMOTO error = EINVAL; 1840f95d4633SHajimu UMEMOTO break; 1841f95d4633SHajimu UMEMOTO } 18420ecd976eSBjoern A. Zeeb INP_WLOCK(inp); 184353af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 18440ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 184556713d16SMatt Macy return (ECONNRESET); 184656713d16SMatt Macy } 18470ecd976eSBjoern A. Zeeb optp = &inp->in6p_outputopts; 1848f95d4633SHajimu UMEMOTO error = ip6_pcbopt(IPV6_HOPLIMIT, 184979ba3952SBjoern A. Zeeb (u_char *)&optval, sizeof(optval), 185079ba3952SBjoern A. Zeeb optp, (td != NULL) ? td->td_ucred : 185179ba3952SBjoern A. Zeeb NULL, uproto); 18520ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 1853f95d4633SHajimu UMEMOTO break; 1854f95d4633SHajimu UMEMOTO } 1855f95d4633SHajimu UMEMOTO 1856f95d4633SHajimu UMEMOTO case IPV6_RECVHOPLIMIT: 185737d4fc1eSSean Bruno OPTSET2292_EXCLUSIVE(IN6P_HOPLIMIT); 1858f95d4633SHajimu UMEMOTO break; 1859f95d4633SHajimu UMEMOTO 1860f95d4633SHajimu UMEMOTO case IPV6_RECVHOPOPTS: 186137d4fc1eSSean Bruno OPTSET2292_EXCLUSIVE(IN6P_HOPOPTS); 1862f95d4633SHajimu UMEMOTO break; 1863f95d4633SHajimu UMEMOTO 1864f95d4633SHajimu UMEMOTO case IPV6_RECVDSTOPTS: 186537d4fc1eSSean Bruno OPTSET2292_EXCLUSIVE(IN6P_DSTOPTS); 1866f95d4633SHajimu UMEMOTO break; 1867f95d4633SHajimu UMEMOTO 1868f95d4633SHajimu UMEMOTO case IPV6_RECVRTHDRDSTOPTS: 186937d4fc1eSSean Bruno OPTSET2292_EXCLUSIVE(IN6P_RTHDRDSTOPTS); 1870f95d4633SHajimu UMEMOTO break; 1871f95d4633SHajimu UMEMOTO 1872f95d4633SHajimu UMEMOTO case IPV6_RECVRTHDR: 187337d4fc1eSSean Bruno OPTSET2292_EXCLUSIVE(IN6P_RTHDR); 187482cd038dSYoshinobu Inoue break; 187582cd038dSYoshinobu Inoue 1876f95d4633SHajimu UMEMOTO case IPV6_RECVPATHMTU: 1877f95d4633SHajimu UMEMOTO /* 1878f95d4633SHajimu UMEMOTO * We ignore this option for TCP 1879f95d4633SHajimu UMEMOTO * sockets. 188018b35df8SHajimu UMEMOTO * (RFC3542 leaves this case 1881f95d4633SHajimu UMEMOTO * unspecified.) 1882f95d4633SHajimu UMEMOTO */ 1883f95d4633SHajimu UMEMOTO if (uproto != IPPROTO_TCP) 1884f95d4633SHajimu UMEMOTO OPTSET(IN6P_MTU); 1885f95d4633SHajimu UMEMOTO break; 1886f95d4633SHajimu UMEMOTO 188768bb8d62SAdrian Chadd case IPV6_RECVFLOWID: 188868bb8d62SAdrian Chadd OPTSET2(INP_RECVFLOWID, optval); 188968bb8d62SAdrian Chadd break; 189068bb8d62SAdrian Chadd 189168bb8d62SAdrian Chadd #ifdef RSS 189268bb8d62SAdrian Chadd case IPV6_RECVRSSBUCKETID: 189368bb8d62SAdrian Chadd OPTSET2(INP_RECVRSSBUCKETID, optval); 189468bb8d62SAdrian Chadd break; 189568bb8d62SAdrian Chadd #endif 189668bb8d62SAdrian Chadd 189733841545SHajimu UMEMOTO case IPV6_V6ONLY: 1898cb49ec54SMark Johnston INP_WLOCK(inp); 18990ecd976eSBjoern A. Zeeb if (inp->inp_lport || 19000ecd976eSBjoern A. Zeeb !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { 1901cb49ec54SMark Johnston /* 1902cb49ec54SMark Johnston * The socket is already bound. 1903cb49ec54SMark Johnston */ 1904cb49ec54SMark Johnston INP_WUNLOCK(inp); 19050554093bSHajimu UMEMOTO error = EINVAL; 19060554093bSHajimu UMEMOTO break; 19070554093bSHajimu UMEMOTO } 1908cb49ec54SMark Johnston if (optval) { 1909cb49ec54SMark Johnston inp->inp_flags |= IN6P_IPV6_V6ONLY; 19100ecd976eSBjoern A. Zeeb inp->inp_vflag &= ~INP_IPV4; 1911cb49ec54SMark Johnston } else { 1912cb49ec54SMark Johnston inp->inp_flags &= ~IN6P_IPV6_V6ONLY; 19130ecd976eSBjoern A. Zeeb inp->inp_vflag |= INP_IPV4; 1914cb49ec54SMark Johnston } 1915cb49ec54SMark Johnston INP_WUNLOCK(inp); 191682cd038dSYoshinobu Inoue break; 1917f95d4633SHajimu UMEMOTO case IPV6_RECVTCLASS: 1918f95d4633SHajimu UMEMOTO /* cannot mix with RFC2292 XXX */ 191937d4fc1eSSean Bruno OPTSET2292_EXCLUSIVE(IN6P_TCLASS); 1920f95d4633SHajimu UMEMOTO break; 1921f95d4633SHajimu UMEMOTO case IPV6_AUTOFLOWLABEL: 1922f95d4633SHajimu UMEMOTO OPTSET(IN6P_AUTOFLOWLABEL); 1923f95d4633SHajimu UMEMOTO break; 1924f95d4633SHajimu UMEMOTO 1925dce33a45SErmal Luçi case IPV6_ORIGDSTADDR: 1926dce33a45SErmal Luçi OPTSET2(INP_ORIGDSTADDR, optval); 1927dce33a45SErmal Luçi break; 1928f44270e7SPawel Jakub Dawidek case IPV6_BINDANY: 1929f44270e7SPawel Jakub Dawidek OPTSET(INP_BINDANY); 1930f44270e7SPawel Jakub Dawidek break; 1931868aabb4SRichard Scheffenegger case IPV6_VLAN_PCP: 1932868aabb4SRichard Scheffenegger if ((optval >= -1) && (optval <= 1933868aabb4SRichard Scheffenegger (INP_2PCP_MASK >> INP_2PCP_SHIFT))) { 1934868aabb4SRichard Scheffenegger if (optval == -1) { 1935868aabb4SRichard Scheffenegger INP_WLOCK(inp); 1936868aabb4SRichard Scheffenegger inp->inp_flags2 &= 1937868aabb4SRichard Scheffenegger ~(INP_2PCP_SET | 1938868aabb4SRichard Scheffenegger INP_2PCP_MASK); 1939868aabb4SRichard Scheffenegger INP_WUNLOCK(inp); 1940868aabb4SRichard Scheffenegger } else { 1941868aabb4SRichard Scheffenegger INP_WLOCK(inp); 1942868aabb4SRichard Scheffenegger inp->inp_flags2 |= 1943868aabb4SRichard Scheffenegger INP_2PCP_SET; 1944868aabb4SRichard Scheffenegger inp->inp_flags2 &= 1945868aabb4SRichard Scheffenegger ~INP_2PCP_MASK; 1946868aabb4SRichard Scheffenegger inp->inp_flags2 |= 1947868aabb4SRichard Scheffenegger optval << 1948868aabb4SRichard Scheffenegger INP_2PCP_SHIFT; 1949868aabb4SRichard Scheffenegger INP_WUNLOCK(inp); 1950868aabb4SRichard Scheffenegger } 1951868aabb4SRichard Scheffenegger } else 1952868aabb4SRichard Scheffenegger error = EINVAL; 1953868aabb4SRichard Scheffenegger break; 195482cd038dSYoshinobu Inoue } 195533841545SHajimu UMEMOTO break; 195633841545SHajimu UMEMOTO 1957f95d4633SHajimu UMEMOTO case IPV6_TCLASS: 1958f95d4633SHajimu UMEMOTO case IPV6_DONTFRAG: 1959f95d4633SHajimu UMEMOTO case IPV6_USE_MIN_MTU: 1960f95d4633SHajimu UMEMOTO case IPV6_PREFER_TEMPADDR: 1961f95d4633SHajimu UMEMOTO if (optlen != sizeof(optval)) { 1962f95d4633SHajimu UMEMOTO error = EINVAL; 1963f95d4633SHajimu UMEMOTO break; 1964f95d4633SHajimu UMEMOTO } 1965f95d4633SHajimu UMEMOTO error = sooptcopyin(sopt, &optval, 1966f95d4633SHajimu UMEMOTO sizeof optval, sizeof optval); 1967f95d4633SHajimu UMEMOTO if (error) 1968f95d4633SHajimu UMEMOTO break; 1969f95d4633SHajimu UMEMOTO { 1970f95d4633SHajimu UMEMOTO struct ip6_pktopts **optp; 19710ecd976eSBjoern A. Zeeb INP_WLOCK(inp); 197253af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 19730ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 197456713d16SMatt Macy return (ECONNRESET); 197556713d16SMatt Macy } 19760ecd976eSBjoern A. Zeeb optp = &inp->in6p_outputopts; 1977f95d4633SHajimu UMEMOTO error = ip6_pcbopt(optname, 197879ba3952SBjoern A. Zeeb (u_char *)&optval, sizeof(optval), 197979ba3952SBjoern A. Zeeb optp, (td != NULL) ? td->td_ucred : 198079ba3952SBjoern A. Zeeb NULL, uproto); 19810ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 1982f95d4633SHajimu UMEMOTO break; 1983f95d4633SHajimu UMEMOTO } 1984f95d4633SHajimu UMEMOTO 1985f95d4633SHajimu UMEMOTO case IPV6_2292PKTINFO: 1986f95d4633SHajimu UMEMOTO case IPV6_2292HOPLIMIT: 1987f95d4633SHajimu UMEMOTO case IPV6_2292HOPOPTS: 1988f95d4633SHajimu UMEMOTO case IPV6_2292DSTOPTS: 1989f95d4633SHajimu UMEMOTO case IPV6_2292RTHDR: 199033841545SHajimu UMEMOTO /* RFC 2292 */ 199133841545SHajimu UMEMOTO if (optlen != sizeof(int)) { 199233841545SHajimu UMEMOTO error = EINVAL; 199333841545SHajimu UMEMOTO break; 199433841545SHajimu UMEMOTO } 199533841545SHajimu UMEMOTO error = sooptcopyin(sopt, &optval, 199633841545SHajimu UMEMOTO sizeof optval, sizeof optval); 199733841545SHajimu UMEMOTO if (error) 199833841545SHajimu UMEMOTO break; 199933841545SHajimu UMEMOTO switch (optname) { 2000f95d4633SHajimu UMEMOTO case IPV6_2292PKTINFO: 2001f95d4633SHajimu UMEMOTO OPTSET2292(IN6P_PKTINFO); 200233841545SHajimu UMEMOTO break; 2003f95d4633SHajimu UMEMOTO case IPV6_2292HOPLIMIT: 2004f95d4633SHajimu UMEMOTO OPTSET2292(IN6P_HOPLIMIT); 200533841545SHajimu UMEMOTO break; 2006f95d4633SHajimu UMEMOTO case IPV6_2292HOPOPTS: 200733841545SHajimu UMEMOTO /* 200833841545SHajimu UMEMOTO * Check super-user privilege. 200933841545SHajimu UMEMOTO * See comments for IPV6_RECVHOPOPTS. 201033841545SHajimu UMEMOTO */ 201179ba3952SBjoern A. Zeeb if (td != NULL) { 201279ba3952SBjoern A. Zeeb error = priv_check(td, 201379ba3952SBjoern A. Zeeb PRIV_NETINET_SETHDROPTS); 201479ba3952SBjoern A. Zeeb if (error) 201579ba3952SBjoern A. Zeeb return (error); 201679ba3952SBjoern A. Zeeb } 2017f95d4633SHajimu UMEMOTO OPTSET2292(IN6P_HOPOPTS); 201833841545SHajimu UMEMOTO break; 2019f95d4633SHajimu UMEMOTO case IPV6_2292DSTOPTS: 202079ba3952SBjoern A. Zeeb if (td != NULL) { 202179ba3952SBjoern A. Zeeb error = priv_check(td, 202279ba3952SBjoern A. Zeeb PRIV_NETINET_SETHDROPTS); 202379ba3952SBjoern A. Zeeb if (error) 202479ba3952SBjoern A. Zeeb return (error); 202579ba3952SBjoern A. Zeeb } 2026f95d4633SHajimu UMEMOTO OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */ 202733841545SHajimu UMEMOTO break; 2028f95d4633SHajimu UMEMOTO case IPV6_2292RTHDR: 2029f95d4633SHajimu UMEMOTO OPTSET2292(IN6P_RTHDR); 203033841545SHajimu UMEMOTO break; 203182cd038dSYoshinobu Inoue } 203282cd038dSYoshinobu Inoue break; 2033f95d4633SHajimu UMEMOTO case IPV6_PKTINFO: 2034f95d4633SHajimu UMEMOTO case IPV6_HOPOPTS: 2035f95d4633SHajimu UMEMOTO case IPV6_RTHDR: 2036f95d4633SHajimu UMEMOTO case IPV6_DSTOPTS: 2037f95d4633SHajimu UMEMOTO case IPV6_RTHDRDSTOPTS: 2038f95d4633SHajimu UMEMOTO case IPV6_NEXTHOP: 2039f95d4633SHajimu UMEMOTO { 204018b35df8SHajimu UMEMOTO /* new advanced API (RFC3542) */ 2041f95d4633SHajimu UMEMOTO u_char *optbuf; 2042e770771aSHajimu UMEMOTO u_char optbuf_storage[MCLBYTES]; 2043f95d4633SHajimu UMEMOTO int optlen; 2044f95d4633SHajimu UMEMOTO struct ip6_pktopts **optp; 2045f95d4633SHajimu UMEMOTO 204672bfa0bfSSean Bruno /* cannot mix with RFC2292 */ 204772bfa0bfSSean Bruno if (OPTBIT(IN6P_RFC2292)) { 204872bfa0bfSSean Bruno error = EINVAL; 204972bfa0bfSSean Bruno break; 205072bfa0bfSSean Bruno } 205172bfa0bfSSean Bruno 2052e770771aSHajimu UMEMOTO /* 2053e770771aSHajimu UMEMOTO * We only ensure valsize is not too large 2054e770771aSHajimu UMEMOTO * here. Further validation will be done 2055e770771aSHajimu UMEMOTO * later. 2056e770771aSHajimu UMEMOTO */ 2057e770771aSHajimu UMEMOTO error = sooptcopyin(sopt, optbuf_storage, 2058e770771aSHajimu UMEMOTO sizeof(optbuf_storage), 0); 2059a5d1aae3SHajimu UMEMOTO if (error) 2060a5d1aae3SHajimu UMEMOTO break; 2061f95d4633SHajimu UMEMOTO optlen = sopt->sopt_valsize; 2062e770771aSHajimu UMEMOTO optbuf = optbuf_storage; 20630ecd976eSBjoern A. Zeeb INP_WLOCK(inp); 206453af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 20650ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 206656713d16SMatt Macy return (ECONNRESET); 206756713d16SMatt Macy } 20680ecd976eSBjoern A. Zeeb optp = &inp->in6p_outputopts; 206979ba3952SBjoern A. Zeeb error = ip6_pcbopt(optname, optbuf, optlen, 207079ba3952SBjoern A. Zeeb optp, (td != NULL) ? td->td_ucred : NULL, 207179ba3952SBjoern A. Zeeb uproto); 20720ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 2073f95d4633SHajimu UMEMOTO break; 2074f95d4633SHajimu UMEMOTO } 207582cd038dSYoshinobu Inoue #undef OPTSET 207682cd038dSYoshinobu Inoue 207782cd038dSYoshinobu Inoue case IPV6_MULTICAST_IF: 207882cd038dSYoshinobu Inoue case IPV6_MULTICAST_HOPS: 207982cd038dSYoshinobu Inoue case IPV6_MULTICAST_LOOP: 208082cd038dSYoshinobu Inoue case IPV6_JOIN_GROUP: 208182cd038dSYoshinobu Inoue case IPV6_LEAVE_GROUP: 208233cde130SBruce M Simpson case IPV6_MSFILTER: 208333cde130SBruce M Simpson case MCAST_BLOCK_SOURCE: 208433cde130SBruce M Simpson case MCAST_UNBLOCK_SOURCE: 208533cde130SBruce M Simpson case MCAST_JOIN_GROUP: 208633cde130SBruce M Simpson case MCAST_LEAVE_GROUP: 208733cde130SBruce M Simpson case MCAST_JOIN_SOURCE_GROUP: 208833cde130SBruce M Simpson case MCAST_LEAVE_SOURCE_GROUP: 20890ecd976eSBjoern A. Zeeb error = ip6_setmoptions(inp, sopt); 209082cd038dSYoshinobu Inoue break; 209182cd038dSYoshinobu Inoue 209282cd038dSYoshinobu Inoue case IPV6_PORTRANGE: 2093686cdd19SJun-ichiro itojun Hagino error = sooptcopyin(sopt, &optval, 2094686cdd19SJun-ichiro itojun Hagino sizeof optval, sizeof optval); 209582cd038dSYoshinobu Inoue if (error) 209682cd038dSYoshinobu Inoue break; 209782cd038dSYoshinobu Inoue 20980ecd976eSBjoern A. Zeeb INP_WLOCK(inp); 209982cd038dSYoshinobu Inoue switch (optval) { 210082cd038dSYoshinobu Inoue case IPV6_PORTRANGE_DEFAULT: 21010ecd976eSBjoern A. Zeeb inp->inp_flags &= ~(INP_LOWPORT); 21020ecd976eSBjoern A. Zeeb inp->inp_flags &= ~(INP_HIGHPORT); 210382cd038dSYoshinobu Inoue break; 210482cd038dSYoshinobu Inoue 210582cd038dSYoshinobu Inoue case IPV6_PORTRANGE_HIGH: 21060ecd976eSBjoern A. Zeeb inp->inp_flags &= ~(INP_LOWPORT); 21070ecd976eSBjoern A. Zeeb inp->inp_flags |= INP_HIGHPORT; 210882cd038dSYoshinobu Inoue break; 210982cd038dSYoshinobu Inoue 211082cd038dSYoshinobu Inoue case IPV6_PORTRANGE_LOW: 21110ecd976eSBjoern A. Zeeb inp->inp_flags &= ~(INP_HIGHPORT); 21120ecd976eSBjoern A. Zeeb inp->inp_flags |= INP_LOWPORT; 211382cd038dSYoshinobu Inoue break; 211482cd038dSYoshinobu Inoue 211582cd038dSYoshinobu Inoue default: 211682cd038dSYoshinobu Inoue error = EINVAL; 211782cd038dSYoshinobu Inoue break; 211882cd038dSYoshinobu Inoue } 21190ecd976eSBjoern A. Zeeb INP_WUNLOCK(inp); 212082cd038dSYoshinobu Inoue break; 212182cd038dSYoshinobu Inoue 2122fcf59617SAndrey V. Elsukov #if defined(IPSEC) || defined(IPSEC_SUPPORT) 212382cd038dSYoshinobu Inoue case IPV6_IPSEC_POLICY: 2124fcf59617SAndrey V. Elsukov if (IPSEC_ENABLED(ipv6)) { 21250ecd976eSBjoern A. Zeeb error = IPSEC_PCBCTL(ipv6, inp, sopt); 212682cd038dSYoshinobu Inoue break; 2127c26fe973SBjoern A. Zeeb } 2128fcf59617SAndrey V. Elsukov /* FALLTHROUGH */ 2129b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */ 213082cd038dSYoshinobu Inoue 213182cd038dSYoshinobu Inoue default: 213282cd038dSYoshinobu Inoue error = ENOPROTOOPT; 213382cd038dSYoshinobu Inoue break; 213482cd038dSYoshinobu Inoue } 213582cd038dSYoshinobu Inoue break; 213682cd038dSYoshinobu Inoue 213782cd038dSYoshinobu Inoue case SOPT_GET: 213882cd038dSYoshinobu Inoue switch (optname) { 2139f95d4633SHajimu UMEMOTO case IPV6_2292PKTOPTIONS: 2140f95d4633SHajimu UMEMOTO #ifdef IPV6_PKTOPTIONS 214182cd038dSYoshinobu Inoue case IPV6_PKTOPTIONS: 2142f95d4633SHajimu UMEMOTO #endif 2143f95d4633SHajimu UMEMOTO /* 2144f95d4633SHajimu UMEMOTO * RFC3542 (effectively) deprecated the 2145f95d4633SHajimu UMEMOTO * semantics of the 2292-style pktoptions. 2146f95d4633SHajimu UMEMOTO * Since it was not reliable in nature (i.e., 2147f95d4633SHajimu UMEMOTO * applications had to expect the lack of some 2148f95d4633SHajimu UMEMOTO * information after all), it would make sense 2149f95d4633SHajimu UMEMOTO * to simplify this part by always returning 2150f95d4633SHajimu UMEMOTO * empty data. 2151f95d4633SHajimu UMEMOTO */ 215282cd038dSYoshinobu Inoue sopt->sopt_valsize = 0; 215382cd038dSYoshinobu Inoue break; 215482cd038dSYoshinobu Inoue 2155f95d4633SHajimu UMEMOTO case IPV6_RECVHOPOPTS: 2156f95d4633SHajimu UMEMOTO case IPV6_RECVDSTOPTS: 2157f95d4633SHajimu UMEMOTO case IPV6_RECVRTHDRDSTOPTS: 215882cd038dSYoshinobu Inoue case IPV6_UNICAST_HOPS: 2159f95d4633SHajimu UMEMOTO case IPV6_RECVPKTINFO: 2160f95d4633SHajimu UMEMOTO case IPV6_RECVHOPLIMIT: 2161f95d4633SHajimu UMEMOTO case IPV6_RECVRTHDR: 2162f95d4633SHajimu UMEMOTO case IPV6_RECVPATHMTU: 216333841545SHajimu UMEMOTO 216433841545SHajimu UMEMOTO case IPV6_V6ONLY: 2165fa310a7eSYoshinobu Inoue case IPV6_PORTRANGE: 2166f95d4633SHajimu UMEMOTO case IPV6_RECVTCLASS: 2167f95d4633SHajimu UMEMOTO case IPV6_AUTOFLOWLABEL: 21685f6bf451SAttilio Rao case IPV6_BINDANY: 2169c7c0d948SAdrian Chadd case IPV6_FLOWID: 2170c7c0d948SAdrian Chadd case IPV6_FLOWTYPE: 217168bb8d62SAdrian Chadd case IPV6_RECVFLOWID: 2172c7c0d948SAdrian Chadd #ifdef RSS 2173c7c0d948SAdrian Chadd case IPV6_RSSBUCKETID: 217468bb8d62SAdrian Chadd case IPV6_RECVRSSBUCKETID: 2175c7c0d948SAdrian Chadd #endif 2176868aabb4SRichard Scheffenegger case IPV6_VLAN_PCP: 217782cd038dSYoshinobu Inoue switch (optname) { 2178f95d4633SHajimu UMEMOTO case IPV6_RECVHOPOPTS: 2179f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_HOPOPTS); 2180f95d4633SHajimu UMEMOTO break; 2181f95d4633SHajimu UMEMOTO 2182f95d4633SHajimu UMEMOTO case IPV6_RECVDSTOPTS: 2183f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_DSTOPTS); 2184f95d4633SHajimu UMEMOTO break; 2185f95d4633SHajimu UMEMOTO 2186f95d4633SHajimu UMEMOTO case IPV6_RECVRTHDRDSTOPTS: 2187f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_RTHDRDSTOPTS); 2188f95d4633SHajimu UMEMOTO break; 2189f95d4633SHajimu UMEMOTO 219082cd038dSYoshinobu Inoue case IPV6_UNICAST_HOPS: 21910ecd976eSBjoern A. Zeeb optval = inp->in6p_hops; 219282cd038dSYoshinobu Inoue break; 219382cd038dSYoshinobu Inoue 2194f95d4633SHajimu UMEMOTO case IPV6_RECVPKTINFO: 2195f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_PKTINFO); 2196f95d4633SHajimu UMEMOTO break; 2197f95d4633SHajimu UMEMOTO 2198f95d4633SHajimu UMEMOTO case IPV6_RECVHOPLIMIT: 2199f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_HOPLIMIT); 2200f95d4633SHajimu UMEMOTO break; 2201f95d4633SHajimu UMEMOTO 2202f95d4633SHajimu UMEMOTO case IPV6_RECVRTHDR: 2203f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_RTHDR); 2204f95d4633SHajimu UMEMOTO break; 2205f95d4633SHajimu UMEMOTO 2206f95d4633SHajimu UMEMOTO case IPV6_RECVPATHMTU: 2207f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_MTU); 220882cd038dSYoshinobu Inoue break; 220982cd038dSYoshinobu Inoue 221033841545SHajimu UMEMOTO case IPV6_V6ONLY: 2211854d3b19SHajimu UMEMOTO optval = OPTBIT(IN6P_IPV6_V6ONLY); 221282cd038dSYoshinobu Inoue break; 221382cd038dSYoshinobu Inoue 221482cd038dSYoshinobu Inoue case IPV6_PORTRANGE: 221582cd038dSYoshinobu Inoue { 221682cd038dSYoshinobu Inoue int flags; 22170ecd976eSBjoern A. Zeeb flags = inp->inp_flags; 221897590249SBjoern A. Zeeb if (flags & INP_HIGHPORT) 221982cd038dSYoshinobu Inoue optval = IPV6_PORTRANGE_HIGH; 222097590249SBjoern A. Zeeb else if (flags & INP_LOWPORT) 222182cd038dSYoshinobu Inoue optval = IPV6_PORTRANGE_LOW; 222282cd038dSYoshinobu Inoue else 222382cd038dSYoshinobu Inoue optval = 0; 222482cd038dSYoshinobu Inoue break; 222582cd038dSYoshinobu Inoue } 2226f95d4633SHajimu UMEMOTO case IPV6_RECVTCLASS: 2227f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_TCLASS); 2228f95d4633SHajimu UMEMOTO break; 2229f95d4633SHajimu UMEMOTO 2230f95d4633SHajimu UMEMOTO case IPV6_AUTOFLOWLABEL: 2231f95d4633SHajimu UMEMOTO optval = OPTBIT(IN6P_AUTOFLOWLABEL); 2232f95d4633SHajimu UMEMOTO break; 2233f44270e7SPawel Jakub Dawidek 2234dce33a45SErmal Luçi case IPV6_ORIGDSTADDR: 2235dce33a45SErmal Luçi optval = OPTBIT2(INP_ORIGDSTADDR); 2236dce33a45SErmal Luçi break; 2237dce33a45SErmal Luçi 2238f44270e7SPawel Jakub Dawidek case IPV6_BINDANY: 2239f44270e7SPawel Jakub Dawidek optval = OPTBIT(INP_BINDANY); 2240f44270e7SPawel Jakub Dawidek break; 2241c7c0d948SAdrian Chadd 2242c7c0d948SAdrian Chadd case IPV6_FLOWID: 22430ecd976eSBjoern A. Zeeb optval = inp->inp_flowid; 2244c7c0d948SAdrian Chadd break; 2245c7c0d948SAdrian Chadd 2246c7c0d948SAdrian Chadd case IPV6_FLOWTYPE: 22470ecd976eSBjoern A. Zeeb optval = inp->inp_flowtype; 2248c7c0d948SAdrian Chadd break; 224968bb8d62SAdrian Chadd 225068bb8d62SAdrian Chadd case IPV6_RECVFLOWID: 225168bb8d62SAdrian Chadd optval = OPTBIT2(INP_RECVFLOWID); 225268bb8d62SAdrian Chadd break; 2253c7c0d948SAdrian Chadd #ifdef RSS 2254c7c0d948SAdrian Chadd case IPV6_RSSBUCKETID: 2255c7c0d948SAdrian Chadd retval = 22560ecd976eSBjoern A. Zeeb rss_hash2bucket(inp->inp_flowid, 22570ecd976eSBjoern A. Zeeb inp->inp_flowtype, 2258c7c0d948SAdrian Chadd &rss_bucket); 2259c7c0d948SAdrian Chadd if (retval == 0) 2260c7c0d948SAdrian Chadd optval = rss_bucket; 2261c7c0d948SAdrian Chadd else 2262c7c0d948SAdrian Chadd error = EINVAL; 2263c7c0d948SAdrian Chadd break; 226468bb8d62SAdrian Chadd 226568bb8d62SAdrian Chadd case IPV6_RECVRSSBUCKETID: 226668bb8d62SAdrian Chadd optval = OPTBIT2(INP_RECVRSSBUCKETID); 226768bb8d62SAdrian Chadd break; 2268c7c0d948SAdrian Chadd #endif 2269c7c0d948SAdrian Chadd 2270868aabb4SRichard Scheffenegger 2271868aabb4SRichard Scheffenegger case IPV6_VLAN_PCP: 2272868aabb4SRichard Scheffenegger if (OPTBIT2(INP_2PCP_SET)) { 2273868aabb4SRichard Scheffenegger optval = (inp->inp_flags2 & 2274868aabb4SRichard Scheffenegger INP_2PCP_MASK) >> 2275868aabb4SRichard Scheffenegger INP_2PCP_SHIFT; 2276868aabb4SRichard Scheffenegger } else { 2277868aabb4SRichard Scheffenegger optval = -1; 227882cd038dSYoshinobu Inoue } 2279868aabb4SRichard Scheffenegger break; 2280868aabb4SRichard Scheffenegger } 2281868aabb4SRichard Scheffenegger 2282f95d4633SHajimu UMEMOTO if (error) 2283f95d4633SHajimu UMEMOTO break; 228482cd038dSYoshinobu Inoue error = sooptcopyout(sopt, &optval, 228582cd038dSYoshinobu Inoue sizeof optval); 228682cd038dSYoshinobu Inoue break; 228782cd038dSYoshinobu Inoue 2288f95d4633SHajimu UMEMOTO case IPV6_PATHMTU: 2289f95d4633SHajimu UMEMOTO { 2290f95d4633SHajimu UMEMOTO u_long pmtu = 0; 2291f95d4633SHajimu UMEMOTO struct ip6_mtuinfo mtuinfo; 22925cbeca44SSean Bruno struct in6_addr addr; 2293f95d4633SHajimu UMEMOTO 2294f95d4633SHajimu UMEMOTO if (!(so->so_state & SS_ISCONNECTED)) 2295f95d4633SHajimu UMEMOTO return (ENOTCONN); 2296f95d4633SHajimu UMEMOTO /* 2297f95d4633SHajimu UMEMOTO * XXX: we dot not consider the case of source 2298f95d4633SHajimu UMEMOTO * routing, or optional information to specify 2299f95d4633SHajimu UMEMOTO * the outgoing interface. 23000ecd976eSBjoern A. Zeeb * Copy faddr out of inp to avoid holding lock 23015cbeca44SSean Bruno * on inp during route lookup. 2302f95d4633SHajimu UMEMOTO */ 23030ecd976eSBjoern A. Zeeb INP_RLOCK(inp); 23040ecd976eSBjoern A. Zeeb bcopy(&inp->in6p_faddr, &addr, sizeof(addr)); 23050ecd976eSBjoern A. Zeeb INP_RUNLOCK(inp); 23060d4df029SAlexander V. Chernikov error = ip6_getpmtu_ctl(so->so_fibnum, 23075cbeca44SSean Bruno &addr, &pmtu); 2308f95d4633SHajimu UMEMOTO if (error) 2309f95d4633SHajimu UMEMOTO break; 2310f95d4633SHajimu UMEMOTO if (pmtu > IPV6_MAXPACKET) 2311f95d4633SHajimu UMEMOTO pmtu = IPV6_MAXPACKET; 2312f95d4633SHajimu UMEMOTO 2313f95d4633SHajimu UMEMOTO bzero(&mtuinfo, sizeof(mtuinfo)); 2314f95d4633SHajimu UMEMOTO mtuinfo.ip6m_mtu = (u_int32_t)pmtu; 2315f95d4633SHajimu UMEMOTO optdata = (void *)&mtuinfo; 2316f95d4633SHajimu UMEMOTO optdatalen = sizeof(mtuinfo); 2317f95d4633SHajimu UMEMOTO error = sooptcopyout(sopt, optdata, 2318f95d4633SHajimu UMEMOTO optdatalen); 2319f95d4633SHajimu UMEMOTO break; 2320f95d4633SHajimu UMEMOTO } 2321f95d4633SHajimu UMEMOTO 2322f95d4633SHajimu UMEMOTO case IPV6_2292PKTINFO: 2323f95d4633SHajimu UMEMOTO case IPV6_2292HOPLIMIT: 2324f95d4633SHajimu UMEMOTO case IPV6_2292HOPOPTS: 2325f95d4633SHajimu UMEMOTO case IPV6_2292RTHDR: 2326f95d4633SHajimu UMEMOTO case IPV6_2292DSTOPTS: 232733841545SHajimu UMEMOTO switch (optname) { 2328f95d4633SHajimu UMEMOTO case IPV6_2292PKTINFO: 232933841545SHajimu UMEMOTO optval = OPTBIT(IN6P_PKTINFO); 233033841545SHajimu UMEMOTO break; 2331f95d4633SHajimu UMEMOTO case IPV6_2292HOPLIMIT: 233233841545SHajimu UMEMOTO optval = OPTBIT(IN6P_HOPLIMIT); 233333841545SHajimu UMEMOTO break; 2334f95d4633SHajimu UMEMOTO case IPV6_2292HOPOPTS: 233533841545SHajimu UMEMOTO optval = OPTBIT(IN6P_HOPOPTS); 233633841545SHajimu UMEMOTO break; 2337f95d4633SHajimu UMEMOTO case IPV6_2292RTHDR: 233833841545SHajimu UMEMOTO optval = OPTBIT(IN6P_RTHDR); 233933841545SHajimu UMEMOTO break; 2340f95d4633SHajimu UMEMOTO case IPV6_2292DSTOPTS: 234133841545SHajimu UMEMOTO optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); 234233841545SHajimu UMEMOTO break; 234333841545SHajimu UMEMOTO } 234433841545SHajimu UMEMOTO error = sooptcopyout(sopt, &optval, 234533841545SHajimu UMEMOTO sizeof optval); 234633841545SHajimu UMEMOTO break; 2347f95d4633SHajimu UMEMOTO case IPV6_PKTINFO: 2348f95d4633SHajimu UMEMOTO case IPV6_HOPOPTS: 2349f95d4633SHajimu UMEMOTO case IPV6_RTHDR: 2350f95d4633SHajimu UMEMOTO case IPV6_DSTOPTS: 2351f95d4633SHajimu UMEMOTO case IPV6_RTHDRDSTOPTS: 2352f95d4633SHajimu UMEMOTO case IPV6_NEXTHOP: 2353f95d4633SHajimu UMEMOTO case IPV6_TCLASS: 2354f95d4633SHajimu UMEMOTO case IPV6_DONTFRAG: 2355f95d4633SHajimu UMEMOTO case IPV6_USE_MIN_MTU: 2356f95d4633SHajimu UMEMOTO case IPV6_PREFER_TEMPADDR: 23570ecd976eSBjoern A. Zeeb error = ip6_getpcbopt(inp, optname, sopt); 2358f95d4633SHajimu UMEMOTO break; 235933841545SHajimu UMEMOTO 236082cd038dSYoshinobu Inoue case IPV6_MULTICAST_IF: 236182cd038dSYoshinobu Inoue case IPV6_MULTICAST_HOPS: 236282cd038dSYoshinobu Inoue case IPV6_MULTICAST_LOOP: 236333cde130SBruce M Simpson case IPV6_MSFILTER: 23640ecd976eSBjoern A. Zeeb error = ip6_getmoptions(inp, sopt); 236582cd038dSYoshinobu Inoue break; 236682cd038dSYoshinobu Inoue 2367fcf59617SAndrey V. Elsukov #if defined(IPSEC) || defined(IPSEC_SUPPORT) 236882cd038dSYoshinobu Inoue case IPV6_IPSEC_POLICY: 2369fcf59617SAndrey V. Elsukov if (IPSEC_ENABLED(ipv6)) { 23700ecd976eSBjoern A. Zeeb error = IPSEC_PCBCTL(ipv6, inp, sopt); 237182cd038dSYoshinobu Inoue break; 237282cd038dSYoshinobu Inoue } 2373fcf59617SAndrey V. Elsukov /* FALLTHROUGH */ 2374b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */ 237582cd038dSYoshinobu Inoue default: 237682cd038dSYoshinobu Inoue error = ENOPROTOOPT; 237782cd038dSYoshinobu Inoue break; 237882cd038dSYoshinobu Inoue } 237982cd038dSYoshinobu Inoue break; 238082cd038dSYoshinobu Inoue } 238182cd038dSYoshinobu Inoue } 238282cd038dSYoshinobu Inoue return (error); 238382cd038dSYoshinobu Inoue } 238482cd038dSYoshinobu Inoue 238502b9a206SHajimu UMEMOTO int 23861272577eSXin LI ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt) 238702b9a206SHajimu UMEMOTO { 238802b9a206SHajimu UMEMOTO int error = 0, optval, optlen; 238902b9a206SHajimu UMEMOTO const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum); 23900ecd976eSBjoern A. Zeeb struct inpcb *inp = sotoinpcb(so); 239102b9a206SHajimu UMEMOTO int level, op, optname; 239202b9a206SHajimu UMEMOTO 239302b9a206SHajimu UMEMOTO level = sopt->sopt_level; 239402b9a206SHajimu UMEMOTO op = sopt->sopt_dir; 239502b9a206SHajimu UMEMOTO optname = sopt->sopt_name; 239602b9a206SHajimu UMEMOTO optlen = sopt->sopt_valsize; 239702b9a206SHajimu UMEMOTO 239802b9a206SHajimu UMEMOTO if (level != IPPROTO_IPV6) { 239902b9a206SHajimu UMEMOTO return (EINVAL); 240002b9a206SHajimu UMEMOTO } 240102b9a206SHajimu UMEMOTO 240202b9a206SHajimu UMEMOTO switch (optname) { 240302b9a206SHajimu UMEMOTO case IPV6_CHECKSUM: 240402b9a206SHajimu UMEMOTO /* 240502b9a206SHajimu UMEMOTO * For ICMPv6 sockets, no modification allowed for checksum 240602b9a206SHajimu UMEMOTO * offset, permit "no change" values to help existing apps. 240702b9a206SHajimu UMEMOTO * 240818b35df8SHajimu UMEMOTO * RFC3542 says: "An attempt to set IPV6_CHECKSUM 240902b9a206SHajimu UMEMOTO * for an ICMPv6 socket will fail." 241018b35df8SHajimu UMEMOTO * The current behavior does not meet RFC3542. 241102b9a206SHajimu UMEMOTO */ 241202b9a206SHajimu UMEMOTO switch (op) { 241302b9a206SHajimu UMEMOTO case SOPT_SET: 241402b9a206SHajimu UMEMOTO if (optlen != sizeof(int)) { 241502b9a206SHajimu UMEMOTO error = EINVAL; 241602b9a206SHajimu UMEMOTO break; 241702b9a206SHajimu UMEMOTO } 241802b9a206SHajimu UMEMOTO error = sooptcopyin(sopt, &optval, sizeof(optval), 241902b9a206SHajimu UMEMOTO sizeof(optval)); 242002b9a206SHajimu UMEMOTO if (error) 242102b9a206SHajimu UMEMOTO break; 24222f041b74SMichael Tuexen if (optval < -1 || (optval % 2) != 0) { 24232f041b74SMichael Tuexen /* 24242f041b74SMichael Tuexen * The API assumes non-negative even offset 24252f041b74SMichael Tuexen * values or -1 as a special value. 24262f041b74SMichael Tuexen */ 242702b9a206SHajimu UMEMOTO error = EINVAL; 242874ed2e8aSGleb Smirnoff } else if (inp->inp_ip_p == IPPROTO_ICMPV6) { 242902b9a206SHajimu UMEMOTO if (optval != icmp6off) 243002b9a206SHajimu UMEMOTO error = EINVAL; 243102b9a206SHajimu UMEMOTO } else 24320ecd976eSBjoern A. Zeeb inp->in6p_cksum = optval; 243302b9a206SHajimu UMEMOTO break; 243402b9a206SHajimu UMEMOTO 243502b9a206SHajimu UMEMOTO case SOPT_GET: 243674ed2e8aSGleb Smirnoff if (inp->inp_ip_p == IPPROTO_ICMPV6) 243702b9a206SHajimu UMEMOTO optval = icmp6off; 243802b9a206SHajimu UMEMOTO else 24390ecd976eSBjoern A. Zeeb optval = inp->in6p_cksum; 244002b9a206SHajimu UMEMOTO 244102b9a206SHajimu UMEMOTO error = sooptcopyout(sopt, &optval, sizeof(optval)); 244202b9a206SHajimu UMEMOTO break; 244302b9a206SHajimu UMEMOTO 244402b9a206SHajimu UMEMOTO default: 244502b9a206SHajimu UMEMOTO error = EINVAL; 244602b9a206SHajimu UMEMOTO break; 244702b9a206SHajimu UMEMOTO } 244802b9a206SHajimu UMEMOTO break; 244902b9a206SHajimu UMEMOTO 245002b9a206SHajimu UMEMOTO default: 245102b9a206SHajimu UMEMOTO error = ENOPROTOOPT; 245202b9a206SHajimu UMEMOTO break; 245302b9a206SHajimu UMEMOTO } 245402b9a206SHajimu UMEMOTO 245502b9a206SHajimu UMEMOTO return (error); 245602b9a206SHajimu UMEMOTO } 245702b9a206SHajimu UMEMOTO 245882cd038dSYoshinobu Inoue /* 245933841545SHajimu UMEMOTO * Set up IP6 options in pcb for insertion in output packets or 246033841545SHajimu UMEMOTO * specifying behavior of outgoing packets. 246182cd038dSYoshinobu Inoue */ 246282cd038dSYoshinobu Inoue static int 24631272577eSXin LI ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, 24641272577eSXin LI struct socket *so, struct sockopt *sopt) 246582cd038dSYoshinobu Inoue { 246633841545SHajimu UMEMOTO struct ip6_pktopts *opt = *pktopt; 246782cd038dSYoshinobu Inoue int error = 0; 2468b40ce416SJulian Elischer struct thread *td = sopt->sopt_td; 24692290dfb4SRyan Stone struct epoch_tracker et; 247082cd038dSYoshinobu Inoue 247182cd038dSYoshinobu Inoue /* turn off any old options. */ 247282cd038dSYoshinobu Inoue if (opt) { 247333841545SHajimu UMEMOTO #ifdef DIAGNOSTIC 247433841545SHajimu UMEMOTO if (opt->ip6po_pktinfo || opt->ip6po_nexthop || 247533841545SHajimu UMEMOTO opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 || 247633841545SHajimu UMEMOTO opt->ip6po_rhinfo.ip6po_rhi_rthdr) 247733841545SHajimu UMEMOTO printf("ip6_pcbopts: all specified options are cleared.\n"); 247833841545SHajimu UMEMOTO #endif 2479f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, -1); 2480e02582d1SMark Johnston } else { 2481e02582d1SMark Johnston opt = malloc(sizeof(*opt), M_IP6OPT, M_NOWAIT); 2482e02582d1SMark Johnston if (opt == NULL) 2483e02582d1SMark Johnston return (ENOMEM); 2484e02582d1SMark Johnston } 248533841545SHajimu UMEMOTO *pktopt = NULL; 248682cd038dSYoshinobu Inoue 248782cd038dSYoshinobu Inoue if (!m || m->m_len == 0) { 248882cd038dSYoshinobu Inoue /* 248935f6695bSHajimu UMEMOTO * Only turning off any previous options, regardless of 249035f6695bSHajimu UMEMOTO * whether the opt is just created or given. 249182cd038dSYoshinobu Inoue */ 249282cd038dSYoshinobu Inoue free(opt, M_IP6OPT); 249382cd038dSYoshinobu Inoue return (0); 249482cd038dSYoshinobu Inoue } 249582cd038dSYoshinobu Inoue 249682cd038dSYoshinobu Inoue /* set options specified by user. */ 24972290dfb4SRyan Stone NET_EPOCH_ENTER(et); 249879ba3952SBjoern A. Zeeb if ((error = ip6_setpktopts(m, opt, NULL, (td != NULL) ? 249979ba3952SBjoern A. Zeeb td->td_ucred : NULL, so->so_proto->pr_protocol)) != 0) { 2500f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, -1); /* XXX: discard all options */ 250135f6695bSHajimu UMEMOTO free(opt, M_IP6OPT); 25022290dfb4SRyan Stone NET_EPOCH_EXIT(et); 250382cd038dSYoshinobu Inoue return (error); 250482cd038dSYoshinobu Inoue } 25052290dfb4SRyan Stone NET_EPOCH_EXIT(et); 250682cd038dSYoshinobu Inoue *pktopt = opt; 250782cd038dSYoshinobu Inoue return (0); 250882cd038dSYoshinobu Inoue } 250982cd038dSYoshinobu Inoue 251082cd038dSYoshinobu Inoue /* 251133841545SHajimu UMEMOTO * initialize ip6_pktopts. beware that there are non-zero default values in 251233841545SHajimu UMEMOTO * the struct. 251333841545SHajimu UMEMOTO */ 251433841545SHajimu UMEMOTO void 25151272577eSXin LI ip6_initpktopts(struct ip6_pktopts *opt) 251633841545SHajimu UMEMOTO { 251733841545SHajimu UMEMOTO 251833841545SHajimu UMEMOTO bzero(opt, sizeof(*opt)); 251933841545SHajimu UMEMOTO opt->ip6po_hlim = -1; /* -1 means default hop limit */ 2520f95d4633SHajimu UMEMOTO opt->ip6po_tclass = -1; /* -1 means default traffic class */ 2521f95d4633SHajimu UMEMOTO opt->ip6po_minmtu = IP6PO_MINMTU_MCASTONLY; 2522f95d4633SHajimu UMEMOTO opt->ip6po_prefer_tempaddr = IP6PO_TEMPADDR_SYSTEM; 2523f95d4633SHajimu UMEMOTO } 2524f95d4633SHajimu UMEMOTO 2525f95d4633SHajimu UMEMOTO static int 25261272577eSXin LI ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt, 252779ba3952SBjoern A. Zeeb struct ucred *cred, int uproto) 2528f95d4633SHajimu UMEMOTO { 25299f5432d5SKristof Provost struct epoch_tracker et; 2530f95d4633SHajimu UMEMOTO struct ip6_pktopts *opt; 25319f5432d5SKristof Provost int ret; 2532f95d4633SHajimu UMEMOTO 2533f95d4633SHajimu UMEMOTO if (*pktopt == NULL) { 2534f95d4633SHajimu UMEMOTO *pktopt = malloc(sizeof(struct ip6_pktopts), M_IP6OPT, 253556713d16SMatt Macy M_NOWAIT); 253656713d16SMatt Macy if (*pktopt == NULL) 253756713d16SMatt Macy return (ENOBUFS); 2538d5e3406dSHajimu UMEMOTO ip6_initpktopts(*pktopt); 2539f95d4633SHajimu UMEMOTO } 2540f95d4633SHajimu UMEMOTO opt = *pktopt; 2541f95d4633SHajimu UMEMOTO 25429f5432d5SKristof Provost NET_EPOCH_ENTER(et); 25439f5432d5SKristof Provost ret = ip6_setpktopt(optname, buf, len, opt, cred, 1, 0, uproto); 25449f5432d5SKristof Provost NET_EPOCH_EXIT(et); 25459f5432d5SKristof Provost 25469f5432d5SKristof Provost return (ret); 2547f95d4633SHajimu UMEMOTO } 2548f95d4633SHajimu UMEMOTO 254906b479a6SSean Bruno #define GET_PKTOPT_VAR(field, lenexpr) do { \ 255006b479a6SSean Bruno if (pktopt && pktopt->field) { \ 25510ecd976eSBjoern A. Zeeb INP_RUNLOCK(inp); \ 255206b479a6SSean Bruno optdata = malloc(sopt->sopt_valsize, M_TEMP, M_WAITOK); \ 255306b479a6SSean Bruno malloc_optdata = true; \ 25540ecd976eSBjoern A. Zeeb INP_RLOCK(inp); \ 255553af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { \ 25560ecd976eSBjoern A. Zeeb INP_RUNLOCK(inp); \ 255706b479a6SSean Bruno free(optdata, M_TEMP); \ 255806b479a6SSean Bruno return (ECONNRESET); \ 255906b479a6SSean Bruno } \ 25600ecd976eSBjoern A. Zeeb pktopt = inp->in6p_outputopts; \ 256106b479a6SSean Bruno if (pktopt && pktopt->field) { \ 256206b479a6SSean Bruno optdatalen = min(lenexpr, sopt->sopt_valsize); \ 2563a8d54fc9SMichael Tuexen bcopy(pktopt->field, optdata, optdatalen); \ 256406b479a6SSean Bruno } else { \ 256506b479a6SSean Bruno free(optdata, M_TEMP); \ 256606b479a6SSean Bruno optdata = NULL; \ 256706b479a6SSean Bruno malloc_optdata = false; \ 256806b479a6SSean Bruno } \ 256906b479a6SSean Bruno } \ 257006b479a6SSean Bruno } while(0) 257106b479a6SSean Bruno 257206b479a6SSean Bruno #define GET_PKTOPT_EXT_HDR(field) GET_PKTOPT_VAR(field, \ 257306b479a6SSean Bruno (((struct ip6_ext *)pktopt->field)->ip6e_len + 1) << 3) 257406b479a6SSean Bruno 257506b479a6SSean Bruno #define GET_PKTOPT_SOCKADDR(field) GET_PKTOPT_VAR(field, \ 257606b479a6SSean Bruno pktopt->field->sa_len) 257706b479a6SSean Bruno 2578f95d4633SHajimu UMEMOTO static int 25790ecd976eSBjoern A. Zeeb ip6_getpcbopt(struct inpcb *inp, int optname, struct sockopt *sopt) 2580f95d4633SHajimu UMEMOTO { 2581f95d4633SHajimu UMEMOTO void *optdata = NULL; 258206b479a6SSean Bruno bool malloc_optdata = false; 2583f95d4633SHajimu UMEMOTO int optdatalen = 0; 2584f95d4633SHajimu UMEMOTO int error = 0; 2585f95d4633SHajimu UMEMOTO struct in6_pktinfo null_pktinfo; 2586f95d4633SHajimu UMEMOTO int deftclass = 0, on; 2587f95d4633SHajimu UMEMOTO int defminmtu = IP6PO_MINMTU_MCASTONLY; 2588f95d4633SHajimu UMEMOTO int defpreftemp = IP6PO_TEMPADDR_SYSTEM; 258906b479a6SSean Bruno struct ip6_pktopts *pktopt; 259006b479a6SSean Bruno 25910ecd976eSBjoern A. Zeeb INP_RLOCK(inp); 25920ecd976eSBjoern A. Zeeb pktopt = inp->in6p_outputopts; 2593f95d4633SHajimu UMEMOTO 2594f95d4633SHajimu UMEMOTO switch (optname) { 2595f95d4633SHajimu UMEMOTO case IPV6_PKTINFO: 2596cb207f93SAndrey V. Elsukov optdata = (void *)&null_pktinfo; 2597cb207f93SAndrey V. Elsukov if (pktopt && pktopt->ip6po_pktinfo) { 2598cb207f93SAndrey V. Elsukov bcopy(pktopt->ip6po_pktinfo, &null_pktinfo, 2599cb207f93SAndrey V. Elsukov sizeof(null_pktinfo)); 2600cb207f93SAndrey V. Elsukov in6_clearscope(&null_pktinfo.ipi6_addr); 2601cb207f93SAndrey V. Elsukov } else { 2602f95d4633SHajimu UMEMOTO /* XXX: we don't have to do this every time... */ 2603f95d4633SHajimu UMEMOTO bzero(&null_pktinfo, sizeof(null_pktinfo)); 2604f95d4633SHajimu UMEMOTO } 2605f95d4633SHajimu UMEMOTO optdatalen = sizeof(struct in6_pktinfo); 2606f95d4633SHajimu UMEMOTO break; 2607f95d4633SHajimu UMEMOTO case IPV6_TCLASS: 2608f95d4633SHajimu UMEMOTO if (pktopt && pktopt->ip6po_tclass >= 0) 260906b479a6SSean Bruno deftclass = pktopt->ip6po_tclass; 2610f95d4633SHajimu UMEMOTO optdata = (void *)&deftclass; 2611f95d4633SHajimu UMEMOTO optdatalen = sizeof(int); 2612f95d4633SHajimu UMEMOTO break; 2613f95d4633SHajimu UMEMOTO case IPV6_HOPOPTS: 261406b479a6SSean Bruno GET_PKTOPT_EXT_HDR(ip6po_hbh); 2615f95d4633SHajimu UMEMOTO break; 2616f95d4633SHajimu UMEMOTO case IPV6_RTHDR: 261706b479a6SSean Bruno GET_PKTOPT_EXT_HDR(ip6po_rthdr); 2618f95d4633SHajimu UMEMOTO break; 2619f95d4633SHajimu UMEMOTO case IPV6_RTHDRDSTOPTS: 262006b479a6SSean Bruno GET_PKTOPT_EXT_HDR(ip6po_dest1); 2621f95d4633SHajimu UMEMOTO break; 2622f95d4633SHajimu UMEMOTO case IPV6_DSTOPTS: 262306b479a6SSean Bruno GET_PKTOPT_EXT_HDR(ip6po_dest2); 2624f95d4633SHajimu UMEMOTO break; 2625f95d4633SHajimu UMEMOTO case IPV6_NEXTHOP: 262606b479a6SSean Bruno GET_PKTOPT_SOCKADDR(ip6po_nexthop); 2627f95d4633SHajimu UMEMOTO break; 2628f95d4633SHajimu UMEMOTO case IPV6_USE_MIN_MTU: 2629f95d4633SHajimu UMEMOTO if (pktopt) 263006b479a6SSean Bruno defminmtu = pktopt->ip6po_minmtu; 2631f95d4633SHajimu UMEMOTO optdata = (void *)&defminmtu; 2632f95d4633SHajimu UMEMOTO optdatalen = sizeof(int); 2633f95d4633SHajimu UMEMOTO break; 2634f95d4633SHajimu UMEMOTO case IPV6_DONTFRAG: 2635f95d4633SHajimu UMEMOTO if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG)) 2636f95d4633SHajimu UMEMOTO on = 1; 2637f95d4633SHajimu UMEMOTO else 2638f95d4633SHajimu UMEMOTO on = 0; 2639f95d4633SHajimu UMEMOTO optdata = (void *)&on; 2640f95d4633SHajimu UMEMOTO optdatalen = sizeof(on); 2641f95d4633SHajimu UMEMOTO break; 2642f95d4633SHajimu UMEMOTO case IPV6_PREFER_TEMPADDR: 2643f95d4633SHajimu UMEMOTO if (pktopt) 264406b479a6SSean Bruno defpreftemp = pktopt->ip6po_prefer_tempaddr; 2645f95d4633SHajimu UMEMOTO optdata = (void *)&defpreftemp; 2646f95d4633SHajimu UMEMOTO optdatalen = sizeof(int); 2647f95d4633SHajimu UMEMOTO break; 2648f95d4633SHajimu UMEMOTO default: /* should not happen */ 2649f95d4633SHajimu UMEMOTO #ifdef DIAGNOSTIC 2650f95d4633SHajimu UMEMOTO panic("ip6_getpcbopt: unexpected option\n"); 2651f95d4633SHajimu UMEMOTO #endif 26520ecd976eSBjoern A. Zeeb INP_RUNLOCK(inp); 2653f95d4633SHajimu UMEMOTO return (ENOPROTOOPT); 2654f95d4633SHajimu UMEMOTO } 26550ecd976eSBjoern A. Zeeb INP_RUNLOCK(inp); 2656f95d4633SHajimu UMEMOTO 2657f95d4633SHajimu UMEMOTO error = sooptcopyout(sopt, optdata, optdatalen); 265806b479a6SSean Bruno if (malloc_optdata) 265906b479a6SSean Bruno free(optdata, M_TEMP); 2660f95d4633SHajimu UMEMOTO 2661f95d4633SHajimu UMEMOTO return (error); 266233841545SHajimu UMEMOTO } 266333841545SHajimu UMEMOTO 266433841545SHajimu UMEMOTO void 26651272577eSXin LI ip6_clearpktopts(struct ip6_pktopts *pktopt, int optname) 266633841545SHajimu UMEMOTO { 2667289b28bdSHajimu UMEMOTO if (pktopt == NULL) 2668289b28bdSHajimu UMEMOTO return; 2669289b28bdSHajimu UMEMOTO 2670f95d4633SHajimu UMEMOTO if (optname == -1 || optname == IPV6_PKTINFO) { 2671885adbfaSHajimu UMEMOTO if (pktopt->ip6po_pktinfo) 267233841545SHajimu UMEMOTO free(pktopt->ip6po_pktinfo, M_IP6OPT); 267333841545SHajimu UMEMOTO pktopt->ip6po_pktinfo = NULL; 267433841545SHajimu UMEMOTO } 2675530c2c30SAndrew Gallatin if (optname == -1 || optname == IPV6_HOPLIMIT) { 267633841545SHajimu UMEMOTO pktopt->ip6po_hlim = -1; 2677530c2c30SAndrew Gallatin pktopt->ip6po_valid &= ~IP6PO_VALID_HLIM; 2678530c2c30SAndrew Gallatin } 2679530c2c30SAndrew Gallatin if (optname == -1 || optname == IPV6_TCLASS) { 2680f95d4633SHajimu UMEMOTO pktopt->ip6po_tclass = -1; 2681530c2c30SAndrew Gallatin pktopt->ip6po_valid &= ~IP6PO_VALID_TC; 2682530c2c30SAndrew Gallatin } 2683f95d4633SHajimu UMEMOTO if (optname == -1 || optname == IPV6_NEXTHOP) { 2684983066f0SAlexander V. Chernikov if (pktopt->ip6po_nextroute.ro_nh) { 2685983066f0SAlexander V. Chernikov NH_FREE(pktopt->ip6po_nextroute.ro_nh); 2686983066f0SAlexander V. Chernikov pktopt->ip6po_nextroute.ro_nh = NULL; 2687f95d4633SHajimu UMEMOTO } 2688885adbfaSHajimu UMEMOTO if (pktopt->ip6po_nexthop) 268933841545SHajimu UMEMOTO free(pktopt->ip6po_nexthop, M_IP6OPT); 269033841545SHajimu UMEMOTO pktopt->ip6po_nexthop = NULL; 2691530c2c30SAndrew Gallatin pktopt->ip6po_valid &= ~IP6PO_VALID_NHINFO; 269233841545SHajimu UMEMOTO } 2693f95d4633SHajimu UMEMOTO if (optname == -1 || optname == IPV6_HOPOPTS) { 2694885adbfaSHajimu UMEMOTO if (pktopt->ip6po_hbh) 269533841545SHajimu UMEMOTO free(pktopt->ip6po_hbh, M_IP6OPT); 269633841545SHajimu UMEMOTO pktopt->ip6po_hbh = NULL; 2697530c2c30SAndrew Gallatin pktopt->ip6po_valid &= ~IP6PO_VALID_HBH; 269833841545SHajimu UMEMOTO } 2699f95d4633SHajimu UMEMOTO if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) { 2700885adbfaSHajimu UMEMOTO if (pktopt->ip6po_dest1) 270133841545SHajimu UMEMOTO free(pktopt->ip6po_dest1, M_IP6OPT); 270233841545SHajimu UMEMOTO pktopt->ip6po_dest1 = NULL; 2703530c2c30SAndrew Gallatin pktopt->ip6po_valid &= ~IP6PO_VALID_DEST1; 270433841545SHajimu UMEMOTO } 2705f95d4633SHajimu UMEMOTO if (optname == -1 || optname == IPV6_RTHDR) { 2706885adbfaSHajimu UMEMOTO if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr) 270733841545SHajimu UMEMOTO free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT); 270833841545SHajimu UMEMOTO pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL; 2709983066f0SAlexander V. Chernikov if (pktopt->ip6po_route.ro_nh) { 2710983066f0SAlexander V. Chernikov NH_FREE(pktopt->ip6po_route.ro_nh); 2711983066f0SAlexander V. Chernikov pktopt->ip6po_route.ro_nh = NULL; 271233841545SHajimu UMEMOTO } 2713530c2c30SAndrew Gallatin pktopt->ip6po_valid &= ~IP6PO_VALID_RHINFO; 271433841545SHajimu UMEMOTO } 2715f95d4633SHajimu UMEMOTO if (optname == -1 || optname == IPV6_DSTOPTS) { 2716885adbfaSHajimu UMEMOTO if (pktopt->ip6po_dest2) 271733841545SHajimu UMEMOTO free(pktopt->ip6po_dest2, M_IP6OPT); 271833841545SHajimu UMEMOTO pktopt->ip6po_dest2 = NULL; 2719530c2c30SAndrew Gallatin pktopt->ip6po_valid &= ~IP6PO_VALID_DEST2; 272033841545SHajimu UMEMOTO } 272133841545SHajimu UMEMOTO } 272233841545SHajimu UMEMOTO 272333841545SHajimu UMEMOTO #define PKTOPT_EXTHDRCPY(type) \ 272433841545SHajimu UMEMOTO do {\ 272533841545SHajimu UMEMOTO if (src->type) {\ 27267efe5d92SHajimu UMEMOTO int hlen = (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\ 272733841545SHajimu UMEMOTO dst->type = malloc(hlen, M_IP6OPT, canwait);\ 27288b07e00eSJonathan T. Looney if (dst->type == NULL)\ 272933841545SHajimu UMEMOTO goto bad;\ 273033841545SHajimu UMEMOTO bcopy(src->type, dst->type, hlen);\ 273133841545SHajimu UMEMOTO }\ 27327efe5d92SHajimu UMEMOTO } while (/*CONSTCOND*/ 0) 273333841545SHajimu UMEMOTO 2734885adbfaSHajimu UMEMOTO static int 27351272577eSXin LI copypktopts(struct ip6_pktopts *dst, struct ip6_pktopts *src, int canwait) 273633841545SHajimu UMEMOTO { 2737885adbfaSHajimu UMEMOTO if (dst == NULL || src == NULL) { 273833841545SHajimu UMEMOTO printf("ip6_clearpktopts: invalid argument\n"); 2739885adbfaSHajimu UMEMOTO return (EINVAL); 274033841545SHajimu UMEMOTO } 274133841545SHajimu UMEMOTO 274233841545SHajimu UMEMOTO dst->ip6po_hlim = src->ip6po_hlim; 2743f95d4633SHajimu UMEMOTO dst->ip6po_tclass = src->ip6po_tclass; 2744f95d4633SHajimu UMEMOTO dst->ip6po_flags = src->ip6po_flags; 27456090ab8bSHiroki Sato dst->ip6po_minmtu = src->ip6po_minmtu; 27466090ab8bSHiroki Sato dst->ip6po_prefer_tempaddr = src->ip6po_prefer_tempaddr; 274733841545SHajimu UMEMOTO if (src->ip6po_pktinfo) { 274833841545SHajimu UMEMOTO dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo), 274933841545SHajimu UMEMOTO M_IP6OPT, canwait); 27502cb64cb2SGeorge V. Neville-Neil if (dst->ip6po_pktinfo == NULL) 275133841545SHajimu UMEMOTO goto bad; 275233841545SHajimu UMEMOTO *dst->ip6po_pktinfo = *src->ip6po_pktinfo; 275333841545SHajimu UMEMOTO } 275433841545SHajimu UMEMOTO if (src->ip6po_nexthop) { 275533841545SHajimu UMEMOTO dst->ip6po_nexthop = malloc(src->ip6po_nexthop->sa_len, 275633841545SHajimu UMEMOTO M_IP6OPT, canwait); 2757403cbcf5SGeorge V. Neville-Neil if (dst->ip6po_nexthop == NULL) 275833841545SHajimu UMEMOTO goto bad; 275933841545SHajimu UMEMOTO bcopy(src->ip6po_nexthop, dst->ip6po_nexthop, 276033841545SHajimu UMEMOTO src->ip6po_nexthop->sa_len); 276133841545SHajimu UMEMOTO } 276233841545SHajimu UMEMOTO PKTOPT_EXTHDRCPY(ip6po_hbh); 276333841545SHajimu UMEMOTO PKTOPT_EXTHDRCPY(ip6po_dest1); 276433841545SHajimu UMEMOTO PKTOPT_EXTHDRCPY(ip6po_dest2); 276533841545SHajimu UMEMOTO PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */ 2766530c2c30SAndrew Gallatin dst->ip6po_valid = src->ip6po_valid; 2767885adbfaSHajimu UMEMOTO return (0); 276833841545SHajimu UMEMOTO 276933841545SHajimu UMEMOTO bad: 2770016fb9d9SMike Makonnen ip6_clearpktopts(dst, -1); 2771885adbfaSHajimu UMEMOTO return (ENOBUFS); 2772885adbfaSHajimu UMEMOTO } 2773885adbfaSHajimu UMEMOTO #undef PKTOPT_EXTHDRCPY 2774885adbfaSHajimu UMEMOTO 2775885adbfaSHajimu UMEMOTO struct ip6_pktopts * 27761272577eSXin LI ip6_copypktopts(struct ip6_pktopts *src, int canwait) 2777885adbfaSHajimu UMEMOTO { 2778885adbfaSHajimu UMEMOTO int error; 2779885adbfaSHajimu UMEMOTO struct ip6_pktopts *dst; 2780885adbfaSHajimu UMEMOTO 2781885adbfaSHajimu UMEMOTO dst = malloc(sizeof(*dst), M_IP6OPT, canwait); 27822cb64cb2SGeorge V. Neville-Neil if (dst == NULL) 2783885adbfaSHajimu UMEMOTO return (NULL); 2784885adbfaSHajimu UMEMOTO ip6_initpktopts(dst); 2785885adbfaSHajimu UMEMOTO 2786885adbfaSHajimu UMEMOTO if ((error = copypktopts(dst, src, canwait)) != 0) { 278735f6695bSHajimu UMEMOTO free(dst, M_IP6OPT); 278833841545SHajimu UMEMOTO return (NULL); 278933841545SHajimu UMEMOTO } 2790885adbfaSHajimu UMEMOTO 2791885adbfaSHajimu UMEMOTO return (dst); 2792885adbfaSHajimu UMEMOTO } 279333841545SHajimu UMEMOTO 279433841545SHajimu UMEMOTO void 27951272577eSXin LI ip6_freepcbopts(struct ip6_pktopts *pktopt) 279633841545SHajimu UMEMOTO { 279733841545SHajimu UMEMOTO if (pktopt == NULL) 279833841545SHajimu UMEMOTO return; 279933841545SHajimu UMEMOTO 2800f95d4633SHajimu UMEMOTO ip6_clearpktopts(pktopt, -1); 280133841545SHajimu UMEMOTO 280233841545SHajimu UMEMOTO free(pktopt, M_IP6OPT); 280333841545SHajimu UMEMOTO } 280433841545SHajimu UMEMOTO 280533841545SHajimu UMEMOTO /* 280682cd038dSYoshinobu Inoue * Set IPv6 outgoing packet options based on advanced API. 280782cd038dSYoshinobu Inoue */ 280882cd038dSYoshinobu Inoue int 28091272577eSXin LI ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt, 281079ba3952SBjoern A. Zeeb struct ip6_pktopts *stickyopt, struct ucred *cred, int uproto) 281182cd038dSYoshinobu Inoue { 2812155d72c4SPedro F. Giffuni struct cmsghdr *cm = NULL; 281382cd038dSYoshinobu Inoue 28148507acb1SHajimu UMEMOTO if (control == NULL || opt == NULL) 281582cd038dSYoshinobu Inoue return (EINVAL); 281682cd038dSYoshinobu Inoue 28172290dfb4SRyan Stone /* 2818d74b7baeSGleb Smirnoff * ip6_setpktopt can call ifnet_byindex(), so it's imperative that we 2819d74b7baeSGleb Smirnoff * are in the network epoch here. 28202290dfb4SRyan Stone */ 28212290dfb4SRyan Stone NET_EPOCH_ASSERT(); 28222290dfb4SRyan Stone 2823885adbfaSHajimu UMEMOTO ip6_initpktopts(opt); 2824f95d4633SHajimu UMEMOTO if (stickyopt) { 2825885adbfaSHajimu UMEMOTO int error; 2826885adbfaSHajimu UMEMOTO 2827f95d4633SHajimu UMEMOTO /* 2828f95d4633SHajimu UMEMOTO * If stickyopt is provided, make a local copy of the options 2829f95d4633SHajimu UMEMOTO * for this particular packet, then override them by ancillary 2830f95d4633SHajimu UMEMOTO * objects. 2831885adbfaSHajimu UMEMOTO * XXX: copypktopts() does not copy the cached route to a next 2832885adbfaSHajimu UMEMOTO * hop (if any). This is not very good in terms of efficiency, 2833885adbfaSHajimu UMEMOTO * but we can allow this since this option should be rarely 2834885adbfaSHajimu UMEMOTO * used. 2835f95d4633SHajimu UMEMOTO */ 2836885adbfaSHajimu UMEMOTO if ((error = copypktopts(opt, stickyopt, M_NOWAIT)) != 0) 2837885adbfaSHajimu UMEMOTO return (error); 2838f95d4633SHajimu UMEMOTO } 283982cd038dSYoshinobu Inoue 284082cd038dSYoshinobu Inoue /* 284182cd038dSYoshinobu Inoue * XXX: Currently, we assume all the optional information is stored 284282cd038dSYoshinobu Inoue * in a single mbuf. 284382cd038dSYoshinobu Inoue */ 284482cd038dSYoshinobu Inoue if (control->m_next) 284582cd038dSYoshinobu Inoue return (EINVAL); 284682cd038dSYoshinobu Inoue 28476f4da201SBjoern A. Zeeb for (; control->m_len > 0; control->m_data += CMSG_ALIGN(cm->cmsg_len), 284833841545SHajimu UMEMOTO control->m_len -= CMSG_ALIGN(cm->cmsg_len)) { 2849f95d4633SHajimu UMEMOTO int error; 2850f95d4633SHajimu UMEMOTO 2851f95d4633SHajimu UMEMOTO if (control->m_len < CMSG_LEN(0)) 2852f95d4633SHajimu UMEMOTO return (EINVAL); 2853f95d4633SHajimu UMEMOTO 285482cd038dSYoshinobu Inoue cm = mtod(control, struct cmsghdr *); 285582cd038dSYoshinobu Inoue if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len) 285682cd038dSYoshinobu Inoue return (EINVAL); 285782cd038dSYoshinobu Inoue if (cm->cmsg_level != IPPROTO_IPV6) 285882cd038dSYoshinobu Inoue continue; 285982cd038dSYoshinobu Inoue 2860d5e3406dSHajimu UMEMOTO error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm), 286179ba3952SBjoern A. Zeeb cm->cmsg_len - CMSG_LEN(0), opt, cred, 0, 1, uproto); 2862f95d4633SHajimu UMEMOTO if (error) 2863f95d4633SHajimu UMEMOTO return (error); 2864f95d4633SHajimu UMEMOTO } 286582cd038dSYoshinobu Inoue 2866f95d4633SHajimu UMEMOTO return (0); 2867f95d4633SHajimu UMEMOTO } 2868f95d4633SHajimu UMEMOTO 2869f95d4633SHajimu UMEMOTO /* 2870f95d4633SHajimu UMEMOTO * Set a particular packet option, as a sticky option or an ancillary data 2871f95d4633SHajimu UMEMOTO * item. "len" can be 0 only when it's a sticky option. 2872f95d4633SHajimu UMEMOTO * We have 4 cases of combination of "sticky" and "cmsg": 2873f95d4633SHajimu UMEMOTO * "sticky=0, cmsg=0": impossible 287418b35df8SHajimu UMEMOTO * "sticky=0, cmsg=1": RFC2292 or RFC3542 ancillary data 287518b35df8SHajimu UMEMOTO * "sticky=1, cmsg=0": RFC3542 socket option 2876f95d4633SHajimu UMEMOTO * "sticky=1, cmsg=1": RFC2292 socket option 2877f95d4633SHajimu UMEMOTO */ 2878f95d4633SHajimu UMEMOTO static int 28791272577eSXin LI ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt, 288079ba3952SBjoern A. Zeeb struct ucred *cred, int sticky, int cmsg, int uproto) 2881f95d4633SHajimu UMEMOTO { 2882f95d4633SHajimu UMEMOTO int minmtupolicy, preftemp; 288379ba3952SBjoern A. Zeeb int error; 2884f95d4633SHajimu UMEMOTO 28859f5432d5SKristof Provost NET_EPOCH_ASSERT(); 28869f5432d5SKristof Provost 2887f95d4633SHajimu UMEMOTO if (!sticky && !cmsg) { 2888f95d4633SHajimu UMEMOTO #ifdef DIAGNOSTIC 2889d5e3406dSHajimu UMEMOTO printf("ip6_setpktopt: impossible case\n"); 2890f95d4633SHajimu UMEMOTO #endif 2891f95d4633SHajimu UMEMOTO return (EINVAL); 2892f95d4633SHajimu UMEMOTO } 2893f95d4633SHajimu UMEMOTO 2894f95d4633SHajimu UMEMOTO /* 2895f95d4633SHajimu UMEMOTO * IPV6_2292xxx is for backward compatibility to RFC2292, and should 289618b35df8SHajimu UMEMOTO * not be specified in the context of RFC3542. Conversely, 289718b35df8SHajimu UMEMOTO * RFC3542 types should not be specified in the context of RFC2292. 2898f95d4633SHajimu UMEMOTO */ 2899f95d4633SHajimu UMEMOTO if (!cmsg) { 2900f95d4633SHajimu UMEMOTO switch (optname) { 2901f95d4633SHajimu UMEMOTO case IPV6_2292PKTINFO: 2902f95d4633SHajimu UMEMOTO case IPV6_2292HOPLIMIT: 2903f95d4633SHajimu UMEMOTO case IPV6_2292NEXTHOP: 2904f95d4633SHajimu UMEMOTO case IPV6_2292HOPOPTS: 2905f95d4633SHajimu UMEMOTO case IPV6_2292DSTOPTS: 2906f95d4633SHajimu UMEMOTO case IPV6_2292RTHDR: 2907f95d4633SHajimu UMEMOTO case IPV6_2292PKTOPTIONS: 2908f95d4633SHajimu UMEMOTO return (ENOPROTOOPT); 2909f95d4633SHajimu UMEMOTO } 2910f95d4633SHajimu UMEMOTO } 2911f95d4633SHajimu UMEMOTO if (sticky && cmsg) { 2912f95d4633SHajimu UMEMOTO switch (optname) { 2913f95d4633SHajimu UMEMOTO case IPV6_PKTINFO: 2914f95d4633SHajimu UMEMOTO case IPV6_HOPLIMIT: 2915f95d4633SHajimu UMEMOTO case IPV6_NEXTHOP: 2916f95d4633SHajimu UMEMOTO case IPV6_HOPOPTS: 2917f95d4633SHajimu UMEMOTO case IPV6_DSTOPTS: 2918f95d4633SHajimu UMEMOTO case IPV6_RTHDRDSTOPTS: 2919f95d4633SHajimu UMEMOTO case IPV6_RTHDR: 2920f95d4633SHajimu UMEMOTO case IPV6_USE_MIN_MTU: 2921f95d4633SHajimu UMEMOTO case IPV6_DONTFRAG: 2922f95d4633SHajimu UMEMOTO case IPV6_TCLASS: 292318b35df8SHajimu UMEMOTO case IPV6_PREFER_TEMPADDR: /* XXX: not an RFC3542 option */ 2924f95d4633SHajimu UMEMOTO return (ENOPROTOOPT); 2925f95d4633SHajimu UMEMOTO } 2926f95d4633SHajimu UMEMOTO } 2927f95d4633SHajimu UMEMOTO 2928f95d4633SHajimu UMEMOTO switch (optname) { 2929f95d4633SHajimu UMEMOTO case IPV6_2292PKTINFO: 2930f95d4633SHajimu UMEMOTO case IPV6_PKTINFO: 2931f95d4633SHajimu UMEMOTO { 2932f95d4633SHajimu UMEMOTO struct ifnet *ifp = NULL; 2933f95d4633SHajimu UMEMOTO struct in6_pktinfo *pktinfo; 2934f95d4633SHajimu UMEMOTO 2935f95d4633SHajimu UMEMOTO if (len != sizeof(struct in6_pktinfo)) 2936f95d4633SHajimu UMEMOTO return (EINVAL); 2937f95d4633SHajimu UMEMOTO 2938f95d4633SHajimu UMEMOTO pktinfo = (struct in6_pktinfo *)buf; 2939f95d4633SHajimu UMEMOTO 2940f95d4633SHajimu UMEMOTO /* 2941f95d4633SHajimu UMEMOTO * An application can clear any sticky IPV6_PKTINFO option by 2942f95d4633SHajimu UMEMOTO * doing a "regular" setsockopt with ipi6_addr being 2943f95d4633SHajimu UMEMOTO * in6addr_any and ipi6_ifindex being zero. 2944f95d4633SHajimu UMEMOTO * [RFC 3542, Section 6] 2945f95d4633SHajimu UMEMOTO */ 2946f95d4633SHajimu UMEMOTO if (optname == IPV6_PKTINFO && opt->ip6po_pktinfo && 2947f95d4633SHajimu UMEMOTO pktinfo->ipi6_ifindex == 0 && 2948f95d4633SHajimu UMEMOTO IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { 2949f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, optname); 2950f95d4633SHajimu UMEMOTO break; 2951f95d4633SHajimu UMEMOTO } 2952f95d4633SHajimu UMEMOTO 2953f95d4633SHajimu UMEMOTO if (uproto == IPPROTO_TCP && optname == IPV6_PKTINFO && 2954f95d4633SHajimu UMEMOTO sticky && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { 2955f95d4633SHajimu UMEMOTO return (EINVAL); 2956f95d4633SHajimu UMEMOTO } 29579196891fSAndrey V. Elsukov if (IN6_IS_ADDR_MULTICAST(&pktinfo->ipi6_addr)) 29589196891fSAndrey V. Elsukov return (EINVAL); 2959f95d4633SHajimu UMEMOTO /* validate the interface index if specified. */ 2960f95d4633SHajimu UMEMOTO if (pktinfo->ipi6_ifindex) { 2961f95d4633SHajimu UMEMOTO ifp = ifnet_byindex(pktinfo->ipi6_ifindex); 2962f95d4633SHajimu UMEMOTO if (ifp == NULL) 296382cd038dSYoshinobu Inoue return (ENXIO); 296482cd038dSYoshinobu Inoue } 2965be393491SDimitry Andric if (ifp != NULL && (ifp->if_afdata[AF_INET6] == NULL || 2966be393491SDimitry Andric (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) != 0)) 29679196891fSAndrey V. Elsukov return (ENETDOWN); 296882cd038dSYoshinobu Inoue 29699196891fSAndrey V. Elsukov if (ifp != NULL && 29709196891fSAndrey V. Elsukov !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { 29719196891fSAndrey V. Elsukov struct in6_ifaddr *ia; 29729196891fSAndrey V. Elsukov 2973cb207f93SAndrey V. Elsukov in6_setscope(&pktinfo->ipi6_addr, ifp, NULL); 29749196891fSAndrey V. Elsukov ia = in6ifa_ifpwithaddr(ifp, &pktinfo->ipi6_addr); 29759196891fSAndrey V. Elsukov if (ia == NULL) 29769196891fSAndrey V. Elsukov return (EADDRNOTAVAIL); 29779196891fSAndrey V. Elsukov ifa_free(&ia->ia_ifa); 29789196891fSAndrey V. Elsukov } 297933841545SHajimu UMEMOTO /* 2980f95d4633SHajimu UMEMOTO * We store the address anyway, and let in6_selectsrc() 2981f95d4633SHajimu UMEMOTO * validate the specified address. This is because ipi6_addr 2982f95d4633SHajimu UMEMOTO * may not have enough information about its scope zone, and 2983f95d4633SHajimu UMEMOTO * we may need additional information (such as outgoing 2984f95d4633SHajimu UMEMOTO * interface or the scope zone of a destination address) to 2985f95d4633SHajimu UMEMOTO * disambiguate the scope. 2986f95d4633SHajimu UMEMOTO * XXX: the delay of the validation may confuse the 2987f95d4633SHajimu UMEMOTO * application when it is used as a sticky option. 298833841545SHajimu UMEMOTO */ 2989f95d4633SHajimu UMEMOTO if (opt->ip6po_pktinfo == NULL) { 2990f95d4633SHajimu UMEMOTO opt->ip6po_pktinfo = malloc(sizeof(*pktinfo), 2991885adbfaSHajimu UMEMOTO M_IP6OPT, M_NOWAIT); 2992885adbfaSHajimu UMEMOTO if (opt->ip6po_pktinfo == NULL) 2993885adbfaSHajimu UMEMOTO return (ENOBUFS); 299482cd038dSYoshinobu Inoue } 2995f95d4633SHajimu UMEMOTO bcopy(pktinfo, opt->ip6po_pktinfo, sizeof(*pktinfo)); 2996530c2c30SAndrew Gallatin opt->ip6po_valid |= IP6PO_VALID_PKTINFO; 299782cd038dSYoshinobu Inoue break; 2998f95d4633SHajimu UMEMOTO } 299982cd038dSYoshinobu Inoue 3000f95d4633SHajimu UMEMOTO case IPV6_2292HOPLIMIT: 300182cd038dSYoshinobu Inoue case IPV6_HOPLIMIT: 3002f95d4633SHajimu UMEMOTO { 3003f95d4633SHajimu UMEMOTO int *hlimp; 3004f95d4633SHajimu UMEMOTO 3005f95d4633SHajimu UMEMOTO /* 3006f95d4633SHajimu UMEMOTO * RFC 3542 deprecated the usage of sticky IPV6_HOPLIMIT 3007f95d4633SHajimu UMEMOTO * to simplify the ordering among hoplimit options. 3008f95d4633SHajimu UMEMOTO */ 3009f95d4633SHajimu UMEMOTO if (optname == IPV6_HOPLIMIT && sticky) 3010f95d4633SHajimu UMEMOTO return (ENOPROTOOPT); 3011f95d4633SHajimu UMEMOTO 3012f95d4633SHajimu UMEMOTO if (len != sizeof(int)) 3013f95d4633SHajimu UMEMOTO return (EINVAL); 3014f95d4633SHajimu UMEMOTO hlimp = (int *)buf; 3015f95d4633SHajimu UMEMOTO if (*hlimp < -1 || *hlimp > 255) 301682cd038dSYoshinobu Inoue return (EINVAL); 301782cd038dSYoshinobu Inoue 3018f95d4633SHajimu UMEMOTO opt->ip6po_hlim = *hlimp; 3019530c2c30SAndrew Gallatin opt->ip6po_valid |= IP6PO_VALID_HLIM; 302082cd038dSYoshinobu Inoue break; 3021f95d4633SHajimu UMEMOTO } 302282cd038dSYoshinobu Inoue 3023f95d4633SHajimu UMEMOTO case IPV6_TCLASS: 3024f95d4633SHajimu UMEMOTO { 3025f95d4633SHajimu UMEMOTO int tclass; 3026f95d4633SHajimu UMEMOTO 3027f95d4633SHajimu UMEMOTO if (len != sizeof(int)) 3028f95d4633SHajimu UMEMOTO return (EINVAL); 3029f95d4633SHajimu UMEMOTO tclass = *(int *)buf; 3030f95d4633SHajimu UMEMOTO if (tclass < -1 || tclass > 255) 3031f95d4633SHajimu UMEMOTO return (EINVAL); 3032f95d4633SHajimu UMEMOTO 3033f95d4633SHajimu UMEMOTO opt->ip6po_tclass = tclass; 3034530c2c30SAndrew Gallatin opt->ip6po_valid |= IP6PO_VALID_TC; 3035f95d4633SHajimu UMEMOTO break; 3036f95d4633SHajimu UMEMOTO } 3037f95d4633SHajimu UMEMOTO 3038f95d4633SHajimu UMEMOTO case IPV6_2292NEXTHOP: 303982cd038dSYoshinobu Inoue case IPV6_NEXTHOP: 304079ba3952SBjoern A. Zeeb if (cred != NULL) { 3041cc426dd3SMateusz Guzik error = priv_check_cred(cred, PRIV_NETINET_SETHDROPTS); 304279ba3952SBjoern A. Zeeb if (error) 304379ba3952SBjoern A. Zeeb return (error); 304479ba3952SBjoern A. Zeeb } 304533841545SHajimu UMEMOTO 3046f95d4633SHajimu UMEMOTO if (len == 0) { /* just remove the option */ 3047f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, IPV6_NEXTHOP); 3048f95d4633SHajimu UMEMOTO break; 3049f95d4633SHajimu UMEMOTO } 3050f95d4633SHajimu UMEMOTO 305133841545SHajimu UMEMOTO /* check if cmsg_len is large enough for sa_len */ 3052f95d4633SHajimu UMEMOTO if (len < sizeof(struct sockaddr) || len < *buf) 305382cd038dSYoshinobu Inoue return (EINVAL); 305482cd038dSYoshinobu Inoue 3055f95d4633SHajimu UMEMOTO switch (((struct sockaddr *)buf)->sa_family) { 3056f95d4633SHajimu UMEMOTO case AF_INET6: 3057f95d4633SHajimu UMEMOTO { 3058f95d4633SHajimu UMEMOTO struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)buf; 3059f95d4633SHajimu UMEMOTO int error; 3060f95d4633SHajimu UMEMOTO 3061f95d4633SHajimu UMEMOTO if (sa6->sin6_len != sizeof(struct sockaddr_in6)) 3062f95d4633SHajimu UMEMOTO return (EINVAL); 3063f95d4633SHajimu UMEMOTO 3064f95d4633SHajimu UMEMOTO if (IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) || 3065f95d4633SHajimu UMEMOTO IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 3066f95d4633SHajimu UMEMOTO return (EINVAL); 3067f95d4633SHajimu UMEMOTO } 3068603724d3SBjoern A. Zeeb if ((error = sa6_embedscope(sa6, V_ip6_use_defzone)) 3069f95d4633SHajimu UMEMOTO != 0) { 3070f95d4633SHajimu UMEMOTO return (error); 3071f95d4633SHajimu UMEMOTO } 3072f95d4633SHajimu UMEMOTO break; 3073f95d4633SHajimu UMEMOTO } 3074f95d4633SHajimu UMEMOTO case AF_LINK: /* should eventually be supported */ 3075f95d4633SHajimu UMEMOTO default: 3076f95d4633SHajimu UMEMOTO return (EAFNOSUPPORT); 3077f95d4633SHajimu UMEMOTO } 3078f95d4633SHajimu UMEMOTO 3079f95d4633SHajimu UMEMOTO /* turn off the previous option, then set the new option. */ 3080f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, IPV6_NEXTHOP); 3081743eee66SSUZUKI Shinsuke opt->ip6po_nexthop = malloc(*buf, M_IP6OPT, M_NOWAIT); 3082743eee66SSUZUKI Shinsuke if (opt->ip6po_nexthop == NULL) 3083743eee66SSUZUKI Shinsuke return (ENOBUFS); 3084f95d4633SHajimu UMEMOTO bcopy(buf, opt->ip6po_nexthop, *buf); 3085530c2c30SAndrew Gallatin opt->ip6po_valid |= IP6PO_VALID_NHINFO; 308682cd038dSYoshinobu Inoue break; 308782cd038dSYoshinobu Inoue 3088f95d4633SHajimu UMEMOTO case IPV6_2292HOPOPTS: 308982cd038dSYoshinobu Inoue case IPV6_HOPOPTS: 309033841545SHajimu UMEMOTO { 309133841545SHajimu UMEMOTO struct ip6_hbh *hbh; 309233841545SHajimu UMEMOTO int hbhlen; 309333841545SHajimu UMEMOTO 3094f95d4633SHajimu UMEMOTO /* 3095f95d4633SHajimu UMEMOTO * XXX: We don't allow a non-privileged user to set ANY HbH 3096f95d4633SHajimu UMEMOTO * options, since per-option restriction has too much 3097f95d4633SHajimu UMEMOTO * overhead. 3098f95d4633SHajimu UMEMOTO */ 309979ba3952SBjoern A. Zeeb if (cred != NULL) { 3100cc426dd3SMateusz Guzik error = priv_check_cred(cred, PRIV_NETINET_SETHDROPTS); 310179ba3952SBjoern A. Zeeb if (error) 310279ba3952SBjoern A. Zeeb return (error); 310379ba3952SBjoern A. Zeeb } 3104f95d4633SHajimu UMEMOTO 3105f95d4633SHajimu UMEMOTO if (len == 0) { 3106f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, IPV6_HOPOPTS); 3107f95d4633SHajimu UMEMOTO break; /* just remove the option */ 3108f95d4633SHajimu UMEMOTO } 3109f95d4633SHajimu UMEMOTO 3110f95d4633SHajimu UMEMOTO /* message length validation */ 3111f95d4633SHajimu UMEMOTO if (len < sizeof(struct ip6_hbh)) 311282cd038dSYoshinobu Inoue return (EINVAL); 3113f95d4633SHajimu UMEMOTO hbh = (struct ip6_hbh *)buf; 311433841545SHajimu UMEMOTO hbhlen = (hbh->ip6h_len + 1) << 3; 3115f95d4633SHajimu UMEMOTO if (len != hbhlen) 311682cd038dSYoshinobu Inoue return (EINVAL); 311733841545SHajimu UMEMOTO 3118f95d4633SHajimu UMEMOTO /* turn off the previous option, then set the new option. */ 3119f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, IPV6_HOPOPTS); 3120743eee66SSUZUKI Shinsuke opt->ip6po_hbh = malloc(hbhlen, M_IP6OPT, M_NOWAIT); 3121743eee66SSUZUKI Shinsuke if (opt->ip6po_hbh == NULL) 3122743eee66SSUZUKI Shinsuke return (ENOBUFS); 312333841545SHajimu UMEMOTO bcopy(hbh, opt->ip6po_hbh, hbhlen); 3124530c2c30SAndrew Gallatin opt->ip6po_valid |= IP6PO_VALID_HBH; 3125f95d4633SHajimu UMEMOTO 312682cd038dSYoshinobu Inoue break; 312733841545SHajimu UMEMOTO } 312882cd038dSYoshinobu Inoue 3129f95d4633SHajimu UMEMOTO case IPV6_2292DSTOPTS: 313082cd038dSYoshinobu Inoue case IPV6_DSTOPTS: 3131f95d4633SHajimu UMEMOTO case IPV6_RTHDRDSTOPTS: 313233841545SHajimu UMEMOTO { 3133f95d4633SHajimu UMEMOTO struct ip6_dest *dest, **newdest = NULL; 313433841545SHajimu UMEMOTO int destlen; 313533841545SHajimu UMEMOTO 313679ba3952SBjoern A. Zeeb if (cred != NULL) { /* XXX: see the comment for IPV6_HOPOPTS */ 3137cc426dd3SMateusz Guzik error = priv_check_cred(cred, PRIV_NETINET_SETHDROPTS); 313879ba3952SBjoern A. Zeeb if (error) 313979ba3952SBjoern A. Zeeb return (error); 314079ba3952SBjoern A. Zeeb } 3141f95d4633SHajimu UMEMOTO 3142f95d4633SHajimu UMEMOTO if (len == 0) { 3143f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, optname); 3144f95d4633SHajimu UMEMOTO break; /* just remove the option */ 3145f95d4633SHajimu UMEMOTO } 3146f95d4633SHajimu UMEMOTO 3147f95d4633SHajimu UMEMOTO /* message length validation */ 3148f95d4633SHajimu UMEMOTO if (len < sizeof(struct ip6_dest)) 314982cd038dSYoshinobu Inoue return (EINVAL); 3150f95d4633SHajimu UMEMOTO dest = (struct ip6_dest *)buf; 315133841545SHajimu UMEMOTO destlen = (dest->ip6d_len + 1) << 3; 3152f95d4633SHajimu UMEMOTO if (len != destlen) 315333841545SHajimu UMEMOTO return (EINVAL); 315482cd038dSYoshinobu Inoue 315582cd038dSYoshinobu Inoue /* 3156f95d4633SHajimu UMEMOTO * Determine the position that the destination options header 3157f95d4633SHajimu UMEMOTO * should be inserted; before or after the routing header. 3158f95d4633SHajimu UMEMOTO */ 3159f95d4633SHajimu UMEMOTO switch (optname) { 3160f95d4633SHajimu UMEMOTO case IPV6_2292DSTOPTS: 3161f95d4633SHajimu UMEMOTO /* 3162f95d4633SHajimu UMEMOTO * The old advacned API is ambiguous on this point. 3163f95d4633SHajimu UMEMOTO * Our approach is to determine the position based 3164f95d4633SHajimu UMEMOTO * according to the existence of a routing header. 3165f95d4633SHajimu UMEMOTO * Note, however, that this depends on the order of the 3166f95d4633SHajimu UMEMOTO * extension headers in the ancillary data; the 1st 3167f95d4633SHajimu UMEMOTO * part of the destination options header must appear 3168f95d4633SHajimu UMEMOTO * before the routing header in the ancillary data, 3169f95d4633SHajimu UMEMOTO * too. 317018b35df8SHajimu UMEMOTO * RFC3542 solved the ambiguity by introducing 3171f95d4633SHajimu UMEMOTO * separate ancillary data or option types. 317282cd038dSYoshinobu Inoue */ 317333841545SHajimu UMEMOTO if (opt->ip6po_rthdr == NULL) 317433841545SHajimu UMEMOTO newdest = &opt->ip6po_dest1; 317533841545SHajimu UMEMOTO else 317633841545SHajimu UMEMOTO newdest = &opt->ip6po_dest2; 3177f95d4633SHajimu UMEMOTO break; 3178f95d4633SHajimu UMEMOTO case IPV6_RTHDRDSTOPTS: 3179f95d4633SHajimu UMEMOTO newdest = &opt->ip6po_dest1; 3180f95d4633SHajimu UMEMOTO break; 3181f95d4633SHajimu UMEMOTO case IPV6_DSTOPTS: 3182f95d4633SHajimu UMEMOTO newdest = &opt->ip6po_dest2; 3183f95d4633SHajimu UMEMOTO break; 3184f95d4633SHajimu UMEMOTO } 318533841545SHajimu UMEMOTO 3186f95d4633SHajimu UMEMOTO /* turn off the previous option, then set the new option. */ 3187f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, optname); 3188743eee66SSUZUKI Shinsuke *newdest = malloc(destlen, M_IP6OPT, M_NOWAIT); 3189fc4c8258SRobert Watson if (*newdest == NULL) 3190743eee66SSUZUKI Shinsuke return (ENOBUFS); 319133841545SHajimu UMEMOTO bcopy(dest, *newdest, destlen); 3192530c2c30SAndrew Gallatin if (newdest == &opt->ip6po_dest1) 3193530c2c30SAndrew Gallatin opt->ip6po_valid |= IP6PO_VALID_DEST1; 3194530c2c30SAndrew Gallatin else 3195530c2c30SAndrew Gallatin opt->ip6po_valid |= IP6PO_VALID_DEST2; 319633841545SHajimu UMEMOTO 319782cd038dSYoshinobu Inoue break; 319833841545SHajimu UMEMOTO } 319982cd038dSYoshinobu Inoue 3200f95d4633SHajimu UMEMOTO case IPV6_2292RTHDR: 320182cd038dSYoshinobu Inoue case IPV6_RTHDR: 320233841545SHajimu UMEMOTO { 320333841545SHajimu UMEMOTO struct ip6_rthdr *rth; 320433841545SHajimu UMEMOTO int rthlen; 320533841545SHajimu UMEMOTO 3206f95d4633SHajimu UMEMOTO if (len == 0) { 3207f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, IPV6_RTHDR); 3208f95d4633SHajimu UMEMOTO break; /* just remove the option */ 3209f95d4633SHajimu UMEMOTO } 3210f95d4633SHajimu UMEMOTO 3211f95d4633SHajimu UMEMOTO /* message length validation */ 3212f95d4633SHajimu UMEMOTO if (len < sizeof(struct ip6_rthdr)) 321382cd038dSYoshinobu Inoue return (EINVAL); 3214f95d4633SHajimu UMEMOTO rth = (struct ip6_rthdr *)buf; 321533841545SHajimu UMEMOTO rthlen = (rth->ip6r_len + 1) << 3; 3216f95d4633SHajimu UMEMOTO if (len != rthlen) 321782cd038dSYoshinobu Inoue return (EINVAL); 321833841545SHajimu UMEMOTO 321933841545SHajimu UMEMOTO switch (rth->ip6r_type) { 322082cd038dSYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 3221f95d4633SHajimu UMEMOTO if (rth->ip6r_len == 0) /* must contain one addr */ 322233841545SHajimu UMEMOTO return (EINVAL); 3223f95d4633SHajimu UMEMOTO if (rth->ip6r_len % 2) /* length must be even */ 322433841545SHajimu UMEMOTO return (EINVAL); 322533841545SHajimu UMEMOTO if (rth->ip6r_len / 2 != rth->ip6r_segleft) 322682cd038dSYoshinobu Inoue return (EINVAL); 322782cd038dSYoshinobu Inoue break; 322882cd038dSYoshinobu Inoue default: 322933841545SHajimu UMEMOTO return (EINVAL); /* not supported */ 323082cd038dSYoshinobu Inoue } 323133841545SHajimu UMEMOTO 3232f95d4633SHajimu UMEMOTO /* turn off the previous option */ 3233f95d4633SHajimu UMEMOTO ip6_clearpktopts(opt, IPV6_RTHDR); 3234743eee66SSUZUKI Shinsuke opt->ip6po_rthdr = malloc(rthlen, M_IP6OPT, M_NOWAIT); 3235743eee66SSUZUKI Shinsuke if (opt->ip6po_rthdr == NULL) 3236743eee66SSUZUKI Shinsuke return (ENOBUFS); 323733841545SHajimu UMEMOTO bcopy(rth, opt->ip6po_rthdr, rthlen); 3238530c2c30SAndrew Gallatin opt->ip6po_valid |= IP6PO_VALID_RHINFO; 323933841545SHajimu UMEMOTO 324082cd038dSYoshinobu Inoue break; 324133841545SHajimu UMEMOTO } 324282cd038dSYoshinobu Inoue 3243f95d4633SHajimu UMEMOTO case IPV6_USE_MIN_MTU: 3244f95d4633SHajimu UMEMOTO if (len != sizeof(int)) 3245f95d4633SHajimu UMEMOTO return (EINVAL); 3246f95d4633SHajimu UMEMOTO minmtupolicy = *(int *)buf; 3247f95d4633SHajimu UMEMOTO if (minmtupolicy != IP6PO_MINMTU_MCASTONLY && 3248f95d4633SHajimu UMEMOTO minmtupolicy != IP6PO_MINMTU_DISABLE && 3249f95d4633SHajimu UMEMOTO minmtupolicy != IP6PO_MINMTU_ALL) { 3250f95d4633SHajimu UMEMOTO return (EINVAL); 3251f95d4633SHajimu UMEMOTO } 3252f95d4633SHajimu UMEMOTO opt->ip6po_minmtu = minmtupolicy; 3253f95d4633SHajimu UMEMOTO break; 3254f95d4633SHajimu UMEMOTO 3255f95d4633SHajimu UMEMOTO case IPV6_DONTFRAG: 3256f95d4633SHajimu UMEMOTO if (len != sizeof(int)) 3257f95d4633SHajimu UMEMOTO return (EINVAL); 3258f95d4633SHajimu UMEMOTO 3259f95d4633SHajimu UMEMOTO if (uproto == IPPROTO_TCP || *(int *)buf == 0) { 3260f95d4633SHajimu UMEMOTO /* 3261f95d4633SHajimu UMEMOTO * we ignore this option for TCP sockets. 326218b35df8SHajimu UMEMOTO * (RFC3542 leaves this case unspecified.) 3263f95d4633SHajimu UMEMOTO */ 3264f95d4633SHajimu UMEMOTO opt->ip6po_flags &= ~IP6PO_DONTFRAG; 3265f95d4633SHajimu UMEMOTO } else 3266f95d4633SHajimu UMEMOTO opt->ip6po_flags |= IP6PO_DONTFRAG; 3267f95d4633SHajimu UMEMOTO break; 3268f95d4633SHajimu UMEMOTO 3269f95d4633SHajimu UMEMOTO case IPV6_PREFER_TEMPADDR: 3270f95d4633SHajimu UMEMOTO if (len != sizeof(int)) 3271f95d4633SHajimu UMEMOTO return (EINVAL); 3272f95d4633SHajimu UMEMOTO preftemp = *(int *)buf; 3273f95d4633SHajimu UMEMOTO if (preftemp != IP6PO_TEMPADDR_SYSTEM && 3274f95d4633SHajimu UMEMOTO preftemp != IP6PO_TEMPADDR_NOTPREFER && 3275f95d4633SHajimu UMEMOTO preftemp != IP6PO_TEMPADDR_PREFER) { 3276f95d4633SHajimu UMEMOTO return (EINVAL); 3277f95d4633SHajimu UMEMOTO } 3278f95d4633SHajimu UMEMOTO opt->ip6po_prefer_tempaddr = preftemp; 3279f95d4633SHajimu UMEMOTO break; 3280f95d4633SHajimu UMEMOTO 328182cd038dSYoshinobu Inoue default: 328282cd038dSYoshinobu Inoue return (ENOPROTOOPT); 3283f95d4633SHajimu UMEMOTO } /* end of switch */ 328482cd038dSYoshinobu Inoue 328582cd038dSYoshinobu Inoue return (0); 328682cd038dSYoshinobu Inoue } 328782cd038dSYoshinobu Inoue 328882cd038dSYoshinobu Inoue /* 328982cd038dSYoshinobu Inoue * Routine called from ip6_output() to loop back a copy of an IP6 multicast 329082cd038dSYoshinobu Inoue * packet to the input queue of a specified interface. Note that this 329182cd038dSYoshinobu Inoue * calls the output routine of the loopback "driver", but with an interface 329282cd038dSYoshinobu Inoue * pointer that might NOT be &loif -- easier than replicating that code here. 329382cd038dSYoshinobu Inoue */ 329482cd038dSYoshinobu Inoue void 329556a5f52eSGleb Smirnoff ip6_mloopback(struct ifnet *ifp, struct mbuf *m) 329682cd038dSYoshinobu Inoue { 329782cd038dSYoshinobu Inoue struct mbuf *copym; 3298686cdd19SJun-ichiro itojun Hagino struct ip6_hdr *ip6; 329982cd038dSYoshinobu Inoue 3300c3bef61eSKevin Lo copym = m_copym(m, 0, M_COPYALL, M_NOWAIT); 3301686cdd19SJun-ichiro itojun Hagino if (copym == NULL) 3302686cdd19SJun-ichiro itojun Hagino return; 3303686cdd19SJun-ichiro itojun Hagino 3304686cdd19SJun-ichiro itojun Hagino /* 3305686cdd19SJun-ichiro itojun Hagino * Make sure to deep-copy IPv6 header portion in case the data 3306686cdd19SJun-ichiro itojun Hagino * is in an mbuf cluster, so that we can safely override the IPv6 3307686cdd19SJun-ichiro itojun Hagino * header portion later. 3308686cdd19SJun-ichiro itojun Hagino */ 3309f0cace5dSRobert Watson if (!M_WRITABLE(copym) || 3310686cdd19SJun-ichiro itojun Hagino copym->m_len < sizeof(struct ip6_hdr)) { 3311686cdd19SJun-ichiro itojun Hagino copym = m_pullup(copym, sizeof(struct ip6_hdr)); 3312686cdd19SJun-ichiro itojun Hagino if (copym == NULL) 3313686cdd19SJun-ichiro itojun Hagino return; 331482cd038dSYoshinobu Inoue } 3315686cdd19SJun-ichiro itojun Hagino ip6 = mtod(copym, struct ip6_hdr *); 331633841545SHajimu UMEMOTO /* 331733841545SHajimu UMEMOTO * clear embedded scope identifiers if necessary. 331833841545SHajimu UMEMOTO * in6_clearscope will touch the addresses only when necessary. 331933841545SHajimu UMEMOTO */ 332033841545SHajimu UMEMOTO in6_clearscope(&ip6->ip6_src); 332133841545SHajimu UMEMOTO in6_clearscope(&ip6->ip6_dst); 3322654bdb5aSAndrey V. Elsukov if (copym->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 3323654bdb5aSAndrey V. Elsukov copym->m_pkthdr.csum_flags |= CSUM_DATA_VALID_IPV6 | 3324654bdb5aSAndrey V. Elsukov CSUM_PSEUDO_HDR; 3325654bdb5aSAndrey V. Elsukov copym->m_pkthdr.csum_data = 0xffff; 3326654bdb5aSAndrey V. Elsukov } 3327331dff07SAlexander V. Chernikov if_simloop(ifp, copym, AF_INET6, 0); 332882cd038dSYoshinobu Inoue } 332982cd038dSYoshinobu Inoue 333082cd038dSYoshinobu Inoue /* 333182cd038dSYoshinobu Inoue * Chop IPv6 header off from the payload. 333282cd038dSYoshinobu Inoue */ 333382cd038dSYoshinobu Inoue static int 33341272577eSXin LI ip6_splithdr(struct mbuf *m, struct ip6_exthdrs *exthdrs) 333582cd038dSYoshinobu Inoue { 333682cd038dSYoshinobu Inoue struct mbuf *mh; 333782cd038dSYoshinobu Inoue struct ip6_hdr *ip6; 333882cd038dSYoshinobu Inoue 333982cd038dSYoshinobu Inoue ip6 = mtod(m, struct ip6_hdr *); 334082cd038dSYoshinobu Inoue if (m->m_len > sizeof(*ip6)) { 33417b07d1beSGleb Smirnoff mh = m_gethdr(M_NOWAIT, MT_DATA); 33427b07d1beSGleb Smirnoff if (mh == NULL) { 334382cd038dSYoshinobu Inoue m_freem(m); 334482cd038dSYoshinobu Inoue return ENOBUFS; 334582cd038dSYoshinobu Inoue } 334610e5acc3SGleb Smirnoff m_move_pkthdr(mh, m); 3347ed6a66caSRobert Watson M_ALIGN(mh, sizeof(*ip6)); 334882cd038dSYoshinobu Inoue m->m_len -= sizeof(*ip6); 334982cd038dSYoshinobu Inoue m->m_data += sizeof(*ip6); 335082cd038dSYoshinobu Inoue mh->m_next = m; 335182cd038dSYoshinobu Inoue m = mh; 335282cd038dSYoshinobu Inoue m->m_len = sizeof(*ip6); 335382cd038dSYoshinobu Inoue bcopy((caddr_t)ip6, mtod(m, caddr_t), sizeof(*ip6)); 335482cd038dSYoshinobu Inoue } 335582cd038dSYoshinobu Inoue exthdrs->ip6e_ip6 = m; 335682cd038dSYoshinobu Inoue return 0; 335782cd038dSYoshinobu Inoue } 335882cd038dSYoshinobu Inoue 335982cd038dSYoshinobu Inoue /* 336082cd038dSYoshinobu Inoue * Compute IPv6 extension header length. 336182cd038dSYoshinobu Inoue */ 336282cd038dSYoshinobu Inoue int 33630ecd976eSBjoern A. Zeeb ip6_optlen(struct inpcb *inp) 336482cd038dSYoshinobu Inoue { 336582cd038dSYoshinobu Inoue int len; 336682cd038dSYoshinobu Inoue 33670ecd976eSBjoern A. Zeeb if (!inp->in6p_outputopts) 336882cd038dSYoshinobu Inoue return 0; 336982cd038dSYoshinobu Inoue 337082cd038dSYoshinobu Inoue len = 0; 337182cd038dSYoshinobu Inoue #define elen(x) \ 337282cd038dSYoshinobu Inoue (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0) 337382cd038dSYoshinobu Inoue 33740ecd976eSBjoern A. Zeeb len += elen(inp->in6p_outputopts->ip6po_hbh); 33750ecd976eSBjoern A. Zeeb if (inp->in6p_outputopts->ip6po_rthdr) 337633841545SHajimu UMEMOTO /* dest1 is valid with rthdr only */ 33770ecd976eSBjoern A. Zeeb len += elen(inp->in6p_outputopts->ip6po_dest1); 33780ecd976eSBjoern A. Zeeb len += elen(inp->in6p_outputopts->ip6po_rthdr); 33790ecd976eSBjoern A. Zeeb len += elen(inp->in6p_outputopts->ip6po_dest2); 338082cd038dSYoshinobu Inoue return len; 338182cd038dSYoshinobu Inoue #undef elen 338282cd038dSYoshinobu Inoue } 3383