+ if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) {
+ rttrash--;
+ (void) m_free(dtom(rt));
+ }
+}
+
+/*
+ * Force a routing table entry to the specified
+ * destination to go through the given gateway.
+ * Normally called as a result of a routing redirect
+ * message from the network layer.
+ *
+ * N.B.: must be called at splnet or higher
+ *
+ */
+rtredirect(dst, gateway, flags, src)
+ struct sockaddr *dst, *gateway, *src;
+ int flags;
+{
+ struct route ro;
+ register struct rtentry *rt;
+
+ /* verify the gateway is directly reachable */
+ if (ifa_ifwithnet(gateway) == 0) {
+ rtstat.rts_badredirect++;
+ return;
+ }
+ ro.ro_dst = *dst;
+ ro.ro_rt = 0;
+ rtalloc(&ro);
+ rt = ro.ro_rt;
+#define equal(a1, a2) \
+ (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0)
+ /*
+ * If the redirect isn't from our current router for this dst,
+ * it's either old or wrong. If it redirects us to ourselves,
+ * we have a routing loop, perhaps as a result of an interface
+ * going down recently.
+ */
+ if ((rt && !equal(src, &rt->rt_gateway)) || ifa_ifwithaddr(gateway)) {
+ rtstat.rts_badredirect++;
+ if (rt)
+ rtfree(rt);
+ return;
+ }
+ /*
+ * Create a new entry if we just got back a wildcard entry
+ * or the the lookup failed. This is necessary for hosts
+ * which use routing redirects generated by smart gateways
+ * to dynamically build the routing tables.
+ */
+ if (rt &&
+ (*afswitch[dst->sa_family].af_netmatch)(&wildcard, &rt->rt_dst)) {
+ rtfree(rt);
+ rt = 0;
+ }
+ if (rt == 0) {
+ rtinit(dst, gateway, (int)SIOCADDRT,
+ (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC);
+ rtstat.rts_dynamic++;
+ return;
+ }
+ /*
+ * Don't listen to the redirect if it's
+ * for a route to an interface.
+ */
+ if (rt->rt_flags & RTF_GATEWAY) {
+ if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
+ /*
+ * Changing from route to net => route to host.
+ * Create new route, rather than smashing route to net.
+ */
+ rtinit(dst, gateway, (int)SIOCADDRT,
+ flags | RTF_DYNAMIC);
+ rtstat.rts_dynamic++;
+ } else {
+ /*
+ * Smash the current notion of the gateway to
+ * this destination.
+ */
+ rt->rt_gateway = *gateway;
+ rt->rt_flags |= RTF_MODIFIED;
+ rtstat.rts_newgateway++;
+ }
+ } else
+ rtstat.rts_badredirect++;
+ rtfree(rt);
+}
+
+/*
+ * Routing table ioctl interface.
+ */
+rtioctl(cmd, data)
+ int cmd;
+ caddr_t data;
+{
+
+ if (cmd != SIOCADDRT && cmd != SIOCDELRT)
+ return (EINVAL);
+ if (!suser())
+ return (u.u_error);
+ return (rtrequest(cmd, (struct rtentry *)data));