Author: tuexen Date: Sun May 13 22:27:54 2012 New Revision: 235418 URL: http://svn.freebsd.org/changeset/base/235418
Log: Support SCTP_REMOTE_ERROR notification. MFC after: 3 days Modified: head/sys/netinet/sctp_constants.h head/sys/netinet/sctp_input.c head/sys/netinet/sctputil.c Modified: head/sys/netinet/sctp_constants.h ============================================================================== --- head/sys/netinet/sctp_constants.h Sun May 13 20:28:43 2012 (r235417) +++ head/sys/netinet/sctp_constants.h Sun May 13 22:27:54 2012 (r235418) @@ -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: head/sys/netinet/sctp_input.c ============================================================================== --- head/sys/netinet/sctp_input.c Sun May 13 20:28:43 2012 (r235417) +++ head/sys/netinet/sctp_input.c Sun May 13 22:27:54 2012 (r235418) @@ -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: head/sys/netinet/sctputil.c ============================================================================== --- head/sys/netinet/sctputil.c Sun May 13 20:28:43 2012 (r235417) +++ head/sys/netinet/sctputil.c Sun May 13 22:27:54 2012 (r235418) @@ -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); _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"