+static int
+sysctl_ipforwarding SYSCTL_HANDLER_ARGS
+{
+#pragma unused(arg1, arg2)
+ int i, was_ipforwarding = ipforwarding;
+
+ i = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
+ if (i != 0 || req->newptr == USER_ADDR_NULL)
+ return (i);
+
+ if (was_ipforwarding && !ipforwarding) {
+ /* clean up IPv4 forwarding cached routes */
+ ifnet_head_lock_shared();
+ for (i = 0; i <= if_index; i++) {
+ struct ifnet *ifp = ifindex2ifnet[i];
+ if (ifp != NULL) {
+ lck_mtx_lock(&ifp->if_cached_route_lock);
+ if (ifp->if_fwd_route.ro_rt != NULL)
+ rtfree(ifp->if_fwd_route.ro_rt);
+ bzero(&ifp->if_fwd_route,
+ sizeof (ifp->if_fwd_route));
+ lck_mtx_unlock(&ifp->if_cached_route_lock);
+ }
+ }
+ ifnet_head_done();
+ }
+
+ return (0);
+}
+
+/*
+ * Similar to inp_route_{copyout,copyin} routines except that these copy
+ * out the cached IPv4 forwarding route from struct ifnet instead of the
+ * inpcb. See comments for those routines for explanations.
+ */
+static void
+ip_fwd_route_copyout(struct ifnet *ifp, struct route *dst)
+{
+ struct route *src = &ifp->if_fwd_route;
+
+ lck_mtx_lock_spin(&ifp->if_cached_route_lock);
+ lck_mtx_convert_spin(&ifp->if_cached_route_lock);
+
+ /* Minor sanity check */
+ if (src->ro_rt != NULL && rt_key(src->ro_rt)->sa_family != AF_INET)
+ panic("%s: wrong or corrupted route: %p", __func__, src);
+
+ route_copyout(dst, src, sizeof(*dst));
+
+ lck_mtx_unlock(&ifp->if_cached_route_lock);
+}
+
+static void
+ip_fwd_route_copyin(struct ifnet *ifp, struct route *src)
+{
+ struct route *dst = &ifp->if_fwd_route;
+
+ lck_mtx_lock_spin(&ifp->if_cached_route_lock);
+ lck_mtx_convert_spin(&ifp->if_cached_route_lock);
+
+ /* Minor sanity check */
+ if (src->ro_rt != NULL && rt_key(src->ro_rt)->sa_family != AF_INET)
+ panic("%s: wrong or corrupted route: %p", __func__, src);
+
+ if (ifp->if_fwd_cacheok)
+ route_copyin(src, dst, sizeof(*src));
+
+ lck_mtx_unlock(&ifp->if_cached_route_lock);
+}
+