- Factor out if_purgeaddrs_nolink(), which frees all non-link ifaddrs no
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 31 Dec 2007 04:58:54 +0000 (04:58 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 31 Dec 2007 04:58:54 +0000 (04:58 +0000)
  ifnet.if_addrhead
- Use above function in if_detach() and free link ifaddr manually, add some
  assertion there to make sure ifnet.if_addrhead is in sane state

Submitted-by: pavalos@
Obtained-from: FreeBSD (w/ modification)

For tap(4)
- Use if_purgeaddrs_nolink() to clean up tap's if_addrhead
- Cleaning up ifaddrs has nothing to do with current tap's mode (vmnet/tap)
- In non-vmnet mode, clear IFF_RUNNING if_flags when a tap is brought down

For tun(4)
- Use if_purgeaddrs_nolink() to clean up tun's if_addrhead
- Cleaning up ifaddrs has nothing to do with IFF_RUNNING
- in_control() is clever enough to set the RTF_HOST flags for tun, so tun
  does not need to record that dst addr has been set.  Since net/tun/if_tunvar.h
  was exposed to /usr/include "accidentally", instead of nuking TUN_DSTADDR,
  I just mark it as "unused" in comment.

sys/net/if.c
sys/net/if_var.h
sys/net/tap/if_tap.c
sys/net/tun/if_tun.c
sys/net/tun/if_tunvar.h

index 383509b..0b629ee 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)if.c        8.3 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/net/if.c,v 1.185 2004/03/13 02:35:03 brooks Exp $
- * $DragonFly: src/sys/net/if.c,v 1.58 2007/12/29 12:51:17 sephe Exp $
+ * $DragonFly: src/sys/net/if.c,v 1.59 2007/12/31 04:58:53 sephe Exp $
  */
 
 #include "opt_compat.h"
@@ -304,6 +304,44 @@ if_attachdomain1(struct ifnet *ifp)
        crit_exit();
 }
 
+/*
+ * Purge all addresses whose type is _not_ AF_LINK
+ */
+void
+if_purgeaddrs_nolink(struct ifnet *ifp)
+{
+       struct ifaddr *ifa, *next;
+
+       TAILQ_FOREACH_MUTABLE(ifa, &ifp->if_addrhead, ifa_link, next) {
+               /* Leave link ifaddr as it is */
+               if (ifa->ifa_addr->sa_family == AF_LINK)
+                       continue;
+#ifdef INET
+               /* XXX: Ugly!! ad hoc just for INET */
+               if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
+                       struct ifaliasreq ifr;
+
+                       bzero(&ifr, sizeof ifr);
+                       ifr.ifra_addr = *ifa->ifa_addr;
+                       if (ifa->ifa_dstaddr)
+                               ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
+                       if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
+                                      NULL) == 0)
+                               continue;
+               }
+#endif /* INET */
+#ifdef INET6
+               if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
+                       in6_purgeaddr(ifa);
+                       /* ifp_addrhead is already updated */
+                       continue;
+               }
+#endif /* INET6 */
+               TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
+               IFAFREE(ifa);
+       }
+}
+
 /*
  * Detach an interface, removing it from the
  * list of "active" interfaces.
@@ -311,7 +349,6 @@ if_attachdomain1(struct ifnet *ifp)
 void
 if_detach(struct ifnet *ifp)
 {
-       struct ifaddr *ifa;
        struct radix_node_head  *rnh;
        int i;
        int cpu, origcpu;
@@ -339,31 +376,18 @@ if_detach(struct ifnet *ifp)
         */
        ifp->if_lladdr = NULL;
 
