+static uint32_t ip6_adj_clear_hwcksum = 0;
+SYSCTL_UINT(_net_inet6_ip6, OID_AUTO, adj_clear_hwcksum,
+ CTLFLAG_RW | CTLFLAG_LOCKED, &ip6_adj_clear_hwcksum, 0,
+ "Invalidate hwcksum info when adjusting length");
+
+static uint32_t ip6_adj_partial_sum = 1;
+SYSCTL_UINT(_net_inet6_ip6, OID_AUTO, adj_partial_sum,
+ CTLFLAG_RW | CTLFLAG_LOCKED, &ip6_adj_partial_sum, 0,
+ "Perform partial sum adjustment of trailing bytes at IP layer");
+
+static int ip6_input_measure = 0;
+SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, input_perf,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ &ip6_input_measure, 0, sysctl_reset_ip6_input_stats, "I", "Do time measurement");
+
+static uint64_t ip6_input_measure_bins = 0;
+SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, input_perf_bins,
+ CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, &ip6_input_measure_bins, 0,
+ sysctl_ip6_input_measure_bins, "I",
+ "bins for chaining performance data histogram");
+
+static net_perf_t net_perf;
+SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, input_perf_data,
+ CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
+ 0, 0, sysctl_ip6_input_getperf, "S,net_perf",
+ "IP6 input performance data (struct net_perf, net/net_perf.h)");
+
+/*
+ * ip6_checkinterface controls the receive side of the models for multihoming
+ * that are discussed in RFC 1122.
+ *
+ * sysctl_ip6_checkinterface values are:
+ * IP6_CHECKINTERFACE_WEAK_ES:
+ * This corresponds to the Weak End-System model where incoming packets from
+ * any interface are accepted provided the destination address of the incoming packet
+ * is assigned to some interface.
+ *
+ * IP6_CHECKINTERFACE_HYBRID_ES:
+ * The Hybrid End-System model use the Strong End-System for tunnel interfaces
+ * (ipsec and utun) and the weak End-System model for other interfaces families.
+ * This prevents a rogue middle box to probe for signs of TCP connections
+ * that use the tunnel interface.
+ *
+ * IP6_CHECKINTERFACE_STRONG_ES:
+ * The Strong model model requires the packet arrived on an interface that
+ * is assigned the destination address of the packet.
+ *
+ * Since the routing table and transmit implementation do not implement the Strong ES model,
+ * setting this to a value different from IP6_CHECKINTERFACE_WEAK_ES may lead to unexpected results.
+ *
+ * When forwarding is enabled, the system reverts to the Weak ES model as a router
+ * is expected by design to receive packets from several interfaces to the same address.
+ */
+#define IP6_CHECKINTERFACE_WEAK_ES 0
+#define IP6_CHECKINTERFACE_HYBRID_ES 1
+#define IP6_CHECKINTERFACE_STRONG_ES 2
+
+static int ip6_checkinterface = IP6_CHECKINTERFACE_HYBRID_ES;
+
+static int sysctl_ip6_checkinterface SYSCTL_HANDLER_ARGS;
+SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, check_interface,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ 0, 0, sysctl_ip6_checkinterface, "I", "Verify packet arrives on correct interface");
+
+#if (DEBUG || DEVELOPMENT)
+#define IP6_CHECK_IFDEBUG 1
+#else
+#define IP6_CHECK_IFDEBUG 0
+#endif /* (DEBUG || DEVELOPMENT) */
+static int ip6_checkinterface_debug = IP6_CHECK_IFDEBUG;
+SYSCTL_INT(_net_inet6_ip6, OID_AUTO, checkinterface_debug, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &ip6_checkinterface_debug, IP6_CHECK_IFDEBUG, "");
+
+typedef enum ip6_check_if_result {
+ IP6_CHECK_IF_NONE = 0,
+ IP6_CHECK_IF_OURS = 1,
+ IP6_CHECK_IF_DROP = 2,
+ IP6_CHECK_IF_FORWARD = 3
+} ip6_check_if_result_t;
+
+static ip6_check_if_result_t ip6_input_check_interface(struct mbuf *, struct ip6_hdr *, struct ifnet *, struct route_in6 *rin6, struct ifnet **);
+
+/*
+ * On platforms which require strict alignment (currently for anything but
+ * i386 or x86_64), check if the IP header pointer is 32-bit aligned; if not,
+ * copy the contents of the mbuf chain into a new chain, and free the original
+ * one. Create some head room in the first mbuf of the new chain, in case
+ * it's needed later on.
+ *
+ * RFC 2460 says that IPv6 headers are 64-bit aligned, but network interfaces
+ * mostly align to 32-bit boundaries. Care should be taken never to use 64-bit
+ * load/store operations on the fields in IPv6 headers.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+#define IP6_HDR_ALIGNMENT_FIXUP(_m, _ifp, _action) do { } while (0)
+#else /* !__i386__ && !__x86_64__ */
+#define IP6_HDR_ALIGNMENT_FIXUP(_m, _ifp, _action) do { \
+ if (!IP6_HDR_ALIGNED_P(mtod(_m, caddr_t))) { \
+ struct mbuf *_n; \
+ struct ifnet *__ifp = (_ifp); \
+ atomic_add_64(&(__ifp)->if_alignerrs, 1); \
+ if (((_m)->m_flags & M_PKTHDR) && \
+ (_m)->m_pkthdr.pkt_hdr != NULL) \
+ (_m)->m_pkthdr.pkt_hdr = NULL; \
+ _n = m_defrag_offset(_m, max_linkhdr, M_NOWAIT); \
+ if (_n == NULL) { \
+ ip6stat.ip6s_toosmall++; \
+ m_freem(_m); \
+ (_m) = NULL; \
+ _action; \
+ } else { \
+ VERIFY(_n != (_m)); \
+ (_m) = _n; \
+ } \
+ } \
+} while (0)
+#endif /* !__i386__ && !__x86_64__ */