+ rt = rtalloc1(dst, 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.
+ */
+#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
+ if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway))
+ error = EINVAL;
+ else if (ifa_ifwithaddr(gateway))
+ error = EHOSTUNREACH;
+ if (error)
+ goto done;
+ /*
+ * 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 == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
+ goto create;
+ /*
+ * 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.
+ */
+ create:
+ flags |= RTF_GATEWAY | RTF_DYNAMIC;
+ error = rtrequest((int)RTM_ADD, dst, gateway,
+ SA(0), flags,
+ (struct rtentry **)0);
+ stat = &rtstat.rts_dynamic;
+ } else {
+ /*
+ * Smash the current notion of the gateway to
+ * this destination. Should check about netmask!!!
+ */
+ if (gateway->sa_len <= rt->rt_gateway->sa_len) {
+ Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
+ rt->rt_flags |= RTF_MODIFIED;
+ flags |= RTF_MODIFIED;
+ stat = &rtstat.rts_newgateway;
+ } else
+ error = ENOSPC;
+ }
+ } else
+ error = EHOSTUNREACH;
+done:
+ if (rt) {
+ if (rtp && !error)
+ *rtp = rt;
+ else
+ rtfree(rt);
+ }
+ if (error)
+ rtstat.rts_badredirect++;
+ else
+ (stat && (*stat)++);
+ rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src, flags, error);