sctp: Fix malformed "Invalid Stream Identifier" error
Vlad Yasevich [Mon, 23 Nov 2009 20:53:56 +0000 (15:53 -0500)]
The "Invalid Stream Identifier" error has a 16 bit reserved
field at the end, thus making the parameter length be 8 bytes.
We've never supplied that reserved field making wireshark
tag the packet as malformed.

Reported-by: Chris Dischino <cdischino@sonusnet.com>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>

include/net/sctp/sm.h
net/sctp/sm_make_chunk.c
net/sctp/sm_statefuns.c

index c1dd893..851c813 100644 (file)
@@ -243,7 +243,8 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *,
                                 const struct sctp_chunk *chunk,
                                 __be16 cause_code,
                                 const void *payload,
-                                size_t paylen);
+                                size_t paylen,
+                                size_t reserve_tail);
 
 struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
                                              union sctp_addr *,
index 9d881a6..9e73291 100644 (file)
@@ -987,7 +987,10 @@ static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
 
        target = skb_put(chunk->skb, len);
 
-       memcpy(target, data, len);
+       if (data)
+               memcpy(target, data, len);
+       else
+               memset(target, 0, len);
 
        /* Adjust the chunk length field.  */
        chunk->chunk_hdr->length = htons(chunklen + len);
@@ -1129,16 +1132,18 @@ nodata:
 struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
                                 const struct sctp_chunk *chunk,
                                 __be16 cause_code, const void *payload,
-                                size_t paylen)
+                                size_t paylen, size_t reserve_tail)
 {
        struct sctp_chunk *retval;
 
-       retval = sctp_make_op_error_space(asoc, chunk, paylen);
+       retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail);
        if (!retval)
                goto nodata;
 
-       sctp_init_cause(retval, cause_code, paylen);
+       sctp_init_cause(retval, cause_code, paylen + reserve_tail);
        sctp_addto_chunk(retval, paylen, payload);
+       if (reserve_tail)
+               sctp_addto_param(retval, reserve_tail, NULL);
 
 nodata:
        return retval;
index 8ee24c9..16a6035 100644 (file)
@@ -1720,7 +1720,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
 
                err = sctp_make_op_error(asoc, chunk,
                                         SCTP_ERROR_COOKIE_IN_SHUTDOWN,
-                                        NULL, 0);
+                                        NULL, 0, 0);
                if (err)
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(err));
@@ -3977,7 +3977,7 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep,
                        err_chunk = sctp_make_op_error(asoc, chunk,
                                                        SCTP_ERROR_UNSUP_HMAC,
                                                        &auth_hdr->hmac_id,
-                                                       sizeof(__u16));
+                                                       sizeof(__u16), 0);
                        if (err_chunk) {
                                sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                                SCTP_CHUNK(err_chunk));
@@ -4069,7 +4069,8 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
                hdr = unk_chunk->chunk_hdr;
                err_chunk = sctp_make_op_error(asoc, unk_chunk,
                                               SCTP_ERROR_UNKNOWN_CHUNK, hdr,
-                                              WORD_ROUND(ntohs(hdr->length)));
+                                              WORD_ROUND(ntohs(hdr->length)),
+                                              0);
                if (err_chunk) {
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(err_chunk));
@@ -4088,7 +4089,8 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
                hdr = unk_chunk->chunk_hdr;
                err_chunk = sctp_make_op_error(asoc, unk_chunk,
                                               SCTP_ERROR_UNKNOWN_CHUNK, hdr,
-                                              WORD_ROUND(ntohs(hdr->length)));
+                                              WORD_ROUND(ntohs(hdr->length)),
+                                              0);
                if (err_chunk) {
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(err_chunk));
@@ -6052,7 +6054,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
 
                err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
                                         &data_hdr->stream,
-                                        sizeof(data_hdr->stream));
+                                        sizeof(data_hdr->stream),
+                                        sizeof(u16));
                if (err)
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(err));