Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Dec 2012 13:01:58 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r244678 - in head/sys: netinet netinet6
Message-ID:  <201212251301.qBPD1wfA059212@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Tue Dec 25 13:01:58 2012
New Revision: 244678
URL: http://svnweb.freebsd.org/changeset/base/244678

Log:
    The SIOCSIFFLAGS ioctl handler runs if_up()/if_down() that notify
  all interested parties in case if interface flag IFF_UP has changed.
  
    However, not only SIOCSIFFLAGS can raise the flag, but SIOCAIFADDR
  and SIOCAIFADDR_IN6 can, too. The actual |= is done not in the protocol
  code, but in code of interface drivers. To fix this historical layering
  violation, we will check whether ifp->if_ioctl(SIOCSIFADDR) raised the
  IFF_UP flag, and if it did, run the if_up() handler.
  
    This fixes configuring an address under CARP control on an interface
  that was initially !IFF_UP.
  
  P.S. I intentionally omitted handling the IFF_SMART flag. This flag was
  never ever used in any driver since it was introduced, and since it
  means another layering violation, it should be garbage collected instead
  of pretended to be supported.

Modified:
  head/sys/netinet/in.c
  head/sys/netinet6/in6.c

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c	Tue Dec 25 13:00:19 2012	(r244677)
+++ head/sys/netinet/in.c	Tue Dec 25 13:01:58 2012	(r244678)
@@ -819,14 +819,19 @@ in_ifinit(struct ifnet *ifp, struct in_i
 		return (error);
 
 	/*
-	 * Give the interface a chance to initialize
-	 * if this is its first address,
-	 * and to validate the address if necessary.
+	 * Give the interface a chance to initialize if this is its first
+	 * address, and to validate the address if necessary.
+	 *
+	 * Historically, drivers managed IFF_UP flag theirselves, so we
+	 * need to check whether driver did that.
 	 */
+	flags = ifp->if_flags;
 	if (ifp->if_ioctl != NULL &&
 	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) != 0)
 			/* LIST_REMOVE(ia, ia_hash) is done in in_control */
 			return (error);
+	if ((ifp->if_flags & IFF_UP) && (flags & IFF_UP) == 0)
+		if_up(ifp);
 
 	/*
 	 * Be compatible with network classes, if netmask isn't supplied,

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Tue Dec 25 13:00:19 2012	(r244677)
+++ head/sys/netinet6/in6.c	Tue Dec 25 13:01:58 2012	(r244678)
@@ -1874,9 +1874,18 @@ in6_ifinit(struct ifnet *ifp, struct in6
 	ia->ia_addr = *sin6;
 
 	if (ifacount <= 1 && ifp->if_ioctl) {
+		int flags;
+
+		/*
+		 * Historically, drivers managed IFF_UP flag theirselves, so we
+		 * need to check whether driver did that.
+		 */
+		flags = ifp->if_flags;
 		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
 		if (error)
 			return (error);
+		if ((ifp->if_flags & IFF_UP) && (flags & IFF_UP) == 0)
+			if_up(ifp);
 	}
 
 	ia->ia_ifa.ifa_metric = ifp->if_metric;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201212251301.qBPD1wfA059212>