diff options
Diffstat (limited to 'net/sctp/sm_statefuns.c')
-rw-r--r-- | net/sctp/sm_statefuns.c | 159 |
1 files changed, 86 insertions, 73 deletions
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 32f57f42af9e..1c42fe983a5b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -187,10 +187,9 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, | |||
187 | */ | 187 | */ |
188 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, | 188 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, |
189 | 0, 0, 0, GFP_ATOMIC); | 189 | 0, 0, 0, GFP_ATOMIC); |
190 | if (!ev) | 190 | if (ev) |
191 | goto nomem; | 191 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, |
192 | 192 | SCTP_ULPEVENT(ev)); | |
193 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | ||
194 | 193 | ||
195 | /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint | 194 | /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint |
196 | * will verify that it is in SHUTDOWN-ACK-SENT state, if it is | 195 | * will verify that it is in SHUTDOWN-ACK-SENT state, if it is |
@@ -215,9 +214,6 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, | |||
215 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); | 214 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); |
216 | 215 | ||
217 | return SCTP_DISPOSITION_DELETE_TCB; | 216 | return SCTP_DISPOSITION_DELETE_TCB; |
218 | |||
219 | nomem: | ||
220 | return SCTP_DISPOSITION_NOMEM; | ||
221 | } | 217 | } |
222 | 218 | ||
223 | /* | 219 | /* |
@@ -347,8 +343,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, | |||
347 | GFP_ATOMIC)) | 343 | GFP_ATOMIC)) |
348 | goto nomem_init; | 344 | goto nomem_init; |
349 | 345 | ||
350 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | ||
351 | |||
352 | /* B) "Z" shall respond immediately with an INIT ACK chunk. */ | 346 | /* B) "Z" shall respond immediately with an INIT ACK chunk. */ |
353 | 347 | ||
354 | /* If there are errors need to be reported for unknown parameters, | 348 | /* If there are errors need to be reported for unknown parameters, |
@@ -360,11 +354,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, | |||
360 | sizeof(sctp_chunkhdr_t); | 354 | sizeof(sctp_chunkhdr_t); |
361 | 355 | ||
362 | if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0) | 356 | if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0) |
363 | goto nomem_ack; | 357 | goto nomem_init; |
364 | 358 | ||
365 | repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); | 359 | repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); |
366 | if (!repl) | 360 | if (!repl) |
367 | goto nomem_ack; | 361 | goto nomem_init; |
368 | 362 | ||
369 | /* If there are errors need to be reported for unknown parameters, | 363 | /* If there are errors need to be reported for unknown parameters, |
370 | * include them in the outgoing INIT ACK as "Unrecognized parameter" | 364 | * include them in the outgoing INIT ACK as "Unrecognized parameter" |
@@ -388,6 +382,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, | |||
388 | sctp_chunk_free(err_chunk); | 382 | sctp_chunk_free(err_chunk); |
389 | } | 383 | } |
390 | 384 | ||
385 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | ||
386 | |||
391 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | 387 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); |
392 | 388 | ||
393 | /* | 389 | /* |
@@ -400,12 +396,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, | |||
400 | 396 | ||
401 | return SCTP_DISPOSITION_DELETE_TCB; | 397 | return SCTP_DISPOSITION_DELETE_TCB; |
402 | 398 | ||
403 | nomem_ack: | ||
404 | if (err_chunk) | ||
405 | sctp_chunk_free(err_chunk); | ||
406 | nomem_init: | 399 | nomem_init: |
407 | sctp_association_free(new_asoc); | 400 | sctp_association_free(new_asoc); |
408 | nomem: | 401 | nomem: |
402 | if (err_chunk) | ||
403 | sctp_chunk_free(err_chunk); | ||
409 | return SCTP_DISPOSITION_NOMEM; | 404 | return SCTP_DISPOSITION_NOMEM; |
410 | } | 405 | } |
411 | 406 | ||
@@ -600,7 +595,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
600 | struct sctp_association *new_asoc; | 595 | struct sctp_association *new_asoc; |
601 | sctp_init_chunk_t *peer_init; | 596 | sctp_init_chunk_t *peer_init; |
602 | struct sctp_chunk *repl; | 597 | struct sctp_chunk *repl; |
603 | struct sctp_ulpevent *ev; | 598 | struct sctp_ulpevent *ev, *ai_ev = NULL; |
604 | int error = 0; | 599 | int error = 0; |
605 | struct sctp_chunk *err_chk_p; | 600 | struct sctp_chunk *err_chk_p; |
606 | 601 | ||
@@ -659,20 +654,10 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
659 | }; | 654 | }; |
660 | } | 655 | } |
661 | 656 | ||
662 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | ||
663 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | ||
664 | SCTP_STATE(SCTP_STATE_ESTABLISHED)); | ||
665 | SCTP_INC_STATS(SCTP_MIB_CURRESTAB); | ||
666 | SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS); | ||
667 | sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); | ||
668 | 657 | ||
669 | if (new_asoc->autoclose) | 658 | /* Delay state machine commands until later. |
670 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, | 659 | * |
671 | SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); | 660 | * Re-build the bind address for the association is done in |
672 | |||
673 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); | ||
674 | |||
675 | /* Re-build the bind address for the association is done in | ||
676 | * the sctp_unpack_cookie() already. | 661 | * the sctp_unpack_cookie() already. |
677 | */ | 662 | */ |
678 | /* This is a brand-new association, so these are not yet side | 663 | /* This is a brand-new association, so these are not yet side |
@@ -687,9 +672,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
687 | 672 | ||
688 | repl = sctp_make_cookie_ack(new_asoc, chunk); | 673 | repl = sctp_make_cookie_ack(new_asoc, chunk); |
689 | if (!repl) | 674 | if (!repl) |
690 | goto nomem_repl; | 675 | goto nomem_init; |
691 | |||
692 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
693 | 676 | ||
694 | /* RFC 2960 5.1 Normal Establishment of an Association | 677 | /* RFC 2960 5.1 Normal Establishment of an Association |
695 | * | 678 | * |
@@ -704,28 +687,53 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
704 | if (!ev) | 687 | if (!ev) |
705 | goto nomem_ev; | 688 | goto nomem_ev; |
706 | 689 | ||
707 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | ||
708 | |||
709 | /* Sockets API Draft Section 5.3.1.6 | 690 | /* Sockets API Draft Section 5.3.1.6 |
710 | * When a peer sends a Adaption Layer Indication parameter , SCTP | 691 | * When a peer sends a Adaption Layer Indication parameter , SCTP |
711 | * delivers this notification to inform the application that of the | 692 | * delivers this notification to inform the application that of the |
712 | * peers requested adaption layer. | 693 | * peers requested adaption layer. |
713 | */ | 694 | */ |
714 | if (new_asoc->peer.adaption_ind) { | 695 | if (new_asoc->peer.adaption_ind) { |
715 | ev = sctp_ulpevent_make_adaption_indication(new_asoc, | 696 | ai_ev = sctp_ulpevent_make_adaption_indication(new_asoc, |
716 | GFP_ATOMIC); | 697 | GFP_ATOMIC); |
717 | if (!ev) | 698 | if (!ai_ev) |
718 | goto nomem_ev; | 699 | goto nomem_aiev; |
700 | } | ||
701 | |||
702 | /* Add all the state machine commands now since we've created | ||
703 | * everything. This way we don't introduce memory corruptions | ||
704 | * during side-effect processing and correclty count established | ||
705 | * associations. | ||
706 | */ | ||
707 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | ||
708 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | ||
709 | SCTP_STATE(SCTP_STATE_ESTABLISHED)); | ||
710 | SCTP_INC_STATS(SCTP_MIB_CURRESTAB); | ||
711 | SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS); | ||
712 | sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); | ||
713 | |||
714 | if (new_asoc->autoclose) | ||
715 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, | ||
716 | SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); | ||
717 | |||
718 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); | ||
719 | 719 | ||
720 | /* This will send the COOKIE ACK */ | ||
721 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
722 | |||
723 | /* Queue the ASSOC_CHANGE event */ | ||
724 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | ||
725 | |||
726 | /* Send up the Adaptation Layer Indication event */ | ||
727 | if (ai_ev) | ||
720 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | 728 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, |
721 | SCTP_ULPEVENT(ev)); | 729 | SCTP_ULPEVENT(ai_ev)); |
722 | } | ||
723 | 730 | ||
724 | return SCTP_DISPOSITION_CONSUME; | 731 | return SCTP_DISPOSITION_CONSUME; |
725 | 732 | ||
733 | nomem_aiev: | ||
734 | sctp_ulpevent_free(ev); | ||
726 | nomem_ev: | 735 | nomem_ev: |
727 | sctp_chunk_free(repl); | 736 | sctp_chunk_free(repl); |
728 | nomem_repl: | ||
729 | nomem_init: | 737 | nomem_init: |
730 | sctp_association_free(new_asoc); | 738 | sctp_association_free(new_asoc); |
731 | nomem: | 739 | nomem: |
@@ -1360,10 +1368,8 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( | |||
1360 | if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, | 1368 | if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, |
1361 | sctp_source(chunk), | 1369 | sctp_source(chunk), |
1362 | (sctp_init_chunk_t *)chunk->chunk_hdr, | 1370 | (sctp_init_chunk_t *)chunk->chunk_hdr, |
1363 | GFP_ATOMIC)) { | 1371 | GFP_ATOMIC)) |
1364 | retval = SCTP_DISPOSITION_NOMEM; | 1372 | goto nomem; |
1365 | goto nomem_init; | ||
1366 | } | ||
1367 | 1373 | ||
1368 | /* Make sure no new addresses are being added during the | 1374 | /* Make sure no new addresses are being added during the |
1369 | * restart. Do not do this check for COOKIE-WAIT state, | 1375 | * restart. Do not do this check for COOKIE-WAIT state, |
@@ -1374,7 +1380,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( | |||
1374 | if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, | 1380 | if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, |
1375 | commands)) { | 1381 | commands)) { |
1376 | retval = SCTP_DISPOSITION_CONSUME; | 1382 | retval = SCTP_DISPOSITION_CONSUME; |
1377 | goto cleanup_asoc; | 1383 | goto nomem_retval; |
1378 | } | 1384 | } |
1379 | } | 1385 | } |
1380 | 1386 | ||
@@ -1430,17 +1436,17 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( | |||
1430 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); | 1436 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); |
1431 | retval = SCTP_DISPOSITION_CONSUME; | 1437 | retval = SCTP_DISPOSITION_CONSUME; |
1432 | 1438 | ||
1439 | return retval; | ||
1440 | |||
1441 | nomem: | ||
1442 | retval = SCTP_DISPOSITION_NOMEM; | ||
1443 | nomem_retval: | ||
1444 | if (new_asoc) | ||
1445 | sctp_association_free(new_asoc); | ||
1433 | cleanup: | 1446 | cleanup: |
1434 | if (err_chunk) | 1447 | if (err_chunk) |
1435 | sctp_chunk_free(err_chunk); | 1448 | sctp_chunk_free(err_chunk); |
1436 | return retval; | 1449 | return retval; |
1437 | nomem: | ||
1438 | retval = SCTP_DISPOSITION_NOMEM; | ||
1439 | goto cleanup; | ||
1440 | nomem_init: | ||
1441 | cleanup_asoc: | ||
1442 | sctp_association_free(new_asoc); | ||
1443 | goto cleanup; | ||
1444 | } | 1450 | } |
1445 | 1451 | ||
1446 | /* | 1452 | /* |
@@ -1611,15 +1617,10 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, | |||
1611 | */ | 1617 | */ |
1612 | sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); | 1618 | sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); |
1613 | 1619 | ||
1614 | /* Update the content of current association. */ | ||
1615 | sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); | ||
1616 | |||
1617 | repl = sctp_make_cookie_ack(new_asoc, chunk); | 1620 | repl = sctp_make_cookie_ack(new_asoc, chunk); |
1618 | if (!repl) | 1621 | if (!repl) |
1619 | goto nomem; | 1622 | goto nomem; |
1620 | 1623 | ||
1621 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
1622 | |||
1623 | /* Report association restart to upper layer. */ | 1624 | /* Report association restart to upper layer. */ |
1624 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, | 1625 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, |
1625 | new_asoc->c.sinit_num_ostreams, | 1626 | new_asoc->c.sinit_num_ostreams, |
@@ -1628,6 +1629,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, | |||
1628 | if (!ev) | 1629 | if (!ev) |
1629 | goto nomem_ev; | 1630 | goto nomem_ev; |
1630 | 1631 | ||
1632 | /* Update the content of current association. */ | ||
1633 | sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); | ||
1634 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
1631 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | 1635 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); |
1632 | return SCTP_DISPOSITION_CONSUME; | 1636 | return SCTP_DISPOSITION_CONSUME; |
1633 | 1637 | ||
@@ -1751,7 +1755,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, | |||
1751 | sctp_cmd_seq_t *commands, | 1755 | sctp_cmd_seq_t *commands, |
1752 | struct sctp_association *new_asoc) | 1756 | struct sctp_association *new_asoc) |
1753 | { | 1757 | { |
1754 | struct sctp_ulpevent *ev = NULL; | 1758 | struct sctp_ulpevent *ev = NULL, *ai_ev = NULL; |
1755 | struct sctp_chunk *repl; | 1759 | struct sctp_chunk *repl; |
1756 | 1760 | ||
1757 | /* Clarification from Implementor's Guide: | 1761 | /* Clarification from Implementor's Guide: |
@@ -1778,29 +1782,25 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, | |||
1778 | * SCTP user upon reception of a valid COOKIE | 1782 | * SCTP user upon reception of a valid COOKIE |
1779 | * ECHO chunk. | 1783 | * ECHO chunk. |
1780 | */ | 1784 | */ |
1781 | ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, | 1785 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, |
1782 | SCTP_COMM_UP, 0, | 1786 | SCTP_COMM_UP, 0, |
1783 | new_asoc->c.sinit_num_ostreams, | 1787 | asoc->c.sinit_num_ostreams, |
1784 | new_asoc->c.sinit_max_instreams, | 1788 | asoc->c.sinit_max_instreams, |
1785 | GFP_ATOMIC); | 1789 | GFP_ATOMIC); |
1786 | if (!ev) | 1790 | if (!ev) |
1787 | goto nomem; | 1791 | goto nomem; |
1788 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
1789 | SCTP_ULPEVENT(ev)); | ||
1790 | 1792 | ||
1791 | /* Sockets API Draft Section 5.3.1.6 | 1793 | /* Sockets API Draft Section 5.3.1.6 |
1792 | * When a peer sends a Adaption Layer Indication parameter, | 1794 | * When a peer sends a Adaption Layer Indication parameter, |
1793 | * SCTP delivers this notification to inform the application | 1795 | * SCTP delivers this notification to inform the application |
1794 | * that of the peers requested adaption layer. | 1796 | * that of the peers requested adaption layer. |
1795 | */ | 1797 | */ |
1796 | if (new_asoc->peer.adaption_ind) { | 1798 | if (asoc->peer.adaption_ind) { |
1797 | ev = sctp_ulpevent_make_adaption_indication(new_asoc, | 1799 | ai_ev = sctp_ulpevent_make_adaption_indication(asoc, |
1798 | GFP_ATOMIC); | 1800 | GFP_ATOMIC); |
1799 | if (!ev) | 1801 | if (!ai_ev) |
1800 | goto nomem; | 1802 | goto nomem; |
1801 | 1803 | ||
1802 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
1803 | SCTP_ULPEVENT(ev)); | ||
1804 | } | 1804 | } |
1805 | } | 1805 | } |
1806 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); | 1806 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); |
@@ -1809,12 +1809,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, | |||
1809 | if (!repl) | 1809 | if (!repl) |
1810 | goto nomem; | 1810 | goto nomem; |
1811 | 1811 | ||
1812 | if (ev) | ||
1813 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
1814 | SCTP_ULPEVENT(ev)); | ||
1815 | if (ai_ev) | ||
1816 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
1817 | SCTP_ULPEVENT(ai_ev)); | ||
1818 | |||
1812 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | 1819 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); |
1813 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); | 1820 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); |
1814 | 1821 | ||
1815 | return SCTP_DISPOSITION_CONSUME; | 1822 | return SCTP_DISPOSITION_CONSUME; |
1816 | 1823 | ||
1817 | nomem: | 1824 | nomem: |
1825 | if (ai_ev) | ||
1826 | sctp_ulpevent_free(ai_ev); | ||
1818 | if (ev) | 1827 | if (ev) |
1819 | sctp_ulpevent_free(ev); | 1828 | sctp_ulpevent_free(ev); |
1820 | return SCTP_DISPOSITION_NOMEM; | 1829 | return SCTP_DISPOSITION_NOMEM; |
@@ -3019,7 +3028,6 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3019 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) | 3028 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) |
3020 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | 3029 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, |
3021 | commands); | 3030 | commands); |
3022 | |||
3023 | /* 10.2 H) SHUTDOWN COMPLETE notification | 3031 | /* 10.2 H) SHUTDOWN COMPLETE notification |
3024 | * | 3032 | * |
3025 | * When SCTP completes the shutdown procedures (section 9.2) this | 3033 | * When SCTP completes the shutdown procedures (section 9.2) this |
@@ -3030,6 +3038,14 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3030 | if (!ev) | 3038 | if (!ev) |
3031 | goto nomem; | 3039 | goto nomem; |
3032 | 3040 | ||
3041 | /* ...send a SHUTDOWN COMPLETE chunk to its peer, */ | ||
3042 | reply = sctp_make_shutdown_complete(asoc, chunk); | ||
3043 | if (!reply) | ||
3044 | goto nomem_chunk; | ||
3045 | |||
3046 | /* Do all the commands now (after allocation), so that we | ||
3047 | * have consistent state if memory allocation failes | ||
3048 | */ | ||
3033 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | 3049 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); |
3034 | 3050 | ||
3035 | /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall | 3051 | /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall |
@@ -3041,11 +3057,6 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3041 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, | 3057 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, |
3042 | SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); | 3058 | SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); |
3043 | 3059 | ||
3044 | /* ...send a SHUTDOWN COMPLETE chunk to its peer, */ | ||
3045 | reply = sctp_make_shutdown_complete(asoc, chunk); | ||
3046 | if (!reply) | ||
3047 | goto nomem; | ||
3048 | |||
3049 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | 3060 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, |
3050 | SCTP_STATE(SCTP_STATE_CLOSED)); | 3061 | SCTP_STATE(SCTP_STATE_CLOSED)); |
3051 | SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS); | 3062 | SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS); |
@@ -3056,6 +3067,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3056 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); | 3067 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); |
3057 | return SCTP_DISPOSITION_DELETE_TCB; | 3068 | return SCTP_DISPOSITION_DELETE_TCB; |
3058 | 3069 | ||
3070 | nomem_chunk: | ||
3071 | sctp_ulpevent_free(ev); | ||
3059 | nomem: | 3072 | nomem: |
3060 | return SCTP_DISPOSITION_NOMEM; | 3073 | return SCTP_DISPOSITION_NOMEM; |
3061 | } | 3074 | } |