diff options
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
-rw-r--r-- | net/sctp/sm_make_chunk.c | 99 |
1 files changed, 55 insertions, 44 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index ae0e616a7ca5..ab734be8cb20 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -3110,50 +3110,63 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, | |||
3110 | return SCTP_ERROR_NO_ERROR; | 3110 | return SCTP_ERROR_NO_ERROR; |
3111 | } | 3111 | } |
3112 | 3112 | ||
3113 | /* Verify the ASCONF packet before we process it. */ | 3113 | /* Verify the ASCONF packet before we process it. */ |
3114 | int sctp_verify_asconf(const struct sctp_association *asoc, | 3114 | bool sctp_verify_asconf(const struct sctp_association *asoc, |
3115 | struct sctp_paramhdr *param_hdr, void *chunk_end, | 3115 | struct sctp_chunk *chunk, bool addr_param_needed, |
3116 | struct sctp_paramhdr **errp) { | 3116 | struct sctp_paramhdr **errp) |
3117 | sctp_addip_param_t *asconf_param; | 3117 | { |
3118 | sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) chunk->chunk_hdr; | ||
3118 | union sctp_params param; | 3119 | union sctp_params param; |
3119 | int length, plen; | 3120 | bool addr_param_seen = false; |
3120 | |||
3121 | param.v = (sctp_paramhdr_t *) param_hdr; | ||
3122 | while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) { | ||
3123 | length = ntohs(param.p->length); | ||
3124 | *errp = param.p; | ||
3125 | 3121 | ||
3126 | if (param.v > chunk_end - length || | 3122 | sctp_walk_params(param, addip, addip_hdr.params) { |
3127 | length < sizeof(sctp_paramhdr_t)) | 3123 | size_t length = ntohs(param.p->length); |
3128 | return 0; | ||
3129 | 3124 | ||
3125 | *errp = param.p; | ||
3130 | switch (param.p->type) { | 3126 | switch (param.p->type) { |
3127 | case SCTP_PARAM_ERR_CAUSE: | ||
3128 | break; | ||
3129 | case SCTP_PARAM_IPV4_ADDRESS: | ||
3130 | if (length != sizeof(sctp_ipv4addr_param_t)) | ||
3131 | return false; | ||
3132 | addr_param_seen = true; | ||
3133 | break; | ||
3134 | case SCTP_PARAM_IPV6_ADDRESS: | ||
3135 | if (length != sizeof(sctp_ipv6addr_param_t)) | ||
3136 | return false; | ||
3137 | addr_param_seen = true; | ||
3138 | break; | ||
3131 | case SCTP_PARAM_ADD_IP: | 3139 | case SCTP_PARAM_ADD_IP: |
3132 | case SCTP_PARAM_DEL_IP: | 3140 | case SCTP_PARAM_DEL_IP: |
3133 | case SCTP_PARAM_SET_PRIMARY: | 3141 | case SCTP_PARAM_SET_PRIMARY: |
3134 | asconf_param = (sctp_addip_param_t *)param.v; | 3142 | /* In ASCONF chunks, these need to be first. */ |
3135 | plen = ntohs(asconf_param->param_hdr.length); | 3143 | if (addr_param_needed && !addr_param_seen) |
3136 | if (plen < sizeof(sctp_addip_param_t) + | 3144 | return false; |
3137 | sizeof(sctp_paramhdr_t)) | 3145 | length = ntohs(param.addip->param_hdr.length); |
3138 | return 0; | 3146 | if (length < sizeof(sctp_addip_param_t) + |
3147 | sizeof(sctp_paramhdr_t)) | ||
3148 | return false; | ||
3139 | break; | 3149 | break; |
3140 | case SCTP_PARAM_SUCCESS_REPORT: | 3150 | case SCTP_PARAM_SUCCESS_REPORT: |
3141 | case SCTP_PARAM_ADAPTATION_LAYER_IND: | 3151 | case SCTP_PARAM_ADAPTATION_LAYER_IND: |
3142 | if (length != sizeof(sctp_addip_param_t)) | 3152 | if (length != sizeof(sctp_addip_param_t)) |
3143 | return 0; | 3153 | return false; |
3144 | |||
3145 | break; | 3154 | break; |
3146 | default: | 3155 | default: |
3147 | break; | 3156 | /* This is unkown to us, reject! */ |
3157 | return false; | ||
3148 | } | 3158 | } |
3149 | |||
3150 | param.v += WORD_ROUND(length); | ||
3151 | } | 3159 | } |
3152 | 3160 | ||
3153 | if (param.v != chunk_end) | 3161 | /* Remaining sanity checks. */ |
3154 | return 0; | 3162 | if (addr_param_needed && !addr_param_seen) |
3163 | return false; | ||
3164 | if (!addr_param_needed && addr_param_seen) | ||
3165 | return false; | ||
3166 | if (param.v != chunk->chunk_end) | ||
3167 | return false; | ||
3155 | 3168 | ||
3156 | return 1; | 3169 | return true; |
3157 | } | 3170 | } |
3158 | 3171 | ||
3159 | /* Process an incoming ASCONF chunk with the next expected serial no. and | 3172 | /* Process an incoming ASCONF chunk with the next expected serial no. and |
@@ -3162,16 +3175,17 @@ int sctp_verify_asconf(const struct sctp_association *asoc, | |||
3162 | struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | 3175 | struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, |
3163 | struct sctp_chunk *asconf) | 3176 | struct sctp_chunk *asconf) |
3164 | { | 3177 | { |
3178 | sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) asconf->chunk_hdr; | ||
3179 | bool all_param_pass = true; | ||
3180 | union sctp_params param; | ||
3165 | sctp_addiphdr_t *hdr; | 3181 | sctp_addiphdr_t *hdr; |
3166 | union sctp_addr_param *addr_param; | 3182 | union sctp_addr_param *addr_param; |
3167 | sctp_addip_param_t *asconf_param; | 3183 | sctp_addip_param_t *asconf_param; |
3168 | struct sctp_chunk *asconf_ack; | 3184 | struct sctp_chunk *asconf_ack; |
3169 | |||
3170 | __be16 err_code; | 3185 | __be16 err_code; |
3171 | int length = 0; | 3186 | int length = 0; |
3172 | int chunk_len; | 3187 | int chunk_len; |
3173 | __u32 serial; | 3188 | __u32 serial; |
3174 | int all_param_pass = 1; | ||
3175 | 3189 | ||
3176 | chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); | 3190 | chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); |
3177 | hdr = (sctp_addiphdr_t *)asconf->skb->data; | 3191 | hdr = (sctp_addiphdr_t *)asconf->skb->data; |
@@ -3199,9 +3213,14 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | |||
3199 | goto done; | 3213 | goto done; |
3200 | 3214 | ||
3201 | /* Process the TLVs contained within the ASCONF chunk. */ | 3215 | /* Process the TLVs contained within the ASCONF chunk. */ |
3202 | while (chunk_len > 0) { | 3216 | sctp_walk_params(param, addip, addip_hdr.params) { |
3217 | /* Skip preceeding address parameters. */ | ||
3218 | if (param.p->type == SCTP_PARAM_IPV4_ADDRESS || | ||
3219 | param.p->type == SCTP_PARAM_IPV6_ADDRESS) | ||
3220 | continue; | ||
3221 | |||
3203 | err_code = sctp_process_asconf_param(asoc, asconf, | 3222 | err_code = sctp_process_asconf_param(asoc, asconf, |
3204 | asconf_param); | 3223 | param.addip); |
3205 | /* ADDIP 4.1 A7) | 3224 | /* ADDIP 4.1 A7) |
3206 | * If an error response is received for a TLV parameter, | 3225 | * If an error response is received for a TLV parameter, |
3207 | * all TLVs with no response before the failed TLV are | 3226 | * all TLVs with no response before the failed TLV are |
@@ -3209,28 +3228,20 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | |||
3209 | * the failed response are considered unsuccessful unless | 3228 | * the failed response are considered unsuccessful unless |
3210 | * a specific success indication is present for the parameter. | 3229 | * a specific success indication is present for the parameter. |
3211 | */ | 3230 | */ |
3212 | if (SCTP_ERROR_NO_ERROR != err_code) | 3231 | if (err_code != SCTP_ERROR_NO_ERROR) |
3213 | all_param_pass = 0; | 3232 | all_param_pass = false; |
3214 | |||
3215 | if (!all_param_pass) | 3233 | if (!all_param_pass) |
3216 | sctp_add_asconf_response(asconf_ack, | 3234 | sctp_add_asconf_response(asconf_ack, param.addip->crr_id, |
3217 | asconf_param->crr_id, err_code, | 3235 | err_code, param.addip); |
3218 | asconf_param); | ||
3219 | 3236 | ||
3220 | /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add | 3237 | /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add |
3221 | * an IP address sends an 'Out of Resource' in its response, it | 3238 | * an IP address sends an 'Out of Resource' in its response, it |
3222 | * MUST also fail any subsequent add or delete requests bundled | 3239 | * MUST also fail any subsequent add or delete requests bundled |
3223 | * in the ASCONF. | 3240 | * in the ASCONF. |
3224 | */ | 3241 | */ |
3225 | if (SCTP_ERROR_RSRC_LOW == err_code) | 3242 | if (err_code == SCTP_ERROR_RSRC_LOW) |
3226 | goto done; | 3243 | goto done; |
3227 | |||
3228 | /* Move to the next ASCONF param. */ | ||
3229 | length = ntohs(asconf_param->param_hdr.length); | ||
3230 | asconf_param = (void *)asconf_param + length; | ||
3231 | chunk_len -= length; | ||
3232 | } | 3244 | } |
3233 | |||
3234 | done: | 3245 | done: |
3235 | asoc->peer.addip_serial++; | 3246 | asoc->peer.addip_serial++; |
3236 | 3247 | ||