diff options
Diffstat (limited to 'net/sctp/sm_statefuns.c')
-rw-r--r-- | net/sctp/sm_statefuns.c | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index d4c3fbc4671e..1c4e5d6c29c0 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -1123,19 +1123,17 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, | |||
1123 | if (from_addr.sa.sa_family == AF_INET6) { | 1123 | if (from_addr.sa.sa_family == AF_INET6) { |
1124 | if (net_ratelimit()) | 1124 | if (net_ratelimit()) |
1125 | printk(KERN_WARNING | 1125 | printk(KERN_WARNING |
1126 | "%s association %p could not find address " | 1126 | "%s association %p could not find address %pI6\n", |
1127 | NIP6_FMT "\n", | ||
1128 | __func__, | 1127 | __func__, |
1129 | asoc, | 1128 | asoc, |
1130 | NIP6(from_addr.v6.sin6_addr)); | 1129 | &from_addr.v6.sin6_addr); |
1131 | } else { | 1130 | } else { |
1132 | if (net_ratelimit()) | 1131 | if (net_ratelimit()) |
1133 | printk(KERN_WARNING | 1132 | printk(KERN_WARNING |
1134 | "%s association %p could not find address " | 1133 | "%s association %p could not find address %pI4\n", |
1135 | NIPQUAD_FMT "\n", | ||
1136 | __func__, | 1134 | __func__, |
1137 | asoc, | 1135 | asoc, |
1138 | NIPQUAD(from_addr.v4.sin_addr.s_addr)); | 1136 | &from_addr.v4.sin_addr.s_addr); |
1139 | } | 1137 | } |
1140 | return SCTP_DISPOSITION_DISCARD; | 1138 | return SCTP_DISPOSITION_DISCARD; |
1141 | } | 1139 | } |
@@ -2544,6 +2542,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, | |||
2544 | sctp_shutdownhdr_t *sdh; | 2542 | sctp_shutdownhdr_t *sdh; |
2545 | sctp_disposition_t disposition; | 2543 | sctp_disposition_t disposition; |
2546 | struct sctp_ulpevent *ev; | 2544 | struct sctp_ulpevent *ev; |
2545 | __u32 ctsn; | ||
2547 | 2546 | ||
2548 | if (!sctp_vtag_verify(chunk, asoc)) | 2547 | if (!sctp_vtag_verify(chunk, asoc)) |
2549 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | 2548 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); |
@@ -2558,6 +2557,14 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, | |||
2558 | sdh = (sctp_shutdownhdr_t *)chunk->skb->data; | 2557 | sdh = (sctp_shutdownhdr_t *)chunk->skb->data; |
2559 | skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t)); | 2558 | skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t)); |
2560 | chunk->subh.shutdown_hdr = sdh; | 2559 | chunk->subh.shutdown_hdr = sdh; |
2560 | ctsn = ntohl(sdh->cum_tsn_ack); | ||
2561 | |||
2562 | /* If Cumulative TSN Ack beyond the max tsn currently | ||
2563 | * send, terminating the association and respond to the | ||
2564 | * sender with an ABORT. | ||
2565 | */ | ||
2566 | if (!TSN_lt(ctsn, asoc->next_tsn)) | ||
2567 | return sctp_sf_violation_ctsn(ep, asoc, type, arg, commands); | ||
2561 | 2568 | ||
2562 | /* API 5.3.1.5 SCTP_SHUTDOWN_EVENT | 2569 | /* API 5.3.1.5 SCTP_SHUTDOWN_EVENT |
2563 | * When a peer sends a SHUTDOWN, SCTP delivers this notification to | 2570 | * When a peer sends a SHUTDOWN, SCTP delivers this notification to |
@@ -2599,6 +2606,51 @@ out: | |||
2599 | return disposition; | 2606 | return disposition; |
2600 | } | 2607 | } |
2601 | 2608 | ||
2609 | /* | ||
2610 | * sctp_sf_do_9_2_shut_ctsn | ||
2611 | * | ||
2612 | * Once an endpoint has reached the SHUTDOWN-RECEIVED state, | ||
2613 | * it MUST NOT send a SHUTDOWN in response to a ULP request. | ||
2614 | * The Cumulative TSN Ack of the received SHUTDOWN chunk | ||
2615 | * MUST be processed. | ||
2616 | */ | ||
2617 | sctp_disposition_t sctp_sf_do_9_2_shut_ctsn(const struct sctp_endpoint *ep, | ||
2618 | const struct sctp_association *asoc, | ||
2619 | const sctp_subtype_t type, | ||
2620 | void *arg, | ||
2621 | sctp_cmd_seq_t *commands) | ||
2622 | { | ||
2623 | struct sctp_chunk *chunk = arg; | ||
2624 | sctp_shutdownhdr_t *sdh; | ||
2625 | |||
2626 | if (!sctp_vtag_verify(chunk, asoc)) | ||
2627 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
2628 | |||
2629 | /* Make sure that the SHUTDOWN chunk has a valid length. */ | ||
2630 | if (!sctp_chunk_length_valid(chunk, | ||
2631 | sizeof(struct sctp_shutdown_chunk_t))) | ||
2632 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
2633 | commands); | ||
2634 | |||
2635 | sdh = (sctp_shutdownhdr_t *)chunk->skb->data; | ||
2636 | |||
2637 | /* If Cumulative TSN Ack beyond the max tsn currently | ||
2638 | * send, terminating the association and respond to the | ||
2639 | * sender with an ABORT. | ||
2640 | */ | ||
2641 | if (!TSN_lt(ntohl(sdh->cum_tsn_ack), asoc->next_tsn)) | ||
2642 | return sctp_sf_violation_ctsn(ep, asoc, type, arg, commands); | ||
2643 | |||
2644 | /* verify, by checking the Cumulative TSN Ack field of the | ||
2645 | * chunk, that all its outstanding DATA chunks have been | ||
2646 | * received by the SHUTDOWN sender. | ||
2647 | */ | ||
2648 | sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN, | ||
2649 | SCTP_BE32(sdh->cum_tsn_ack)); | ||
2650 | |||
2651 | return SCTP_DISPOSITION_CONSUME; | ||
2652 | } | ||
2653 | |||
2602 | /* RFC 2960 9.2 | 2654 | /* RFC 2960 9.2 |
2603 | * If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk | 2655 | * If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk |
2604 | * (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination | 2656 | * (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination |
@@ -3637,6 +3689,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep, | |||
3637 | { | 3689 | { |
3638 | struct sctp_chunk *chunk = arg; | 3690 | struct sctp_chunk *chunk = arg; |
3639 | struct sctp_fwdtsn_hdr *fwdtsn_hdr; | 3691 | struct sctp_fwdtsn_hdr *fwdtsn_hdr; |
3692 | struct sctp_fwdtsn_skip *skip; | ||
3640 | __u16 len; | 3693 | __u16 len; |
3641 | __u32 tsn; | 3694 | __u32 tsn; |
3642 | 3695 | ||
@@ -3666,6 +3719,12 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep, | |||
3666 | if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) | 3719 | if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) |
3667 | goto discard_noforce; | 3720 | goto discard_noforce; |
3668 | 3721 | ||
3722 | /* Silently discard the chunk if stream-id is not valid */ | ||
3723 | sctp_walk_fwdtsn(skip, chunk) { | ||
3724 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | ||
3725 | goto discard_noforce; | ||
3726 | } | ||
3727 | |||
3669 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); | 3728 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); |
3670 | if (len > sizeof(struct sctp_fwdtsn_hdr)) | 3729 | if (len > sizeof(struct sctp_fwdtsn_hdr)) |
3671 | sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, | 3730 | sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, |
@@ -3697,6 +3756,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( | |||
3697 | { | 3756 | { |
3698 | struct sctp_chunk *chunk = arg; | 3757 | struct sctp_chunk *chunk = arg; |
3699 | struct sctp_fwdtsn_hdr *fwdtsn_hdr; | 3758 | struct sctp_fwdtsn_hdr *fwdtsn_hdr; |
3759 | struct sctp_fwdtsn_skip *skip; | ||
3700 | __u16 len; | 3760 | __u16 len; |
3701 | __u32 tsn; | 3761 | __u32 tsn; |
3702 | 3762 | ||
@@ -3726,6 +3786,12 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( | |||
3726 | if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) | 3786 | if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) |
3727 | goto gen_shutdown; | 3787 | goto gen_shutdown; |
3728 | 3788 | ||
3789 | /* Silently discard the chunk if stream-id is not valid */ | ||
3790 | sctp_walk_fwdtsn(skip, chunk) { | ||
3791 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | ||
3792 | goto gen_shutdown; | ||
3793 | } | ||
3794 | |||
3729 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); | 3795 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); |
3730 | if (len > sizeof(struct sctp_fwdtsn_hdr)) | 3796 | if (len > sizeof(struct sctp_fwdtsn_hdr)) |
3731 | sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, | 3797 | sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, |