aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/sm_make_chunk.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
-rw-r--r--net/sctp/sm_make_chunk.c99
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. */
3114int sctp_verify_asconf(const struct sctp_association *asoc, 3114bool 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,
3162struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, 3175struct 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
3234done: 3245done:
3235 asoc->peer.addip_serial++; 3246 asoc->peer.addip_serial++;
3236 3247