diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2007-12-20 17:11:47 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:59:23 -0500 |
commit | a08de64d074b36a56ee3bb985cd171281db78e96 (patch) | |
tree | 15b3c77a7078b5dc0510a23cc7d95922f7ad420a /net/sctp/associola.c | |
parent | ba8a06daed7d7c8785c92c343da9e202e6988fda (diff) |
[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>
Diffstat (limited to 'net/sctp/associola.c')
-rw-r--r-- | net/sctp/associola.c | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 61bebb9b96e6..a016e78061f4 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -61,6 +61,7 @@ | |||
61 | 61 | ||
62 | /* Forward declarations for internal functions. */ | 62 | /* Forward declarations for internal functions. */ |
63 | static void sctp_assoc_bh_rcv(struct work_struct *work); | 63 | static void sctp_assoc_bh_rcv(struct work_struct *work); |
64 | static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc); | ||
64 | 65 | ||
65 | 66 | ||
66 | /* 1st Level Abstractions. */ | 67 | /* 1st Level Abstractions. */ |
@@ -242,6 +243,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
242 | asoc->addip_serial = asoc->c.initial_tsn; | 243 | asoc->addip_serial = asoc->c.initial_tsn; |
243 | 244 | ||
244 | INIT_LIST_HEAD(&asoc->addip_chunk_list); | 245 | INIT_LIST_HEAD(&asoc->addip_chunk_list); |
246 | INIT_LIST_HEAD(&asoc->asconf_ack_list); | ||
245 | 247 | ||
246 | /* Make an empty list of remote transport addresses. */ | 248 | /* Make an empty list of remote transport addresses. */ |
247 | INIT_LIST_HEAD(&asoc->peer.transport_addr_list); | 249 | INIT_LIST_HEAD(&asoc->peer.transport_addr_list); |
@@ -431,8 +433,7 @@ void sctp_association_free(struct sctp_association *asoc) | |||
431 | asoc->peer.transport_count = 0; | 433 | asoc->peer.transport_count = 0; |
432 | 434 | ||
433 | /* Free any cached ASCONF_ACK chunk. */ | 435 | /* Free any cached ASCONF_ACK chunk. */ |
434 | if (asoc->addip_last_asconf_ack) | 436 | sctp_assoc_free_asconf_acks(asoc); |
435 | sctp_chunk_free(asoc->addip_last_asconf_ack); | ||
436 | 437 | ||
437 | /* Free any cached ASCONF chunk. */ | 438 | /* Free any cached ASCONF chunk. */ |
438 | if (asoc->addip_last_asconf) | 439 | if (asoc->addip_last_asconf) |
@@ -1485,3 +1486,56 @@ retry: | |||
1485 | asoc->assoc_id = (sctp_assoc_t) assoc_id; | 1486 | asoc->assoc_id = (sctp_assoc_t) assoc_id; |
1486 | return error; | 1487 | return error; |
1487 | } | 1488 | } |
1489 | |||
1490 | /* Free asconf_ack cache */ | ||
1491 | static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc) | ||
1492 | { | ||
1493 | struct sctp_chunk *ack; | ||
1494 | struct sctp_chunk *tmp; | ||
1495 | |||
1496 | list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list, | ||
1497 | transmitted_list) { | ||
1498 | list_del_init(&ack->transmitted_list); | ||
1499 | sctp_chunk_free(ack); | ||
1500 | } | ||
1501 | } | ||
1502 | |||
1503 | /* Clean up the ASCONF_ACK queue */ | ||
1504 | void sctp_assoc_clean_asconf_ack_cache(const struct sctp_association *asoc) | ||
1505 | { | ||
1506 | struct sctp_chunk *ack; | ||
1507 | struct sctp_chunk *tmp; | ||
1508 | |||
1509 | /* We can remove all the entries from the queue upto | ||
1510 | * the "Peer-Sequence-Number". | ||
1511 | */ | ||
1512 | list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list, | ||
1513 | transmitted_list) { | ||
1514 | if (ack->subh.addip_hdr->serial == | ||
1515 | htonl(asoc->peer.addip_serial)) | ||
1516 | break; | ||
1517 | |||
1518 | list_del_init(&ack->transmitted_list); | ||
1519 | sctp_chunk_free(ack); | ||
1520 | } | ||
1521 | } | ||
1522 | |||
1523 | /* Find the ASCONF_ACK whose serial number matches ASCONF */ | ||
1524 | struct sctp_chunk *sctp_assoc_lookup_asconf_ack( | ||
1525 | const struct sctp_association *asoc, | ||
1526 | __be32 serial) | ||
1527 | { | ||
1528 | struct sctp_chunk *ack = NULL; | ||
1529 | |||
1530 | /* Walk through the list of cached ASCONF-ACKs and find the | ||
1531 | * ack chunk whose serial number matches that of the request. | ||
1532 | */ | ||
1533 | list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) { | ||
1534 | if (ack->subh.addip_hdr->serial == serial) { | ||
1535 | sctp_chunk_hold(ack); | ||
1536 | break; | ||
1537 | } | ||
1538 | } | ||
1539 | |||
1540 | return ack; | ||
1541 | } | ||