changeset 5113:aed655dd7790

6602811 GLDv3 MAC has references to an ill after the ill is long gone
author yz147064
date Fri, 21 Sep 2007 07:56:36 -0700
parents 7fcdd39ee1af
children 0dab8b69b8f2
files usr/src/uts/common/inet/ip.h usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip/ip_if.c usr/src/uts/common/io/dld/dld_proto.c usr/src/uts/common/io/dld/dld_str.c usr/src/uts/common/sys/dld_impl.h
diffstat 6 files changed, 69 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip.h	Fri Sep 21 05:48:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip.h	Fri Sep 21 07:56:36 2007 -0700
@@ -1836,8 +1836,8 @@
 		ill_up_ipifs : 1,
 
 		ill_note_link : 1,	/* supports link-up notification */
-
-		ill_pad_to_bit_31 : 19;
+		ill_capab_reneg : 1, /* capability renegotiation to be done */
+		ill_pad_to_bit_31 : 18;
 
 	/* Following bit fields protected by ill_lock */
 	uint_t
@@ -2146,7 +2146,6 @@
 #define	IDS_INPROGRESS	1	/* DLPI request sent */
 #define	IDS_OK		2	/* DLPI request completed successfully */
 #define	IDS_FAILED	3	/* DLPI request failed */
