[SCTP]: Update ASCONF processing to conform to spec.

The processing of the ASCONF chunks has changed a lot in the
spec.  New items are:
    1. A list of ASCONF-ACK chunks is now cached
    2. The source of the packet is used in response.
    3. New handling for unexpect ASCONF chunks.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Vlad Yasevich
2007-12-20 14:11:47 -08:00
committed by David S. Miller
parent ba8a06daed
commit a08de64d07
5 changed files with 143 additions and 44 deletions

View File

@@ -3402,48 +3402,68 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
/* Verify the ASCONF chunk before processing it. */
if (!sctp_verify_asconf(asoc,
(sctp_paramhdr_t *)((void *)addr_param + length),
(void *)chunk->chunk_end,
&err_param))
(sctp_paramhdr_t *)((void *)addr_param + length),
(void *)chunk->chunk_end,
&err_param))
return sctp_sf_violation_paramlen(ep, asoc, type,
(void *)&err_param, commands);
(void *)&err_param, commands);
/* ADDIP 4.2 C1) Compare the value of the serial number to the value
/* ADDIP 5.2 E1) Compare the value of the serial number to the value
* the endpoint stored in a new association variable
* 'Peer-Serial-Number'.
*/
if (serial == asoc->peer.addip_serial + 1) {
/* ADDIP 4.2 C2) If the value found in the serial number is
* equal to the ('Peer-Serial-Number' + 1), the endpoint MUST
* do V1-V5.
/* If this is the first instance of ASCONF in the packet,
* we can clean our old ASCONF-ACKs.
*/
if (!chunk->has_asconf)
sctp_assoc_clean_asconf_ack_cache(asoc);
/* ADDIP 5.2 E4) When the Sequence Number matches the next one
* expected, process the ASCONF as described below and after
* processing the ASCONF Chunk, append an ASCONF-ACK Chunk to
* the response packet and cache a copy of it (in the event it
* later needs to be retransmitted).
*
* Essentially, do V1-V5.
*/
asconf_ack = sctp_process_asconf((struct sctp_association *)
asoc, chunk);
if (!asconf_ack)
return SCTP_DISPOSITION_NOMEM;
} else if (serial == asoc->peer.addip_serial) {
/* ADDIP 4.2 C3) If the value found in the serial number is
* equal to the value stored in the 'Peer-Serial-Number'
* IMPLEMENTATION NOTE: As an optimization a receiver may wish
* to save the last ASCONF-ACK for some predetermined period of
* time and instead of re-processing the ASCONF (with the same
* serial number) it may just re-transmit the ASCONF-ACK.
} else if (serial < asoc->peer.addip_serial + 1) {
/* ADDIP 5.2 E2)
* If the value found in the Sequence Number is less than the
* ('Peer- Sequence-Number' + 1), simply skip to the next
* ASCONF, and include in the outbound response packet
* any previously cached ASCONF-ACK response that was
* sent and saved that matches the Sequence Number of the
* ASCONF. Note: It is possible that no cached ASCONF-ACK
* Chunk exists. This will occur when an older ASCONF
* arrives out of order. In such a case, the receiver
* should skip the ASCONF Chunk and not include ASCONF-ACK
* Chunk for that chunk.
*/
if (asoc->addip_last_asconf_ack)
asconf_ack = asoc->addip_last_asconf_ack;
else
asconf_ack = sctp_assoc_lookup_asconf_ack(asoc, hdr->serial);
if (!asconf_ack)
return SCTP_DISPOSITION_DISCARD;
} else {
/* ADDIP 4.2 C4) Otherwise, the ASCONF Chunk is discarded since
/* ADDIP 5.2 E5) Otherwise, the ASCONF Chunk is discarded since
* it must be either a stale packet or from an attacker.
*/
return SCTP_DISPOSITION_DISCARD;
}
/* ADDIP 4.2 C5) In both cases C2 and C3 the ASCONF-ACK MUST be sent
* back to the source address contained in the IP header of the ASCONF
* being responded to.
/* ADDIP 5.2 E6) The destination address of the SCTP packet
* containing the ASCONF-ACK Chunks MUST be the source address of
* the SCTP packet that held the ASCONF Chunks.
*
* To do this properly, we'll set the destination address of the chunk
* and at the transmit time, will try look up the transport to use.
* Since ASCONFs may be bundled, the correct transport may not be
* created untill we process the entire packet, thus this workaround.
*/
asconf_ack->dest = chunk->source;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack));
return SCTP_DISPOSITION_CONSUME;