diff options
Diffstat (limited to 'net/sctp/sm_sideeffect.c')
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 76 |
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 | */ | ||
| 403 | void 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 | |||
| 429 | out_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. */ |
| 400 | static void sctp_generate_sack_event(unsigned long data) | 436 | static 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 | */ | ||
| 1003 | static 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); |