-#define	IDS_RENEG	4	/* Driver asked for a renegotiation */
 
 /* Named Dispatch Parameter Management Structure */
 typedef struct ipparam_s {
--- a/usr/src/uts/common/inet/ip/ip.c	Fri Sep 21 05:48:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip/ip.c	Fri Sep 21 07:56:36 2007 -0700
@@ -15678,24 +15678,20 @@
 			ip_dlpi_error(ill, dlea->dl_error_primitive,
 			    dlea->dl_errno, dlea->dl_unix_errno);
 		break;
-	case DL_CAPABILITY_ACK: {
-		boolean_t reneg_flag = B_FALSE;
+	case DL_CAPABILITY_ACK:
 		/* Call a routine to handle this one. */
 		ill_dlpi_done(ill, DL_CAPABILITY_REQ);
-		/*
-		 * Check if the ACK is due to renegotiation case since we
-		 * will need to send a new CAPABILITY_REQ later.
-		 */
-		if (ill->ill_dlpi_capab_state == IDS_RENEG) {
-			/* This is the ack for a renogiation case */
-			reneg_flag = B_TRUE;
-			ill->ill_dlpi_capab_state = IDS_UNKNOWN;
-		}
 		ill_capability_ack(ill, mp);
-		if (reneg_flag)
+
+		/*
+		 * If the ack is due to renegotiation, we will need to send
+		 * a new CAPABILITY_REQ to start the renegotiation.
+		 */
+		if (ill->ill_capab_reneg) {
+			ill->ill_capab_reneg = B_FALSE;
 			ill_capability_probe(ill);
-		break;
-	}
+		}
+		break;
 	case DL_CONTROL_ACK:
 		/* We treat all of these as "fire and forget" */
 		ill_dlpi_done(ill, DL_CONTROL_REQ);
@@ -15996,17 +15992,26 @@
 			/*
 			 * Something changed on the driver side.
 			 * It wants us to renegotiate the capabilities
-			 * on this ill. The most likely cause is the
-			 * aggregation interface under us where a
-			 * port got added or went away.
-			 *
-			 * We reset the capabilities and set the
-			 * state to IDS_RENG so that when the ack
-			 * comes back, we can start the
-			 * renegotiation process.
-			 */
-			ill_capability_reset(ill);
-			ill->ill_dlpi_capab_state = IDS_RENEG;
+			 * on this ill. One possible cause is the aggregation
+			 * interface under us where a port got added or
+			 * went away.
+			 *
+			 * If the capability negotiation is already done
+			 * or is in progress, reset the capabilities and
+			 * mark the ill's ill_capab_reneg to be B_TRUE,
+			 * so that when the ack comes back, we can start
+			 * the renegotiation process.
+			 *
+			 * Note that if ill_capab_reneg is already B_TRUE
+			 * (ill_dlpi_capab_state is IDS_UNKNOWN in this case),
+			 * the capability resetting request has been sent
+			 * and the renegotiation has not been started yet;
+			 * nothing needs to be done in this case.
+			 */
+			if (ill->ill_dlpi_capab_state != IDS_UNKNOWN) {
+				ill_capability_reset(ill);
+				ill->ill_capab_reneg = B_TRUE;
+			}
 			break;
 		default:
 			ip0dbg(("ip_rput_dlpi_writer: unknown notification "
--- a/usr/src/uts/common/inet/ip/ip_if.c	Fri Sep 21 05:48:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip/ip_if.c	Fri Sep 21 07:56:36 2007 -0700
@@ -1737,11 +1737,9 @@
 ill_capability_probe(ill_t *ill)
 {
 	/*
-	 * Do so only if negotiation is enabled, capabilities are unknown,
-	 * and a capability negotiation is not already in progress.
-	 */
-	if (ill->ill_dlpi_capab_state != IDS_UNKNOWN &&
-	    ill->ill_dlpi_capab_state != IDS_RENEG)
+	 * Do so only if capabilities are still unknown.
+	 */
+	if (ill->ill_dlpi_capab_state != IDS_UNKNOWN)
 		return;
 
 	ill->ill_dlpi_capab_state = IDS_INPROGRESS;
@@ -1767,6 +1765,7 @@
 	 * features are turned off until the state reaches IDS_OK.
 	 */
 	ill->ill_dlpi_capab_state = IDS_UNKNOWN;
+	ill->ill_capab_reneg = B_FALSE;
 
 	/*
 	 * Disable sub-capabilities and request a list of sub-capability
@@ -18143,8 +18142,20 @@
 		mutex_enter(&ill->ill_lock);
 		ill->ill_state_flags |= ILL_DL_UNBIND_IN_PROGRESS;
 		mutex_exit(&ill->ill_lock);
-		if (ill->ill_dlpi_capab_state == IDS_OK)
+		/*
+		 * Reset the capabilities if the negotiation is done or is
+		 * still in progress. Note that ill_capability_reset() will
+		 * set ill_dlpi_capab_state to IDS_UNKNOWN, so the subsequent
+		 * DL_CAPABILITY_ACK and DL_NOTE_CAPAB_RENEG will be ignored.
+		 *
+		 * Further, reset ill_capab_reneg to be B_FALSE so that the
+		 * subsequent DL_CAPABILITY_ACK can be ignored, to prevent
+		 * the capabilities renegotiation from happening.
+		 */
+		if (ill->ill_dlpi_capab_state != IDS_UNKNOWN)
 			ill_capability_reset(ill);
+		ill->ill_capab_reneg = B_FALSE;
+
 		ill_dlpi_send(ill, mp);
 	}
 
--- a/usr/src/uts/common/io/dld/dld_proto.c	Fri Sep 21 05:48:44 2007 -0700
+++ b/usr/src/uts/common/io/dld/dld_proto.c	Fri Sep 21 07:56:36 2007 -0700
@@ -1692,7 +1692,7 @@
 
 	if (type == SOFT_RING_NONE) {
 		rx = (dsp->ds_mode == DLD_FASTPATH) ?
-			    dld_str_rx_fastpath : dld_str_rx_unitdata;
+		    dld_str_rx_fastpath : dld_str_rx_unitdata;
 	} else {
 		rx = (dls_rx_t)dls_soft_ring_fanout;
 	}
@@ -1734,7 +1734,7 @@
 	 */
 	if (!(dld_opt & DLD_OPT_NO_SOFTRING)) {
 		subsize += sizeof (dl_capability_sub_t) +
-				    sizeof (dl_capab_dls_t);
+		    sizeof (dl_capab_dls_t);
 	}
 
 	/*
@@ -1943,3 +1943,16 @@
 	qreply(q, mp);
 	return (B_TRUE);
 }
+
+/*
+ * Disable any enabled capabilities.
+ */
+void
+dld_capabilities_disable(dld_str_t *dsp)
+{
+	if (dsp->ds_polling)
+		proto_poll_disable(dsp);
+
+	if (dsp->ds_soft_ring)
+		proto_soft_ring_disable(dsp);
+}
--- a/usr/src/uts/common/io/dld/dld_str.c	Fri Sep 21 05:48:44 2007 -0700
+++ b/usr/src/uts/common/io/dld/dld_str.c	Fri Sep 21 07:56:36 2007 -0700
@@ -1098,10 +1098,11 @@
 	mac_notify_remove(dsp->ds_mh, dsp->ds_mnh);
 
 	/*
-	 * Clear the polling and promisc flags.
+	 * Disable the capabilities and clear the promisc flag.
 	 */
-	dsp->ds_polling = B_FALSE;
-	dsp->ds_soft_ring = B_FALSE;
+	ASSERT(!dsp->ds_polling);
+	ASSERT(!dsp->ds_soft_ring);
+	dld_capabilities_disable(dsp);
 	dsp->ds_promisc = 0;
 
 	/*
--- a/usr/src/uts/common/sys/dld_impl.h	Fri Sep 21 05:48:44 2007 -0700
+++ b/usr/src/uts/common/sys/dld_impl.h	Fri Sep 21 07:56:36 2007 -0700
@@ -243,6 +243,7 @@
  */
 extern void		dld_proto(dld_str_t *, mblk_t *);
 extern void		dld_finish_pending_ops(dld_str_t *);
+extern void		dld_capabilities_disable(dld_str_t *);
 
 /*
  * Options: there should be a separate bit defined here for each