[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:
committed by
David S. Miller
parent
ba8a06daed
commit
a08de64d07
@@ -61,6 +61,7 @@
|
||||
|
||||
/* Forward declarations for internal functions. */
|
||||
static void sctp_assoc_bh_rcv(struct work_struct *work);
|
||||
static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc);
|
||||
|
||||
|
||||
/* 1st Level Abstractions. */
|
||||
@@ -242,6 +243,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
|
||||
asoc->addip_serial = asoc->c.initial_tsn;
|
||||
|
||||
INIT_LIST_HEAD(&asoc->addip_chunk_list);
|
||||
INIT_LIST_HEAD(&asoc->asconf_ack_list);
|
||||
|
||||
/* Make an empty list of remote transport addresses. */
|
||||
INIT_LIST_HEAD(&asoc->peer.transport_addr_list);
|
||||
@@ -431,8 +433,7 @@ void sctp_association_free(struct sctp_association *asoc)
|
||||
asoc->peer.transport_count = 0;
|
||||
|
||||
/* Free any cached ASCONF_ACK chunk. */
|
||||
if (asoc->addip_last_asconf_ack)
|
||||
sctp_chunk_free(asoc->addip_last_asconf_ack);
|
||||
sctp_assoc_free_asconf_acks(asoc);
|
||||
|
||||
/* Free any cached ASCONF chunk. */
|
||||
if (asoc->addip_last_asconf)
|
||||
@@ -1485,3 +1486,56 @@ retry:
|
||||
asoc->assoc_id = (sctp_assoc_t) assoc_id;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Free asconf_ack cache */
|
||||
static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc)
|
||||
{
|
||||
struct sctp_chunk *ack;
|
||||
struct sctp_chunk *tmp;
|
||||
|
||||
list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list,
|
||||
transmitted_list) {
|
||||
list_del_init(&ack->transmitted_list);
|
||||
sctp_chunk_free(ack);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up the ASCONF_ACK queue */
|
||||
void sctp_assoc_clean_asconf_ack_cache(const struct sctp_association *asoc)
|
||||
{
|
||||
struct sctp_chunk *ack;
|
||||
struct sctp_chunk *tmp;
|
||||
|
||||
/* We can remove all the entries from the queue upto
|
||||
* the "Peer-Sequence-Number".
|
||||
*/
|
||||
list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list,
|
||||
transmitted_list) {
|
||||
if (ack->subh.addip_hdr->serial ==
|
||||
htonl(asoc->peer.addip_serial))
|
||||
break;
|
||||
|
||||
list_del_init(&ack->transmitted_list);
|
||||
sctp_chunk_free(ack);
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the ASCONF_ACK whose serial number matches ASCONF */
|
||||
struct sctp_chunk *sctp_assoc_lookup_asconf_ack(
|
||||
const struct sctp_association *asoc,
|
||||
__be32 serial)
|
||||
{
|
||||
struct sctp_chunk *ack = NULL;
|
||||
|
||||
/* Walk through the list of cached ASCONF-ACKs and find the
|
||||
* ack chunk whose serial number matches that of the request.
|
||||
*/
|
||||
list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) {
|
||||
if (ack->subh.addip_hdr->serial == serial) {
|
||||
sctp_chunk_hold(ack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ack;
|
||||
}
|
||||
|
Reference in New Issue
Block a user