changeset 6979:c28789e83536

6709252 DL_{EN,DIS}ABMULTI_REQs can still trigger ASSERT() in ill_move_to_new_ipsq() 6715867 ip_rput_dlpi() could be simplified a bit
author meem
date Sat, 28 Jun 2008 01:47:43 -0700
parents 75d541818603
children f9acf54be1af
files usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip/ip_multi.c
diffstat 2 files changed, 110 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip/ip.c	Fri Jun 27 21:26:48 2008 -0700
+++ b/usr/src/uts/common/inet/ip/ip.c	Sat Jun 28 01:47:43 2008 -0700
@@ -15451,91 +15451,75 @@
 {
 	dl_ok_ack_t	*dloa = (dl_ok_ack_t *)mp->b_rptr;
 	dl_error_ack_t	*dlea = (dl_error_ack_t *)dloa;
-	ill_t		*ill = (ill_t *)q->q_ptr;
-	boolean_t	pending;
+	ill_t		*ill = q->q_ptr;
+	t_uscalar_t	prim = dloa->dl_primitive;
+	t_uscalar_t	reqprim = DL_PRIM_INVAL;
 
 	ip1dbg(("ip_rput_dlpi"));
-	if (dloa->dl_primitive == DL_ERROR_ACK) {
-		ip2dbg(("ip_rput_dlpi(%s): DL_ERROR_ACK %s (0x%x): "
-		    "%s (0x%x), unix %u\n", ill->ill_name,
-		    dl_primstr(dlea->dl_error_primitive),
-		    dlea->dl_error_primitive,
-		    dl_errstr(dlea->dl_errno),
-		    dlea->dl_errno,
-		    dlea->dl_unix_errno));
-	}
 
 	/*
 	 * If we received an ACK but didn't send a request for it, then it
 	 * can't be part of any pending operation; discard up-front.
 	 */
-	switch (dloa->dl_primitive) {
-	case DL_NOTIFY_IND:
-		pending = B_TRUE;
-		break;
+	switch (prim) {
 	case DL_ERROR_ACK:
-		pending = ill_dlpi_pending(ill, dlea->dl_error_primitive);
+		reqprim = dlea->dl_error_primitive;
+		ip2dbg(("ip_rput_dlpi(%s): DL_ERROR_ACK for %s (0x%x): %s "
+		    "(0x%x), unix %u\n", ill->ill_name, dl_primstr(reqprim),
+		    reqprim, dl_errstr(dlea->dl_errno), dlea->dl_errno,
+		    dlea->dl_unix_errno));
 		break;
 	case DL_OK_ACK:
-		pending = ill_dlpi_pending(ill, dloa->dl_correct_primitive);
+		reqprim = dloa->dl_correct_primitive;
 		break;
 	case DL_INFO_ACK:
-		pending = ill_dlpi_pending(ill, DL_INFO_REQ);
+		reqprim = DL_INFO_REQ;
 		break;
 	case DL_BIND_ACK:
-		pending = ill_dlpi_pending(ill, DL_BIND_REQ);
+		reqprim = DL_BIND_REQ;
 		break;
 	case DL_PHYS_ADDR_ACK:
-		pending = ill_dlpi_pending(ill, DL_PHYS_ADDR_REQ);
+		reqprim = DL_PHYS_ADDR_REQ;
 		break;
 	case DL_NOTIFY_ACK:
-		pending = ill_dlpi_pending(ill, DL_NOTIFY_REQ);
+		reqprim = DL_NOTIFY_REQ;
 		break;
 	case DL_CONTROL_ACK:
-		pending = ill_dlpi_pending(ill, DL_CONTROL_REQ);
+		reqprim = DL_CONTROL_REQ;
 		break;
 	case DL_CAPABILITY_ACK:
-		pending = ill_dlpi_pending(ill, DL_CAPABILITY_REQ);
-		break;
-	default:
-		/* Not a DLPI message we support or were expecting */
-		freemsg(mp);
-		return;
-	}
-
-	if (!pending) {
-		freemsg(mp);
-		return;
-	}
-
-	switch (dloa->dl_primitive) {
-	case DL_ERROR_ACK:
-		if (dlea->dl_error_primitive == DL_UNBIND_REQ) {
-			mutex_enter(&ill->ill_lock);
-			ill->ill_state_flags &= ~ILL_DL_UNBIND_IN_PROGRESS;
-			cv_signal(&ill->ill_cv);
-			mutex_exit(&ill->ill_lock);
-		}
-		break;
-
-	case DL_OK_ACK:
-		ip1dbg(("ip_rput: DL_OK_ACK for %s\n",
-		    dl_primstr((int)dloa->dl_correct_primitive)));
-		switch (dloa->dl_correct_primitive) {
-		case DL_UNBIND_REQ:
-			mutex_enter(&ill->ill_lock);
-			ill->ill_state_flags &= ~ILL_DL_UNBIND_IN_PROGRESS;
-			cv_signal(&ill->ill_cv);
-			mutex_exit(&ill->ill_lock);
-			break;
-
-		case DL_ENABMULTI_REQ:
+		reqprim = DL_CAPABILITY_REQ;
+		break;
+	}
+
+	if (prim != DL_NOTIFY_IND) {
+		if (reqprim == DL_PRIM_INVAL ||
+		    !ill_dlpi_pending(ill, reqprim)) {
+			/* Not a DLPI message we support or expected */
+			freemsg(mp);
+			return;
+		}
+		ip1dbg(("ip_rput: received %s for %s\n", dl_primstr(prim),
+		    dl_primstr(reqprim)));
+	}
+
+	switch (reqprim) {
+	case DL_UNBIND_REQ:
+		/*
+		 * NOTE: we mark the unbind as complete even if we got a
+		 * DL_ERROR_ACK, since there's not much else we can do.
+		 */
+		mutex_enter(&ill->ill_lock);
+		ill->ill_state_flags &= ~ILL_DL_UNBIND_IN_PROGRESS;
+		cv_signal(&ill->ill_cv);
+		mutex_exit(&ill->ill_lock);
+		break;
+
+	case DL_ENABMULTI_REQ:
+		if (prim == DL_OK_ACK) {
 			if (ill->ill_dlpi_multicast_state == IDS_INPROGRESS)
 				ill->ill_dlpi_multicast_state = IDS_OK;
-			break;
-		}
-		break;
-	default:
+		}
 		break;
 	}
 
@@ -15551,7 +15535,7 @@
 	 * refcount without doing ILL_CAN_LOOKUP().
 	 */
 	ill_refhold(ill);
-	if (dloa->dl_primitive == DL_NOTIFY_IND)
+	if (prim == DL_NOTIFY_IND)
 		qwriter_ip(ill, q, mp, ip_rput_dlpi_writer, NEW_OP, B_FALSE);
 	else
 		qwriter_ip(ill, q, mp, ip_rput_dlpi_writer, CUR_OP, B_FALSE);
@@ -15610,9 +15594,13 @@
 		    dl_primstr(dlea->dl_error_primitive)));
 
 		switch (dlea->dl_error_primitive) {
+		case DL_DISABMULTI_REQ:
+			if (!ill->ill_isv6)
+				ipsq_current_finish(ipsq);
+			ill_dlpi_done(ill, dlea->dl_error_primitive);
+			break;
 		case DL_PROMISCON_REQ:
 		case DL_PROMISCOFF_REQ:
-		case DL_DISABMULTI_REQ:
 		case DL_UNBIND_REQ:
 		case DL_ATTACH_REQ:
 		case DL_INFO_REQ:
@@ -15697,6 +15685,8 @@
 			}
 			break;
 		case DL_ENABMULTI_REQ:
