svn commit: r237890 - stable/9/sys/netinet

Michael Tuexen tuexen at FreeBSD.org
Sun Jul 1 07:49:14 UTC 2012


Author: tuexen
Date: Sun Jul  1 07:49:14 2012
New Revision: 237890
URL: http://svn.freebsd.org/changeset/base/237890

Log:
  MFC r235418:
  Support SCTP_REMOTE_ERROR notification.

Modified:
  stable/9/sys/netinet/sctp_constants.h
  stable/9/sys/netinet/sctp_input.c
  stable/9/sys/netinet/sctputil.c
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/netinet/sctp_constants.h
==============================================================================
--- stable/9/sys/netinet/sctp_constants.h	Sun Jul  1 07:42:59 2012	(r237889)
+++ stable/9/sys/netinet/sctp_constants.h	Sun Jul  1 07:49:14 2012	(r237890)
@@ -765,6 +765,7 @@ __FBSDID("$FreeBSD$");
 #define SCTP_NOTIFY_AUTH_FREE_KEY               24
 #define SCTP_NOTIFY_NO_PEER_AUTH                25
 #define SCTP_NOTIFY_SENDER_DRY                  26
+#define SCTP_NOTIFY_REMOTE_ERROR                27
 
 /* This is the value for messages that are NOT completely
  * copied down where we will start to split the message.

Modified: stable/9/sys/netinet/sctp_input.c
==============================================================================
--- stable/9/sys/netinet/sctp_input.c	Sun Jul  1 07:42:59 2012	(r237889)
+++ stable/9/sys/netinet/sctp_input.c	Sun Jul  1 07:49:14 2012	(r237890)
@@ -1111,7 +1111,7 @@ sctp_handle_error(struct sctp_chunkhdr *
 {
 	int chklen;
 	struct sctp_paramhdr *phdr;
-	uint16_t error_type;
+	uint16_t error, error_type;
 	uint16_t error_len;
 	struct sctp_association *asoc;
 	int adjust;
@@ -1126,6 +1126,7 @@ sctp_handle_error(struct sctp_chunkhdr *
 	phdr = (struct sctp_paramhdr *)((caddr_t)ch +
 	    sizeof(struct sctp_chunkhdr));
 	chklen = ntohs(ch->chunk_length) - sizeof(struct sctp_chunkhdr);
+	error = 0;
 	while ((size_t)chklen >= sizeof(struct sctp_paramhdr)) {
 		/* Process an Error Cause */
 		error_type = ntohs(phdr->param_type);
@@ -1136,6 +1137,10 @@ sctp_handle_error(struct sctp_chunkhdr *
 			    chklen, error_len);
 			return (0);
 		}
+		if (error == 0) {
+			/* report the first error cause */
+			error = error_type;
+		}
 		switch (error_type) {
 		case SCTP_CAUSE_INVALID_STREAM:
 		case SCTP_CAUSE_MISSING_PARAM:
@@ -1252,6 +1257,7 @@ sctp_handle_error(struct sctp_chunkhdr *
 		chklen -= adjust;
 		phdr = (struct sctp_paramhdr *)((caddr_t)phdr + adjust);
 	}
+	sctp_ulp_notify(SCTP_NOTIFY_REMOTE_ERROR, stcb, error, ch, SCTP_SO_NOT_LOCKED);
 	return (0);
 }
 

Modified: stable/9/sys/netinet/sctputil.c
==============================================================================
--- stable/9/sys/netinet/sctputil.c	Sun Jul  1 07:42:59 2012	(r237889)
+++ stable/9/sys/netinet/sctputil.c	Sun Jul  1 07:49:14 2012	(r237890)
@@ -3464,6 +3464,63 @@ sctp_notify_stream_reset(struct sctp_tcb
 }
 
 
+static void
+sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk)
+{
+	struct mbuf *m_notify;
+	struct sctp_remote_error *sre;
+	struct sctp_queued_to_read *control;
+	size_t notif_len, chunk_len;
+
+	if ((stcb == NULL) ||
+	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) {
+		return;
+	}
+	if (chunk != NULL) {
+		chunk_len = htons(chunk->ch.chunk_length);
+	} else {
+		chunk_len = 0;
+	}
+	notif_len = sizeof(struct sctp_remote_error) + chunk_len;
+	m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
+	if (m_notify == NULL) {
+		/* Retry with smaller value. */
+		notif_len = sizeof(struct sctp_remote_error);
+		m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
+		if (m_notify == NULL) {
+			return;
+		}
+	}
+	SCTP_BUF_NEXT(m_notify) = NULL;
+	sre = mtod(m_notify, struct sctp_remote_error *);
+	sre->sre_type = SCTP_REMOTE_ERROR;
+	sre->sre_flags = 0;
+	sre->sre_length = sizeof(struct sctp_remote_error);
+	sre->sre_error = error;
+	sre->sre_assoc_id = sctp_get_associd(stcb);
+	if (notif_len > sizeof(struct sctp_remote_error)) {
+		memcpy(sre->sre_data, chunk, chunk_len);
+		sre->sre_length += chunk_len;
+	}
+	SCTP_BUF_LEN(m_notify) = sre->sre_length;
+	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
+	    0, 0, stcb->asoc.context, 0, 0, 0,
+	    m_notify);
+	if (control != NULL) {
+		control->length = SCTP_BUF_LEN(m_notify);
+		/* not that we need this */
+		control->tail_mbuf = m_notify;
+		control->spec_flags = M_NOTIFICATION;
+		sctp_add_to_readq(stcb->sctp_ep, stcb,
+		    control,
+		    &stcb->sctp_socket->so_rcv, 1,
+		    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+	} else {
+		sctp_m_freem(m_notify);
+	}
+}
+
+
 void
 sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
     uint32_t error, void *data, int so_locked
@@ -3634,6 +3691,9 @@ sctp_ulp_notify(uint32_t notification, s
 	case SCTP_NOTIFY_SENDER_DRY:
 		sctp_notify_sender_dry_event(stcb, so_locked);
 		break;
+	case SCTP_NOTIFY_REMOTE_ERROR:
+		sctp_notify_remote_error(stcb, error, data);
+		break;
 	default:
 		SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n",
 		    __FUNCTION__, notification, notification);


More information about the svn-src-all mailing list