diff options
Diffstat (limited to 'net/sctp/sm_sideeffect.c')
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index efa516b47e81..eb1f42f45fdd 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> |
| @@ -217,8 +218,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, | |||
| 217 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, | 218 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, |
| 218 | SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); | 219 | SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); |
| 219 | } else { | 220 | } else { |
| 220 | if (asoc->a_rwnd > asoc->rwnd) | 221 | asoc->a_rwnd = asoc->rwnd; |
| 221 | asoc->a_rwnd = asoc->rwnd; | ||
| 222 | sack = sctp_make_sack(asoc); | 222 | sack = sctp_make_sack(asoc); |
| 223 | if (!sack) | 223 | if (!sack) |
| 224 | goto nomem; | 224 | goto nomem; |
| @@ -397,6 +397,41 @@ out_unlock: | |||
| 397 | sctp_transport_put(transport); | 397 | sctp_transport_put(transport); |
| 398 | } | 398 | } |
| 399 | 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 | |||
| 400 | /* Inject a SACK Timeout event into the state machine. */ | 435 | /* Inject a SACK Timeout event into the state machine. */ |
| 401 | static void sctp_generate_sack_event(unsigned long data) | 436 | static void sctp_generate_sack_event(unsigned long data) |
| 402 | { | 437 | { |
| @@ -476,7 +511,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, | |||
| 476 | * used to provide an upper bound to this doubling operation. | 511 | * used to provide an upper bound to this doubling operation. |
| 477 | * | 512 | * |
| 478 | * Special Case: the first HB doesn't trigger exponential backoff. | 513 | * Special Case: the first HB doesn't trigger exponential backoff. |
| 479 | * 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 |
| 480 | * that indicates that we have an outstanding HB. | 515 | * that indicates that we have an outstanding HB. |
| 481 | */ | 516 | */ |
| 482 | if (!is_hb || transport->hb_sent) { | 517 | if (!is_hb || transport->hb_sent) { |
| @@ -718,7 +753,7 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, | |||
| 718 | 753 | ||
| 719 | if (sctp_style(sk, TCP)) { | 754 | if (sctp_style(sk, TCP)) { |
| 720 | /* Change the sk->sk_state of a TCP-style socket that has | 755 | /* Change the sk->sk_state of a TCP-style socket that has |
| 721 | * sucessfully completed a connect() call. | 756 | * successfully completed a connect() call. |
| 722 | */ | 757 | */ |
| 723 | if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED)) | 758 | if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED)) |
| 724 | sk->sk_state = SCTP_SS_ESTABLISHED; | 759 | sk->sk_state = SCTP_SS_ESTABLISHED; |
| @@ -962,6 +997,29 @@ static int sctp_cmd_send_msg(struct sctp_association *asoc, | |||
| 962 | } | 997 | } |
| 963 | 998 | ||
| 964 | 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 | |||
| 965 | 1023 | ||
| 966 | /* 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 |
| 967 | * 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 |
| @@ -1417,6 +1475,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
| 1417 | asoc->init_last_sent_to = t; | 1475 | asoc->init_last_sent_to = t; |
| 1418 | chunk->transport = t; | 1476 | chunk->transport = t; |
| 1419 | t->init_sent_count++; | 1477 | t->init_sent_count++; |
| 1478 | /* Set the new transport as primary */ | ||
| 1479 | sctp_assoc_set_primary(asoc, t); | ||
| 1420 | break; | 1480 | break; |
| 1421 | 1481 | ||
| 1422 | case SCTP_CMD_INIT_RESTART: | 1482 | case SCTP_CMD_INIT_RESTART: |
| @@ -1615,6 +1675,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
| 1615 | } | 1675 | } |
| 1616 | error = sctp_cmd_send_msg(asoc, cmd->obj.msg); | 1676 | error = sctp_cmd_send_msg(asoc, cmd->obj.msg); |
| 1617 | break; | 1677 | break; |
| 1678 | case SCTP_CMD_SEND_NEXT_ASCONF: | ||
| 1679 | sctp_cmd_send_asconf(asoc); | ||
| 1680 | break; | ||
| 1618 | default: | 1681 | default: |
| 1619 | printk(KERN_WARNING "Impossible command: %u, %p\n", | 1682 | printk(KERN_WARNING "Impossible command: %u, %p\n", |
| 1620 | cmd->verb, cmd->obj.ptr); | 1683 | cmd->verb, cmd->obj.ptr); |
