+ return (0);
+}
+#endif /* MROUTING */
+
+static inline u_short
+ip_cksum(struct mbuf *m, int hlen)
+{
+ u_short sum;
+
+ if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
+ sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
+ } else if (!(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) &&
+ !(m->m_pkthdr.pkt_flags & PKTF_LOOP)) {
+ /*
+ * The packet arrived on an interface which isn't capable
+ * of performing IP header checksum; compute it now.
+ */
+ sum = ip_cksum_hdr_in(m, hlen);
+ } else {
+ sum = 0;
+ m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
+ CSUM_IP_CHECKED | CSUM_IP_VALID);
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+
+ if (sum != 0)
+ OSAddAtomic(1, &ipstat.ips_badsum);
+
+ return (sum);
+}
+
+static int
+ip_getstat SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ if (req->oldptr == USER_ADDR_NULL)
+ req->oldlen = (size_t)sizeof (struct ipstat);
+
+ return (SYSCTL_OUT(req, &ipstat, MIN(sizeof (ipstat), req->oldlen)));
+}
+
+void
+ip_setsrcifaddr_info(struct mbuf *m, uint32_t src_idx, struct in_ifaddr *ia)
+{
+ VERIFY(m->m_flags & M_PKTHDR);
+
+ /*
+ * If the source ifaddr is specified, pick up the information
+ * from there; otherwise just grab the passed-in ifindex as the
+ * caller may not have the ifaddr available.
+ */
+ if (ia != NULL) {
+ m->m_pkthdr.pkt_flags |= PKTF_IFAINFO;
+ m->m_pkthdr.src_ifindex = ia->ia_ifp->if_index;
+ } else {
+ m->m_pkthdr.src_ifindex = src_idx;
+ if (src_idx != 0)
+ m->m_pkthdr.pkt_flags |= PKTF_IFAINFO;
+ }
+}
+
+void
+ip_setdstifaddr_info(struct mbuf *m, uint32_t dst_idx, struct in_ifaddr *ia)
+{
+ VERIFY(m->m_flags & M_PKTHDR);
+
+ /*
+ * If the destination ifaddr is specified, pick up the information
+ * from there; otherwise just grab the passed-in ifindex as the
+ * caller may not have the ifaddr available.
+ */
+ if (ia != NULL) {
+ m->m_pkthdr.pkt_flags |= PKTF_IFAINFO;
+ m->m_pkthdr.dst_ifindex = ia->ia_ifp->if_index;
+ } else {
+ m->m_pkthdr.dst_ifindex = dst_idx;
+ if (dst_idx != 0)
+ m->m_pkthdr.pkt_flags |= PKTF_IFAINFO;
+ }
+}
+
+int
+ip_getsrcifaddr_info(struct mbuf *m, uint32_t *src_idx, uint32_t *iaf)
+{
+ VERIFY(m->m_flags & M_PKTHDR);
+
+ if (!(m->m_pkthdr.pkt_flags & PKTF_IFAINFO))
+ return (-1);
+
+ if (src_idx != NULL)
+ *src_idx = m->m_pkthdr.src_ifindex;
+
+ if (iaf != NULL)
+ *iaf = 0;
+
+ return (0);
+}
+
+int
+ip_getdstifaddr_info(struct mbuf *m, uint32_t *dst_idx, uint32_t *iaf)
+{
+ VERIFY(m->m_flags & M_PKTHDR);
+
+ if (!(m->m_pkthdr.pkt_flags & PKTF_IFAINFO))
+ return (-1);
+
+ if (dst_idx != NULL)
+ *dst_idx = m->m_pkthdr.dst_ifindex;
+
+ if (iaf != NULL)
+ *iaf = 0;
+
+ return (0);
+}
+
+/*
+ * Protocol input handler for IPPROTO_GRE.
+ */
+void
+gre_input(struct mbuf *m, int off)
+{
+ gre_input_func_t fn = gre_input_func;
+
+ /*
+ * If there is a registered GRE input handler, pass mbuf to it.
+ */
+ if (fn != NULL) {
+ lck_mtx_unlock(inet_domain_mutex);
+ m = fn(m, off, (mtod(m, struct ip *))->ip_p);
+ lck_mtx_lock(inet_domain_mutex);
+ }
+
+ /*
+ * If no matching tunnel that is up is found, we inject
+ * the mbuf to raw ip socket to see if anyone picks it up.
+ */
+ if (m != NULL)
+ rip_input(m, off);
+}
+
+/*
+ * Private KPI for PPP/PPTP.
+ */
+int
+ip_gre_register_input(gre_input_func_t fn)
+{
+ lck_mtx_lock(inet_domain_mutex);
+ gre_input_func = fn;
+ lck_mtx_unlock(inet_domain_mutex);
+
+ return (0);