diff options
| -rw-r--r-- | net/sctp/sm_statefuns.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a7f18a352364..c8fae1983dd1 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -2891,6 +2891,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, | |||
| 2891 | goto discard_force; | 2891 | goto discard_force; |
| 2892 | case SCTP_IERROR_NO_DATA: | 2892 | case SCTP_IERROR_NO_DATA: |
| 2893 | goto consume; | 2893 | goto consume; |
| 2894 | case SCTP_IERROR_PROTO_VIOLATION: | ||
| 2895 | return sctp_sf_abort_violation(ep, asoc, chunk, commands, | ||
| 2896 | (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t)); | ||
| 2894 | default: | 2897 | default: |
| 2895 | BUG(); | 2898 | BUG(); |
| 2896 | } | 2899 | } |
| @@ -3001,6 +3004,9 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep, | |||
| 3001 | break; | 3004 | break; |
| 3002 | case SCTP_IERROR_NO_DATA: | 3005 | case SCTP_IERROR_NO_DATA: |
| 3003 | goto consume; | 3006 | goto consume; |
| 3007 | case SCTP_IERROR_PROTO_VIOLATION: | ||
| 3008 | return sctp_sf_abort_violation(ep, asoc, chunk, commands, | ||
| 3009 | (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t)); | ||
| 3004 | default: | 3010 | default: |
| 3005 | BUG(); | 3011 | BUG(); |
| 3006 | } | 3012 | } |
| @@ -5877,6 +5883,9 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
| 5877 | __u32 tsn; | 5883 | __u32 tsn; |
| 5878 | struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; | 5884 | struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; |
| 5879 | struct sock *sk = asoc->base.sk; | 5885 | struct sock *sk = asoc->base.sk; |
| 5886 | u16 ssn; | ||
| 5887 | u16 sid; | ||
| 5888 | u8 ordered = 0; | ||
| 5880 | 5889 | ||
| 5881 | data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; | 5890 | data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; |
| 5882 | skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); | 5891 | skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); |
| @@ -6016,8 +6025,10 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
| 6016 | */ | 6025 | */ |
| 6017 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) | 6026 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) |
| 6018 | SCTP_INC_STATS(SCTP_MIB_INUNORDERCHUNKS); | 6027 | SCTP_INC_STATS(SCTP_MIB_INUNORDERCHUNKS); |
| 6019 | else | 6028 | else { |
| 6020 | SCTP_INC_STATS(SCTP_MIB_INORDERCHUNKS); | 6029 | SCTP_INC_STATS(SCTP_MIB_INORDERCHUNKS); |
| 6030 | ordered = 1; | ||
| 6031 | } | ||
| 6021 | 6032 | ||
| 6022 | /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number | 6033 | /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number |
| 6023 | * | 6034 | * |
| @@ -6027,7 +6038,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
| 6027 | * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) | 6038 | * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) |
| 6028 | * and discard the DATA chunk. | 6039 | * and discard the DATA chunk. |
| 6029 | */ | 6040 | */ |
| 6030 | if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { | 6041 | sid = ntohs(data_hdr->stream); |
| 6042 | if (sid >= asoc->c.sinit_max_instreams) { | ||
| 6031 | /* Mark tsn as received even though we drop it */ | 6043 | /* Mark tsn as received even though we drop it */ |
| 6032 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); | 6044 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); |
| 6033 | 6045 | ||
| @@ -6040,6 +6052,18 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
| 6040 | return SCTP_IERROR_BAD_STREAM; | 6052 | return SCTP_IERROR_BAD_STREAM; |
| 6041 | } | 6053 | } |
| 6042 | 6054 | ||
| 6055 | /* Check to see if the SSN is possible for this TSN. | ||
| 6056 | * The biggest gap we can record is 4K wide. Since SSNs wrap | ||
| 6057 | * at an unsigned short, there is no way that an SSN can | ||
| 6058 | * wrap and for a valid TSN. We can simply check if the current | ||
| 6059 | * SSN is smaller then the next expected one. If it is, it wrapped | ||
| 6060 | * and is invalid. | ||
| 6061 | */ | ||
| 6062 | ssn = ntohs(data_hdr->ssn); | ||
| 6063 | if (ordered && SSN_lt(ssn, sctp_ssn_peek(&asoc->ssnmap->in, sid))) { | ||
| 6064 | return SCTP_IERROR_PROTO_VIOLATION; | ||
| 6065 | } | ||
| 6066 | |||
| 6043 | /* Send the data up to the user. Note: Schedule the | 6067 | /* Send the data up to the user. Note: Schedule the |
| 6044 | * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK | 6068 | * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK |
| 6045 | * chunk needs the updated rwnd. | 6069 | * chunk needs the updated rwnd. |
