+ 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);