aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/sm_sideeffect.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/sm_sideeffect.c')
-rw-r--r--net/sctp/sm_sideeffect.c76
1 files changed, 69 insertions, 7 deletions
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 4e4ca65cd320..f5e5e27cac5e 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -51,6 +51,7 @@
51#include <linux/types.h> 51#include <linux/types.h>
52#include <linux/socket.h> 52#include <linux/socket.h>
53#include <linux/ip.h> 53#include <linux/ip.h>
54#include <linux/gfp.h>
54#include <net/sock.h> 55#include <net/sock.h>
55#include <net/sctp/sctp.h> 56#include <net/sctp/sctp.h>
56#include <net/sctp/sm.h> 57#include <net/sctp/sm.h>
@@ -396,6 +397,41 @@ out_unlock:
396 sctp_transport_put(transport); 397 sctp_transport_put(transport);
397} 398}
398 399
400/* Handle the timeout of the ICMP protocol unreachable timer. Trigger
401 * the correct state machine transition that will close the association.
402 */
403void sctp_generate_proto_unreach_event(unsigned long data)
404{
405 struct sctp_transport *transport = (struct sctp_transport *) data;
406 struct sctp_association *asoc = transport->asoc;
407
408 sctp_bh_lock_sock(asoc->base.sk);
409 if (sock_owned_by_user(asoc->base.sk)) {
410 SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
411
412 /* Try again later. */
413 if (!mod_timer(&transport->proto_unreach_timer,
414 jiffies + (HZ/20)))
415 sctp_association_hold(asoc);
416 goto out_unlock;
417 }
418
419 /* Is this structure just waiting around for us to actually
420 * get destroyed?
421 */
422 if (asoc->base.dead)
423 goto out_unlock;
424
425 sctp_do_sm(SCTP_EVENT_T_OTHER,
426 SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
427 asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC);
428
429out_unlock:
430 sctp_bh_unlock_sock(asoc->base.sk);
431 sctp_association_put(asoc);
432}
433
434
399/* Inject a SACK Timeout event into the state machine. */ 435/* Inject a SACK Timeout event into the state machine. */
400static void sctp_generate_sack_event(unsigned long data) 436static void sctp_generate_sack_event(unsigned long data)
401{ 437{
@@ -475,7 +511,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
475 * used to provide an upper bound to this doubling operation. 511 * used to provide an upper bound to this doubling operation.
476 * 512 *
477 * Special Case: the first HB doesn't trigger exponential backoff. 513 * Special Case: the first HB doesn't trigger exponential backoff.
478 * The first unacknowleged HB triggers it. We do this with a flag 514 * The first unacknowledged HB triggers it. We do this with a flag
479 * that indicates that we have an outstanding HB. 515 * that indicates that we have an outstanding HB.
480 */ 516 */
481 if (!is_hb || transport->hb_sent) { 517 if (!is_hb || transport->hb_sent) {
@@ -696,11 +732,15 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
696{ 732{
697 struct sctp_transport *t; 733 struct sctp_transport *t;
698 734
699 t = sctp_assoc_choose_alter_transport(asoc, 735 if (chunk->transport)
736 t = chunk->transport;
737 else {
738 t = sctp_assoc_choose_alter_transport(asoc,
700 asoc->shutdown_last_sent_to); 739 asoc->shutdown_last_sent_to);
740 chunk->transport = t;
741 }
701 asoc->shutdown_last_sent_to = t; 742 asoc->shutdown_last_sent_to = t;
702 asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; 743 asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
703 chunk->transport = t;
704} 744}
705 745
706/* Helper function to change the state of an association. */ 746/* Helper function to change the state of an association. */
@@ -852,8 +892,6 @@ static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq,
852 sctp_walk_fwdtsn(skip, chunk) { 892 sctp_walk_fwdtsn(skip, chunk) {
853 sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn)); 893 sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn));
854 } 894 }
855
856 return;
857} 895}
858 896
859/* Helper function to remove the association non-primary peer 897/* Helper function to remove the association non-primary peer
@@ -872,8 +910,6 @@ static void sctp_cmd_del_non_primary(struct sctp_association *asoc)
872 sctp_assoc_del_peer(asoc, &t->ipaddr); 910 sctp_assoc_del_peer(asoc, &t->ipaddr);
873 } 911 }
874 } 912 }
875
876 return;
877} 913}
878 914
879/* Helper function to set sk_err on a 1-1 style socket. */ 915/* Helper function to set sk_err on a 1-1 style socket. */
@@ -961,6 +997,29 @@ static int sctp_cmd_send_msg(struct sctp_association *asoc,
961} 997}
962 998
963 999
1000/* Sent the next ASCONF packet currently stored in the association.
1001 * This happens after the ASCONF_ACK was succeffully processed.
1002 */
1003static void sctp_cmd_send_asconf(struct sctp_association *asoc)
1004{
1005 /* Send the next asconf chunk from the addip chunk
1006 * queue.
1007 */
1008 if (!list_empty(&asoc->addip_chunk_list)) {
1009 struct list_head *entry = asoc->addip_chunk_list.next;
1010 struct sctp_chunk *asconf = list_entry(entry,
1011 struct sctp_chunk, list);
1012 list_del_init(entry);
1013
1014 /* Hold the chunk until an ASCONF_ACK is received. */
1015 sctp_chunk_hold(asconf);
1016 if (sctp_primitive_ASCONF(asoc, asconf))
1017 sctp_chunk_free(asconf);
1018 else
1019 asoc->addip_last_asconf = asconf;
1020 }
1021}
1022
964 1023
965/* These three macros allow us to pull the debugging code out of the 1024/* These three macros allow us to pull the debugging code out of the
966 * main flow of sctp_do_sm() to keep attention focused on the real 1025 * main flow of sctp_do_sm() to keep attention focused on the real
@@ -1616,6 +1675,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
1616 } 1675 }
1617 error = sctp_cmd_send_msg(asoc, cmd->obj.msg); 1676 error = sctp_cmd_send_msg(asoc, cmd->obj.msg);
1618 break; 1677 break;
1678 case SCTP_CMD_SEND_NEXT_ASCONF:
1679 sctp_cmd_send_asconf(asoc);
1680 break;
1619 default: 1681 default:
1620 printk(KERN_WARNING "Impossible command: %u, %p\n", 1682 printk(KERN_WARNING "Impossible command: %u, %p\n",
1621 cmd->verb, cmd->obj.ptr); 1683 cmd->verb, cmd->obj.ptr);