aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/associola.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/associola.c')
-rw-r--r--net/sctp/associola.c58
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. */
63static void sctp_assoc_bh_rcv(struct work_struct *work); 63static void sctp_assoc_bh_rcv(struct work_struct *work);
64static 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 */
1491static 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 */
1504void 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 */
1524struct 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}