|
@@ -3402,48 +3402,68 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
|
|
|
|
|
|
/* Verify the ASCONF chunk before processing it. */
|
|
/* Verify the ASCONF chunk before processing it. */
|
|
if (!sctp_verify_asconf(asoc,
|
|
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,
|
|
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
|
|
* the endpoint stored in a new association variable
|
|
* 'Peer-Serial-Number'.
|
|
* 'Peer-Serial-Number'.
|
|
*/
|
|
*/
|
|
if (serial == asoc->peer.addip_serial + 1) {
|
|
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 *)
|
|
asconf_ack = sctp_process_asconf((struct sctp_association *)
|
|
asoc, chunk);
|
|
asoc, chunk);
|
|
if (!asconf_ack)
|
|
if (!asconf_ack)
|
|
return SCTP_DISPOSITION_NOMEM;
|
|
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;
|
|
return SCTP_DISPOSITION_DISCARD;
|
|
} else {
|
|
} 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.
|
|
* it must be either a stale packet or from an attacker.
|
|
*/
|
|
*/
|
|
return SCTP_DISPOSITION_DISCARD;
|
|
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));
|
|
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack));
|
|
|
|
|
|
return SCTP_DISPOSITION_CONSUME;
|
|
return SCTP_DISPOSITION_CONSUME;
|