diff options
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in.c | 3 | ||||
-rw-r--r-- | sys/netinet/in_proto.c | 2 | ||||
-rw-r--r-- | sys/netinet/in_rmx.c | 50 | ||||
-rw-r--r-- | sys/netinet/in_var.h | 2 | ||||
-rw-r--r-- | sys/netinet/ip_var.h | 1 | ||||
-rw-r--r-- | sys/netinet/raw_ip.c | 64 |
6 files changed, 117 insertions, 5 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c index a52ec77..60bf97a 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -58,7 +58,6 @@ static void in_socktrim __P((struct sockaddr_in *)); static int in_ifinit __P((struct ifnet *, struct in_ifaddr *, struct sockaddr_in *, int)); -static void in_ifscrub __P((struct ifnet *, struct in_ifaddr *)); static int subnetsarelocal = 0; SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, @@ -366,7 +365,7 @@ in_control(so, cmd, data, ifp) /* * Delete any existing route for an interface. */ -static void +void in_ifscrub(ifp, ia) register struct ifnet *ifp; register struct in_ifaddr *ia; diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 5b66e0d..9a80959 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -116,7 +116,7 @@ struct protosw inetsw[] = { &tcp_usrreqs }, { SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR, - rip_input, 0, 0, rip_ctloutput, + rip_input, 0, rip_ctlinput, rip_ctloutput, rip_usrreq, 0, 0, 0, 0, }, diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c index 095afc9..a302c1a 100644 --- a/sys/netinet/in_rmx.c +++ b/sys/netinet/in_rmx.c @@ -26,7 +26,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $Id$ */ /* @@ -382,3 +382,51 @@ in_inithead(void **head, int off) return 1; } + +/* + * This zaps old routes when the interface goes down. + * Currently it doesn't delete static routes; there are + * arguments one could make for both behaviors. For the moment, + * we will adopt the Principle of Least Surprise and leave them + * alone (with the knowledge that this will not be enough for some + * people). The ones we really want to get rid of are things like ARP + * entries, since the user might down the interface, walk over to a completely + * different network, and plug back in. + */ +struct in_ifadown_arg { + struct radix_node_head *rnh; + struct ifaddr *ifa; +}; + +static int +in_ifadownkill(struct radix_node *rn, void *xap) +{ + struct in_ifadown_arg *ap = xap; + struct rtentry *rt = (struct rtentry *)rn; + int err; + + if (rt->rt_ifa == ap->ifa && !(rt->rt_flags & RTF_STATIC)) { + err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), + rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); + if (err) { + log(LOG_WARNING, "in_ifadownkill: error %d\n", err); + } + } + return 0; +} + +int +in_ifadown(struct ifaddr *ifa) +{ + struct in_ifadown_arg arg; + struct radix_node_head *rnh; + + if (ifa->ifa_addr->sa_family != AF_INET) + return 1; + + arg.rnh = rnh = rt_tables[AF_INET]; + arg.ifa = ifa; + rnh->rnh_walktree(rnh, in_ifadownkill, &arg); + ifa->ifa_flags &= ~IFA_ROUTE; + return 0; +} diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h index f760956..dfc08ca 100644 --- a/sys/netinet/in_var.h +++ b/sys/netinet/in_var.h @@ -219,6 +219,8 @@ void in_delmulti __P((struct in_multi *)); int in_control __P((struct socket *, u_long, caddr_t, struct ifnet *)); void in_rtqdrain __P((void)); void ip_input __P((struct mbuf *)); +int in_ifadown __P((struct ifaddr *ifa)); +void in_ifscrub __P((struct ifnet *, struct in_ifaddr *)); #endif /* KERNEL */ diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 5f595b5..75a60fc 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -186,6 +186,7 @@ struct mbuf * ip_srcroute __P((void)); void ip_stripoptions __P((struct mbuf *, struct mbuf *)); int rip_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); +void rip_ctlinput __P((int, struct sockaddr *, void *)); void rip_init __P((void)); void rip_input __P((struct mbuf *, int)); int rip_output __P((struct mbuf *, struct socket *, u_long)); diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index c5382e0..0011ab2 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 - * $FreeBSD$ + * $Id$ */ #include <sys/param.h> @@ -314,6 +314,68 @@ rip_ctloutput(op, so, level, optname, m) return (ip_ctloutput(op, so, level, optname, m)); } +/* + * This function exists solely to receive the PRC_IFDOWN messages which + * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa, + * and calls in_ifadown() to remove all routes corresponding to that address. + * It also receives the PRC_IFUP messages from if_up() and reinstalls the + * interface routes. + */ +void +rip_ctlinput(cmd, sa, vip) + int cmd; + struct sockaddr *sa; + void *vip; +{ + struct in_ifaddr *ia; + struct ifnet *ifp; + int err; + int flags; + + switch(cmd) { + case PRC_IFDOWN: + for (ia = in_ifaddrhead.tqh_first; ia; + ia = ia->ia_link.tqe_next) { + if (ia->ia_ifa.ifa_addr == sa + && (ia->ia_flags & IFA_ROUTE)) { + /* + * in_ifscrub kills the interface route. + */ + in_ifscrub(ia->ia_ifp, ia); + /* + * in_ifadown gets rid of all the rest of + * the routes. This is not quite the right + * thing to do, but at least if we are running + * a routing process they will come back. + */ + in_ifadown(&ia->ia_ifa); + break; + } + } + break; + + case PRC_IFUP: + for (ia = in_ifaddrhead.tqh_first; ia; + ia = ia->ia_link.tqe_next) { + if (ia->ia_ifa.ifa_addr == sa) + break; + } + if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) + return; + flags = RTF_UP; + ifp = ia->ia_ifa.ifa_ifp; + + if ((ifp->if_flags & IFF_LOOPBACK) + || (ifp->if_flags & IFF_POINTOPOINT)) + flags |= RTF_HOST; + + err = rtinit(&ia->ia_ifa, RTM_ADD, flags); + if (err == 0) + ia->ia_flags |= IFA_ROUTE; + break; + } +} + static u_long rip_sendspace = RIPSNDQ; /* XXX sysctl ? */ static u_long rip_recvspace = RIPRCVQ; /* XXX sysctl ? */ |