+/*
+ * 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
+ *
+ * Should notify all parties with a reference to
+ * the route that it's changed (so, for instance,
+ * current round trip time estimates could be flushed),
+ * but we have no back pointers at the moment.
+ */
+rtredirect(dst, gateway)
+ struct sockaddr *dst, *gateway;
+{
+ struct route ro;
+ register struct rtentry *rt;
+
+ /* verify the gateway is directly reachable */
+ if (if_ifwithnet(gateway) == 0) {
+ rtstat.rts_badredirect++;
+ return;
+ }
+ ro.ro_dst = *dst;
+ ro.ro_rt = 0;
+ rtalloc(&ro);
+ rt = ro.ro_rt;
+ /*
+ * 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, RTF_GATEWAY);
+ 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) {
+ /*
+ * Smash the current notion of the gateway to
+ * this destination. This is probably not right,
+ * as it's conceivable a flurry of redirects could
+ * cause the gateway value to fluctuate wildly during
+ * dynamic routing reconfiguration.
+ */
+ rt->rt_gateway = *gateway;
+ rtfree(rt);
+ rtstat.rts_newgateway++;
+ return;
+ }
+}
+
+/*
+ * 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));
+}
+