-       for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
-            ifa = TAILQ_FIRST(&ifp->if_addrhead)) {
-#ifdef INET
-               /* XXX: Ugly!! ad hoc just for INET */
-               if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
-                       struct ifaliasreq ifr;
+       if_purgeaddrs_nolink(ifp);
+       if (!TAILQ_EMPTY(&ifp->if_addrhead)) {
+               struct ifaddr *ifa;
+
+               ifa = TAILQ_FIRST(&ifp->if_addrhead);
+               KASSERT(ifa->ifa_addr->sa_family == AF_LINK,
+                       ("non-link ifaddr is left on if_addrhead"));
 
-                       bzero(&ifr, sizeof ifr);
-                       ifr.ifra_addr = *ifa->ifa_addr;
-                       if (ifa->ifa_dstaddr)
-                               ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
-                       if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
-                                      NULL) == 0)
-                               continue;
-               }
-#endif /* INET */
-#ifdef INET6
-               if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
-                       in6_purgeaddr(ifa);
-                       /* ifp_addrhead is already updated */
-                       continue;
-               }
-#endif /* INET6 */
                TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
                IFAFREE(ifa);
+               KASSERT(TAILQ_EMPTY(&ifp->if_addrhead),
+                       ("there are still ifaddrs left on if_addrhead"));
        }
 
 #ifdef INET
index a39c088..5efe27a 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     From: @(#)if.h  8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/net/if_var.h,v 1.18.2.16 2003/04/15 18:11:19 fjoe Exp $
- * $DragonFly: src/sys/net/if_var.h,v 1.42 2007/10/01 12:56:36 sephe Exp $
+ * $DragonFly: src/sys/net/if_var.h,v 1.43 2007/12/31 04:58:53 sephe Exp $
  */
 
 #ifndef        _NET_IF_VAR_H_
@@ -466,6 +466,7 @@ int if_addmulti(struct ifnet *, struct sockaddr *, struct ifmultiaddr **);
 int    if_allmulti(struct ifnet *, int);
 void   if_attach(struct ifnet *, struct lwkt_serialize *);
 int    if_delmulti(struct ifnet *, struct sockaddr *);
+void   if_purgeaddrs_nolink(struct ifnet *);
 void   if_detach(struct ifnet *);
 void   if_down(struct ifnet *);
 void   if_link_state_change(struct ifnet *);
index 9149221..c2be28b 100644 (file)
@@ -32,7 +32,7 @@
 
 /*
  * $FreeBSD: src/sys/net/if_tap.c,v 1.3.2.3 2002/04/14 21:41:48 luigi Exp $
- * $DragonFly: src/sys/net/tap/if_tap.c,v 1.37 2007/09/16 17:02:49 pavalos Exp $
+ * $DragonFly: src/sys/net/tap/if_tap.c,v 1.38 2007/12/31 04:58:53 sephe Exp $
  * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
  */
 
@@ -322,36 +322,20 @@ tapclose(struct dev_close_args *ap)
         * interface, if we are in VMnet mode. just close the device.
         */
 
-       if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
-               EVENTHANDLER_INVOKE(ifnet_detach_event, ifp);
-
-               /* Announce the departure of the interface. */
-               rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
-
-               if_down(ifp);
-               lwkt_serialize_enter(ifp->if_serializer);
-               if (ifp->if_flags & IFF_RUNNING) {
-                       /* find internet addresses and delete routes */
-                       struct ifaddr   *ifa = NULL;
-
-                       TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-                               if (ifa->ifa_addr->sa_family == AF_INET) {
-                                       rtinit(ifa, (int)RTM_DELETE, 0);
-
-                                       /* remove address from interface */
-                                       bzero(ifa->ifa_addr, 
-                                                  sizeof(*(ifa->ifa_addr)));
-                                       bzero(ifa->ifa_dstaddr, 
-                                                  sizeof(*(ifa->ifa_dstaddr)));
-                                       bzero(ifa->ifa_netmask, 
-                                                  sizeof(*(ifa->ifa_netmask)));
-                               }
-                       }
-
-                       ifp->if_flags &= ~IFF_RUNNING;
+       if ((tp->tap_flags & TAP_VMNET) == 0) {
+               if (ifp->if_flags & IFF_UP) {
+                       lwkt_serialize_enter(ifp->if_serializer);
+                       if_down(ifp);
+                       lwkt_serialize_exit(ifp->if_serializer);
                }
-               lwkt_serialize_exit(ifp->if_serializer);
+               ifp->if_flags &= ~IFF_RUNNING;
        }
+       if_purgeaddrs_nolink(ifp);
+
+       EVENTHANDLER_INVOKE(ifnet_detach_event, ifp);
+
+       /* Announce the departure of the interface. */
+       rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
 
        funsetown(tp->tap_sigio);
        selwakeup(&tp->tap_rsel);
@@ -427,6 +411,9 @@ tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                                if (ifp->if_flags & IFF_UP) {
                                        if ((ifp->if_flags & IFF_RUNNING) == 0)
                                                tapifinit(tp);
+                               } else {
+                                       /* We don't have a tapifstop() */
+                                       ifp->if_flags &= ~IFF_RUNNING;
                                }
                        }
                        break;