+			if (!ill->ill_isv6)
+				ipsq_current_finish(ipsq);
 			ill_dlpi_done(ill, DL_ENABMULTI_REQ);
 
 			if (ill->ill_dlpi_multicast_state == IDS_INPROGRESS)
@@ -16214,10 +16204,14 @@
 		    dl_primstr((int)dloa->dl_correct_primitive),
 		    dloa->dl_correct_primitive));
 		switch (dloa->dl_correct_primitive) {
+		case DL_ENABMULTI_REQ:
+		case DL_DISABMULTI_REQ:
+			if (!ill->ill_isv6)
+				ipsq_current_finish(ipsq);
+			ill_dlpi_done(ill, dloa->dl_correct_primitive);
+			break;
 		case DL_PROMISCON_REQ:
 		case DL_PROMISCOFF_REQ:
-		case DL_ENABMULTI_REQ:
-		case DL_DISABMULTI_REQ:
 		case DL_UNBIND_REQ:
 		case DL_ATTACH_REQ:
 			ill_dlpi_done(ill, dloa->dl_correct_primitive);
--- a/usr/src/uts/common/inet/ip/ip_multi.c	Fri Jun 27 21:26:48 2008 -0700
+++ b/usr/src/uts/common/inet/ip/ip_multi.c	Sat Jun 28 01:47:43 2008 -0700
@@ -1331,9 +1331,8 @@
 }
 
 /*
- * Create a dlpi message with room for phys+sap. When we come back in
- * ip_wput_ctl() we will strip the sap for those primitives which
- * only need a physical address.
+ * Create a DLPI message; for DL_{ENAB,DISAB}MULTI_REQ, room is left for
+ * the hardware address.
  */
 static mblk_t *
 ill_create_dl(ill_t *ill, uint32_t dl_primitive, uint32_t length,
@@ -1407,41 +1406,61 @@
 	return (mp);
 }
 
