aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/sm_statefuns.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/sm_statefuns.c')
-rw-r--r--net/sctp/sm_statefuns.c64
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;