index a9e7803..4020419 100644 (file)
@@ -14,7 +14,7 @@
  * operation though.
  *
  * $FreeBSD: src/sys/net/if_tun.c,v 1.74.2.8 2002/02/13 00:43:11 dillon Exp $
- * $DragonFly: src/sys/net/tun/if_tun.c,v 1.31 2006/12/20 18:14:42 dillon Exp $
+ * $DragonFly: src/sys/net/tun/if_tun.c,v 1.32 2007/12/31 04:58:53 sephe Exp $
  */
 
 #include "opt_atalk.h"
@@ -183,21 +183,8 @@ tunclose(struct dev_close_args *ap)
                if_down(ifp);
                lwkt_serialize_exit(ifp->if_serializer);
        }
-
-       if (ifp->if_flags & IFF_RUNNING) {
-               struct ifaddr *ifa;
-
-               lwkt_serialize_enter(ifp->if_serializer);
-               /* find internet addresses and delete routes */
-               TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-                       if (ifa->ifa_addr->sa_family == AF_INET) {
-                               rtinit(ifa, (int)RTM_DELETE,
-                                   tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
-                       }
-               }
-               ifp->if_flags &= ~IFF_RUNNING;
-               lwkt_serialize_exit(ifp->if_serializer);
-       }
+       ifp->if_flags &= ~IFF_RUNNING;
+       if_purgeaddrs_nolink(ifp);
 
        funsetown(tp->tun_sigio);
        selwakeup(&tp->tun_rsel);
@@ -231,10 +218,6 @@ tuninit(struct ifnet *ifp)
                            si = (struct sockaddr_in *)ifa->ifa_addr;
                            if (si->sin_addr.s_addr)
                                    tp->tun_flags |= TUN_IASET;
-
-                           si = (struct sockaddr_in *)ifa->ifa_dstaddr;
-                           if (si && si->sin_addr.s_addr)
-                                   tp->tun_flags |= TUN_DSTADDR;
                        }
 #endif
                }
index 17ee97f..92efa70 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/net/if_tunvar.h,v 1.7 2000/01/23 01:47:12 brian Exp $
- * $DragonFly: src/sys/net/tun/if_tunvar.h,v 1.2 2003/06/17 04:28:48 dillon Exp $
+ * $DragonFly: src/sys/net/tun/if_tunvar.h,v 1.3 2007/12/31 04:58:54 sephe Exp $
  */
 
 #ifndef _NET_IF_TUNVAR_H_
@@ -36,7 +36,7 @@ struct tun_softc {
 #define        TUN_INITED      0x0002
 #define        TUN_RCOLL       0x0004
 #define        TUN_IASET       0x0008
-#define        TUN_DSTADDR     0x0010
+#define        TUN_DSTADDR     0x0010          /* unused */
 #define        TUN_LMODE       0x0020
 #define        TUN_RWAIT       0x0040
 #define        TUN_ASYNC       0x0080