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"

Reply via email to