diff --git a/src/add-ons/kernel/network/core/core_private.h b/src/add-ons/kernel/network/core/core_private.h index f46ed511fc..8b3647b07f 100644 --- a/src/add-ons/kernel/network/core/core_private.h +++ b/src/add-ons/kernel/network/core/core_private.h @@ -2,6 +2,11 @@ #define _CORE_PRIVATE__H +struct ifnet; + +void in_if_detach(struct ifnet *ifp); + // this removes all IP related references for this interface (route, address) + extern struct pool_ctl *mbpool; extern struct pool_ctl *clpool; diff --git a/src/add-ons/kernel/network/core/if.c b/src/add-ons/kernel/network/core/if.c index ef69e2688e..cd9b6f6fba 100644 --- a/src/add-ons/kernel/network/core/if.c +++ b/src/add-ons/kernel/network/core/if.c @@ -10,6 +10,7 @@ #define printf dprintf #endif +#include "core_private.h" #include "netinet/in.h" #include "sys/socketvar.h" #include "net/if.h" @@ -399,6 +400,8 @@ void if_attach(struct ifnet *ifp) void if_detach(struct ifnet *ifp) { struct ifnet *p = devices, *q = NULL; + int32 index; + bool found = false; for(; p && p != ifp; p = p->if_next) q = p; @@ -406,6 +409,26 @@ void if_detach(struct ifnet *ifp) if(!p) return; + // XXX: this is a hack, but we don't want to invest too much work into this stack + in_if_detach(ifp); + // this should also remove all remaining routes + + // remove the ifa entry from ifnet_addrs and reduce all following ifnet indices + for(index = 0; index < if_index; index++) { + if(found) { + --ifnet_addrs[index]->ifa_ifp->if_index; + ifnet_addrs[index - 1] = ifnet_addrs[index]; + } + + if(ifnet_addrs[index]->ifa_ifp == ifp) { + found = true; + free(ifnet_addrs[index]); + } + } + + if(found) + --if_index; + if(q) q->if_next = p->if_next; else diff --git a/src/add-ons/kernel/network/core/in.c b/src/add-ons/kernel/network/core/in.c index 97a812cea0..56eb29bdec 100644 --- a/src/add-ons/kernel/network/core/in.c +++ b/src/add-ons/kernel/network/core/in.c @@ -9,6 +9,8 @@ #include #include +#include "core_private.h" + #ifdef _KERNEL_MODE #include #define printf dprintf @@ -23,6 +25,7 @@ struct in_ifaddr *get_primary_addr(void) return in_ifaddr; } + /* * Trim a mask in a sockaddr */ @@ -39,9 +42,60 @@ void in_socktrim(struct sockaddr_in *ap) } } + #define rtinitflags(x) \ ((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \ ? RTF_HOST : 0) + +void +in_if_detach(struct ifnet *ifp) +{ + // remove all references to this ifnet + struct in_ifaddr *ia = NULL, *previous = NULL; + struct ifaddr *ifa; + + if(!ifp || !in_ifaddr) + return; + + if(in_ifaddr->ia_ifp == ifp) + ia = in_ifaddr; + else { + for(previous = in_ifaddr; previous && previous->ia_next; + previous = previous->ia_next) + if(previous->ia_next->ia_ifp == ifp) { + ia = previous->ia_next; + break; + } + } + + if(!ia) + return; + + if(rtinit(&(ia->ia_ifa), RTM_DELETE, rtinitflags(ia))) + printf("core.c.: in_if_detach(): Could not delete route!\n"); + + if(ifp->if_addrlist) { + ifa = ifp->if_addrlist; + if(ifa->ifa_addr->sa_family == AF_INET) + ifp->if_addrlist = ifa->ifa_next; + else + for(; ifa; ifa = ifa->ifa_next) + if(ifa->ifa_next && ifa->ifa_next->ifa_addr->sa_family == AF_INET) { + struct ifaddr *tmp = ifa; + ifa = ifa->ifa_next; + tmp->ifa_next = ifa->ifa_next; + } + + if(ifa) + free(ifa); + } + + if(previous) + previous->ia_next = ia->ia_next; + else + in_ifaddr = ia->ia_next; +} + /* * remove a route to prefix ("connected route" in cisco terminology). * re-installs the route by using another interface address, if there's one @@ -193,12 +247,12 @@ int in_control(struct socket *so, int cmd, caddr_t data, struct ifnet *ifp) struct sockaddr_in oldaddr; int error = 0, hostIsNew, maskIsNew; long i; - + if (ifp) /* we need to find the in_ifaddr */ - for (ia = in_ifaddr;ia; ia = ia->ia_next) + for (ia = in_ifaddr; ia; ia = ia->ia_next) if (ia->ia_ifp == ifp) break; - + switch (cmd) { case SIOCAIFADDR: printf("SIOCAIFADDR\n");