-void
-ip_wput_ctl(queue_t *q, mblk_t *mp_orig)
+/*
+ * Writer processing for ip_wput_ctl(): send the DL_{ENAB,DISAB}MULTI_REQ
+ * messages that had been delayed until we'd heard back from ARP.  One catch:
+ * we need to ensure that no one else becomes writer on the IPSQ before we've
+ * received the replies, or they'll incorrectly process our replies as part of
+ * their unrelated IPSQ operation.  To do this, we start a new IPSQ operation,
+ * which will complete when we process the reply in ip_rput_dlpi_writer().
+ */
+/* ARGSUSED */
+static void
+ip_wput_ctl_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *arg)
 {
-	ill_t	*ill = (ill_t *)q->q_ptr;
-	mblk_t	*mp = mp_orig;
+	ill_t *ill = q->q_ptr;
+	t_uscalar_t prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
+
+	ASSERT(IAM_WRITER_ILL(ill));
+	ASSERT(prim == DL_ENABMULTI_REQ || prim == DL_DISABMULTI_REQ);
+	ip1dbg(("ip_wput_ctl_writer: %s\n", dl_primstr(prim)));
+
+	if (prim == DL_ENABMULTI_REQ) {
+		/* Track the state if this is the first enabmulti */
+		if (ill->ill_dlpi_multicast_state == IDS_UNKNOWN)
+			ill->ill_dlpi_multicast_state = IDS_INPROGRESS;
+	}
+
+	ipsq_current_start(ipsq, ill->ill_ipif, 0);
+	ill_dlpi_send(ill, mp);
+}
+
+void
+ip_wput_ctl(queue_t *q, mblk_t *mp)
+{
+	ill_t	*ill = q->q_ptr;
+	mblk_t	*dlmp = mp->b_cont;
 	area_t	*area = (area_t *)mp->b_rptr;
-
-	/* Check that we have a AR_ENTRY_SQUERY with a tacked on mblk */
-	if (MBLKL(mp) < sizeof (area_t) || mp->b_cont == NULL ||
-	    area->area_cmd != AR_ENTRY_SQUERY) {
+	t_uscalar_t prim;
+
+	/* Check that we have an AR_ENTRY_SQUERY with a tacked on mblk */
+	if (MBLKL(mp) < sizeof (area_t) || area->area_cmd != AR_ENTRY_SQUERY ||
+	    dlmp == NULL) {
 		putnext(q, mp);
 		return;
 	}
-	mp = mp->b_cont;
-
-	/*
-	 * Update dl_addr_length and dl_addr_offset for primitives that
-	 * have physical addresses as opposed to full saps
-	 */
-	switch (((union DL_primitives *)mp->b_rptr)->dl_primitive) {
-	case DL_ENABMULTI_REQ:
-		/* Track the state if this is the first enabmulti */
-		if (ill->ill_dlpi_multicast_state == IDS_UNKNOWN)
-			ill->ill_dlpi_multicast_state = IDS_INPROGRESS;
-		ip1dbg(("ip_wput_ctl: ENABMULTI\n"));
-		break;
-	case DL_DISABMULTI_REQ:
-		ip1dbg(("ip_wput_ctl: DISABMULTI\n"));
-		break;
-	default:
-		ip1dbg(("ip_wput_ctl: default\n"));
-		break;
+
+	/* Check that the tacked on mblk is a DL_{DISAB,ENAB}MULTI_REQ */
+	prim = ((union DL_primitives *)dlmp->b_rptr)->dl_primitive;
+	if (prim != DL_DISABMULTI_REQ && prim != DL_ENABMULTI_REQ) {
+		putnext(q, mp);
+		return;
 	}
-	freeb(mp_orig);
-	ill_dlpi_send(ill, mp);
+	freeb(mp);
+
+	/* See comments above ip_wput_ctl_writer() for details */
+	ill_refhold(ill);
+	qwriter_ip(ill, ill->ill_wq, dlmp, ip_wput_ctl_writer, NEW_OP, B_FALSE);
 }
 
 /*