diff options
Diffstat (limited to 'net/sctp/sm_statefuns.c')
-rw-r--r-- | net/sctp/sm_statefuns.c | 64 |
1 files changed, 42 insertions, 22 deletions
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index b6aaa7e97d82..a1be9d93f1a8 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -3402,48 +3402,68 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, | |||
3402 | 3402 | ||
3403 | /* Verify the ASCONF chunk before processing it. */ | 3403 | /* Verify the ASCONF chunk before processing it. */ |
3404 | if (!sctp_verify_asconf(asoc, | 3404 | if (!sctp_verify_asconf(asoc, |
3405 | (sctp_paramhdr_t *)((void *)addr_param + length), | 3405 | (sctp_paramhdr_t *)((void *)addr_param + length), |
3406 | (void *)chunk->chunk_end, | 3406 | (void *)chunk->chunk_end, |
3407 | &err_param)) | 3407 | &err_param)) |
3408 | return sctp_sf_violation_paramlen(ep, asoc, type, | 3408 | return sctp_sf_violation_paramlen(ep, asoc, type, |
3409 | (void *)&err_param, commands); | 3409 | (void *)&err_param, commands); |
3410 | 3410 | ||
3411 | /* ADDIP 4.2 C1) Compare the value of the serial number to the value | 3411 | /* ADDIP 5.2 E1) Compare the value of the serial number to the value |
3412 | * the endpoint stored in a new association variable | 3412 | * the endpoint stored in a new association variable |
3413 | * 'Peer-Serial-Number'. | 3413 | * 'Peer-Serial-Number'. |
3414 | */ | 3414 | */ |
3415 | if (serial == asoc->peer.addip_serial + 1) { | 3415 | if (serial == asoc->peer.addip_serial + 1) { |
3416 | /* ADDIP 4.2 C2) If the value found in the serial number is | 3416 | /* If this is the first instance of ASCONF in the packet, |
3417 | * equal to the ('Peer-Serial-Number' + 1), the endpoint MUST | 3417 | * we can clean our old ASCONF-ACKs. |
3418 | * do V1-V5. | 3418 | */ |
3419 | if (!chunk->has_asconf) | ||
3420 | sctp_assoc_clean_asconf_ack_cache(asoc); | ||
3421 | |||
3422 | /* ADDIP 5.2 E4) When the Sequence Number matches the next one | ||
3423 | * expected, process the ASCONF as described below and after | ||
3424 | * processing the ASCONF Chunk, append an ASCONF-ACK Chunk to | ||
3425 | * the response packet and cache a copy of it (in the event it | ||
3426 | * later needs to be retransmitted). | ||
3427 | * | ||
3428 | * Essentially, do V1-V5. | ||
3419 | */ | 3429 | */ |
3420 | asconf_ack = sctp_process_asconf((struct sctp_association *) | 3430 | asconf_ack = sctp_process_asconf((struct sctp_association *) |
3421 | asoc, chunk); | 3431 | asoc, chunk); |
3422 | if (!asconf_ack) | 3432 | if (!asconf_ack) |
3423 | return SCTP_DISPOSITION_NOMEM; | 3433 | return SCTP_DISPOSITION_NOMEM; |
3424 | } else if (serial == asoc->peer.addip_serial) { | 3434 | } else if (serial < asoc->peer.addip_serial + 1) { |
3425 | /* ADDIP 4.2 C3) If the value found in the serial number is | 3435 | /* ADDIP 5.2 E2) |
3426 | * equal to the value stored in the 'Peer-Serial-Number' | 3436 | * If the value found in the Sequence Number is less than the |
3427 | * IMPLEMENTATION NOTE: As an optimization a receiver may wish | 3437 | * ('Peer- Sequence-Number' + 1), simply skip to the next |
3428 | * to save the last ASCONF-ACK for some predetermined period of | 3438 | * ASCONF, and include in the outbound response packet |
3429 | * time and instead of re-processing the ASCONF (with the same | 3439 | * any previously cached ASCONF-ACK response that was |
3430 | * serial number) it may just re-transmit the ASCONF-ACK. | 3440 | * sent and saved that matches the Sequence Number of the |
3441 | * ASCONF. Note: It is possible that no cached ASCONF-ACK | ||
3442 | * Chunk exists. This will occur when an older ASCONF | ||
3443 | * arrives out of order. In such a case, the receiver | ||
3444 | * should skip the ASCONF Chunk and not include ASCONF-ACK | ||
3445 | * Chunk for that chunk. | ||
3431 | */ | 3446 | */ |
3432 | if (asoc->addip_last_asconf_ack) | 3447 | asconf_ack = sctp_assoc_lookup_asconf_ack(asoc, hdr->serial); |
3433 | asconf_ack = asoc->addip_last_asconf_ack; | 3448 | if (!asconf_ack) |
3434 | else | ||
3435 | return SCTP_DISPOSITION_DISCARD; | 3449 | return SCTP_DISPOSITION_DISCARD; |
3436 | } else { | 3450 | } else { |
3437 | /* ADDIP 4.2 C4) Otherwise, the ASCONF Chunk is discarded since | 3451 | /* ADDIP 5.2 E5) Otherwise, the ASCONF Chunk is discarded since |
3438 | * it must be either a stale packet or from an attacker. | 3452 | * it must be either a stale packet or from an attacker. |
3439 | */ | 3453 | */ |
3440 | return SCTP_DISPOSITION_DISCARD; | 3454 | return SCTP_DISPOSITION_DISCARD; |
3441 | } | 3455 | } |
3442 | 3456 | ||
3443 | /* ADDIP 4.2 C5) In both cases C2 and C3 the ASCONF-ACK MUST be sent | 3457 | /* ADDIP 5.2 E6) The destination address of the SCTP packet |
3444 | * back to the source address contained in the IP header of the ASCONF | 3458 | * containing the ASCONF-ACK Chunks MUST be the source address of |
3445 | * being responded to. | 3459 | * the SCTP packet that held the ASCONF Chunks. |
3460 | * | ||
3461 | * To do this properly, we'll set the destination address of the chunk | ||
3462 | * and at the transmit time, will try look up the transport to use. | ||
3463 | * Since ASCONFs may be bundled, the correct transport may not be | ||
3464 | * created untill we process the entire packet, thus this workaround. | ||
3446 | */ | 3465 | */ |
3466 | asconf_ack->dest = chunk->source; | ||
3447 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack)); | 3467 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack)); |
3448 | 3468 | ||
3449 | return SCTP_DISPOSITION_CONSUME; | 3469 | return SCTP_DISPOSITION_CONSUME; |