diff options
| author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2007-05-04 16:55:27 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2007-05-04 16:55:27 -0400 |
| commit | 07d939677166cc4f000c767196872a9becc2697b (patch) | |
| tree | bef3d3c75ac3dd56813adbc63281feb4195a5b47 | |
| parent | 827bf12236fbafc02bc899aec1b37c342c8cf4e5 (diff) | |
[SCTP]: Set assoc_id correctly during INIT collision.
During the INIT/COOKIE-ACK collision cases, it's possible to get
into a situation where the association id is not yet set at the time
of the user event generation. As a result, user events have an
association id set to 0 which will confuse applications.
This happens if we hit case B of duplicate cookie processing.
In the particular example found and provided by Oscar Isaula
<Oscar.Isaula@motorola.com>, flow looks like this:
A B
---- INIT-------> (lost)
<---------INIT------
---- INIT-ACK--->
<------ Cookie ECHO
When the Cookie Echo is received, we end up trying to update the
association that was created on A as a result of the (lost) INIT,
but that association doesn't have the ID set yet.
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/sctp/command.h | 2 | ||||
| -rw-r--r-- | include/net/sctp/structs.h | 1 | ||||
| -rw-r--r-- | net/sctp/associola.c | 29 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 15 | ||||
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 35 | ||||
| -rw-r--r-- | net/sctp/sm_statefuns.c | 29 |
6 files changed, 80 insertions, 31 deletions
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 6114c4f54b0a..f56c8d695a82 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h | |||
| @@ -100,6 +100,8 @@ typedef enum { | |||
| 100 | SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */ | 100 | SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */ |
| 101 | SCTP_CMD_FORCE_PRIM_RETRAN, /* Forces retrans. over primary path. */ | 101 | SCTP_CMD_FORCE_PRIM_RETRAN, /* Forces retrans. over primary path. */ |
| 102 | SCTP_CMD_SET_SK_ERR, /* Set sk_err */ | 102 | SCTP_CMD_SET_SK_ERR, /* Set sk_err */ |
| 103 | SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */ | ||
| 104 | SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */ | ||
| 103 | SCTP_CMD_LAST | 105 | SCTP_CMD_LAST |
| 104 | } sctp_verb_t; | 106 | } sctp_verb_t; |
| 105 | 107 | ||
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7b4fff93ba7f..5e81984b8478 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
| @@ -1857,6 +1857,7 @@ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *, | |||
| 1857 | int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *, | 1857 | int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *, |
| 1858 | struct sctp_cookie*, | 1858 | struct sctp_cookie*, |
| 1859 | gfp_t gfp); | 1859 | gfp_t gfp); |
| 1860 | int sctp_assoc_set_id(struct sctp_association *, gfp_t); | ||
| 1860 | 1861 | ||
| 1861 | int sctp_cmp_addr_exact(const union sctp_addr *ss1, | 1862 | int sctp_cmp_addr_exact(const union sctp_addr *ss1, |
| 1862 | const union sctp_addr *ss2); | 1863 | const union sctp_addr *ss2); |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index db73ef97485a..df94e3cdfba3 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
| @@ -1103,6 +1103,13 @@ void sctp_assoc_update(struct sctp_association *asoc, | |||
| 1103 | asoc->ssnmap = new->ssnmap; | 1103 | asoc->ssnmap = new->ssnmap; |
| 1104 | new->ssnmap = NULL; | 1104 | new->ssnmap = NULL; |
| 1105 | } | 1105 | } |
| 1106 | |||
| 1107 | if (!asoc->assoc_id) { | ||
| 1108 | /* get a new association id since we don't have one | ||
| 1109 | * yet. | ||
| 1110 | */ | ||
| 1111 | sctp_assoc_set_id(asoc, GFP_ATOMIC); | ||
| 1112 | } | ||
| 1106 | } | 1113 | } |
| 1107 | } | 1114 | } |
| 1108 | 1115 | ||
| @@ -1375,3 +1382,25 @@ out: | |||
| 1375 | sctp_read_unlock(&asoc->base.addr_lock); | 1382 | sctp_read_unlock(&asoc->base.addr_lock); |
| 1376 | return found; | 1383 | return found; |
| 1377 | } | 1384 | } |
| 1385 | |||
| 1386 | /* Set an association id for a given association */ | ||
| 1387 | int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp) | ||
| 1388 | { | ||
| 1389 | int assoc_id; | ||
| 1390 | int error = 0; | ||
| 1391 | retry: | ||
| 1392 | if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp))) | ||
| 1393 | return -ENOMEM; | ||
| 1394 | |||
| 1395 | spin_lock_bh(&sctp_assocs_id_lock); | ||
| 1396 | error = idr_get_new_above(&sctp_assocs_id, (void *)asoc, | ||
| 1397 | 1, &assoc_id); | ||
| 1398 | spin_unlock_bh(&sctp_assocs_id_lock); | ||
| 1399 | if (error == -EAGAIN) | ||
| 1400 | goto retry; | ||
| 1401 | else if (error) | ||
| 1402 | return error; | ||
| 1403 | |||
| 1404 | asoc->assoc_id = (sctp_assoc_t) assoc_id; | ||
| 1405 | return error; | ||
| 1406 | } | ||
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index be783a3761c4..8d18f570c2e6 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
| @@ -1939,7 +1939,6 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, | |||
| 1939 | * association. | 1939 | * association. |
| 1940 | */ | 1940 | */ |
| 1941 | if (!asoc->temp) { | 1941 | if (!asoc->temp) { |
| 1942 | int assoc_id; | ||
| 1943 | int error; | 1942 | int error; |
| 1944 | 1943 | ||
| 1945 | asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams, | 1944 | asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams, |
| @@ -1947,19 +1946,9 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, | |||
| 1947 | if (!asoc->ssnmap) | 1946 | if (!asoc->ssnmap) |
| 1948 | goto clean_up; | 1947 | goto clean_up; |
| 1949 | 1948 | ||
| 1950 | retry: | 1949 | error = sctp_assoc_set_id(asoc, gfp); |
| 1951 | if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp))) | 1950 | if (error) |
| 1952 | goto clean_up; | 1951 | goto clean_up; |
| 1953 | spin_lock_bh(&sctp_assocs_id_lock); | ||
| 1954 | error = idr_get_new_above(&sctp_assocs_id, (void *)asoc, 1, | ||
| 1955 | &assoc_id); | ||
| 1956 | spin_unlock_bh(&sctp_assocs_id_lock); | ||
| 1957 | if (error == -EAGAIN) | ||
| 1958 | goto retry; | ||
| 1959 | else if (error) | ||
| 1960 | goto clean_up; | ||
| 1961 | |||
| 1962 | asoc->assoc_id = (sctp_assoc_t) assoc_id; | ||
| 1963 | } | 1952 | } |
| 1964 | 1953 | ||
| 1965 | /* ADDIP Section 4.1 ASCONF Chunk Procedures | 1954 | /* ADDIP Section 4.1 ASCONF Chunk Procedures |
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index b37a7adeb150..d9fad4f6ffc3 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
| @@ -862,6 +862,33 @@ static void sctp_cmd_set_sk_err(struct sctp_association *asoc, int error) | |||
| 862 | sk->sk_err = error; | 862 | sk->sk_err = error; |
| 863 | } | 863 | } |
| 864 | 864 | ||
| 865 | /* Helper function to generate an association change event */ | ||
| 866 | static void sctp_cmd_assoc_change(sctp_cmd_seq_t *commands, | ||
| 867 | struct sctp_association *asoc, | ||
| 868 | u8 state) | ||
| 869 | { | ||
| 870 | struct sctp_ulpevent *ev; | ||
| 871 | |||
| 872 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, state, 0, | ||
| 873 | asoc->c.sinit_num_ostreams, | ||
| 874 | asoc->c.sinit_max_instreams, | ||
| 875 | NULL, GFP_ATOMIC); | ||
| 876 | if (ev) | ||
| 877 | sctp_ulpq_tail_event(&asoc->ulpq, ev); | ||
| 878 | } | ||
| 879 | |||
| 880 | /* Helper function to generate an adaptation indication event */ | ||
| 881 | static void sctp_cmd_adaptation_ind(sctp_cmd_seq_t *commands, | ||
| 882 | struct sctp_association *asoc) | ||
| 883 | { | ||
| 884 | struct sctp_ulpevent *ev; | ||
| 885 | |||
| 886 | ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC); | ||
| 887 | |||
| 888 | if (ev) | ||
| 889 | sctp_ulpq_tail_event(&asoc->ulpq, ev); | ||
| 890 | } | ||
| 891 | |||
| 865 | /* These three macros allow us to pull the debugging code out of the | 892 | /* These three macros allow us to pull the debugging code out of the |
| 866 | * main flow of sctp_do_sm() to keep attention focused on the real | 893 | * main flow of sctp_do_sm() to keep attention focused on the real |
| 867 | * functionality there. | 894 | * functionality there. |
| @@ -1485,6 +1512,14 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
| 1485 | case SCTP_CMD_SET_SK_ERR: | 1512 | case SCTP_CMD_SET_SK_ERR: |
| 1486 | sctp_cmd_set_sk_err(asoc, cmd->obj.error); | 1513 | sctp_cmd_set_sk_err(asoc, cmd->obj.error); |
| 1487 | break; | 1514 | break; |
| 1515 | case SCTP_CMD_ASSOC_CHANGE: | ||
| 1516 | sctp_cmd_assoc_change(commands, asoc, | ||
| 1517 | cmd->obj.u8); | ||
| 1518 | break; | ||
| 1519 | case SCTP_CMD_ADAPTATION_IND: | ||
| 1520 | sctp_cmd_adaptation_ind(commands, asoc); | ||
| 1521 | break; | ||
| 1522 | |||
| 1488 | default: | 1523 | default: |
| 1489 | printk(KERN_WARNING "Impossible command: %u, %p\n", | 1524 | printk(KERN_WARNING "Impossible command: %u, %p\n", |
| 1490 | cmd->verb, cmd->obj.ptr); | 1525 | cmd->verb, cmd->obj.ptr); |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 9e28a5d51200..f02ce3dddb7b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -1656,7 +1656,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, | |||
| 1656 | struct sctp_association *new_asoc) | 1656 | struct sctp_association *new_asoc) |
| 1657 | { | 1657 | { |
| 1658 | sctp_init_chunk_t *peer_init; | 1658 | sctp_init_chunk_t *peer_init; |
| 1659 | struct sctp_ulpevent *ev; | ||
| 1660 | struct sctp_chunk *repl; | 1659 | struct sctp_chunk *repl; |
| 1661 | 1660 | ||
| 1662 | /* new_asoc is a brand-new association, so these are not yet | 1661 | /* new_asoc is a brand-new association, so these are not yet |
| @@ -1687,34 +1686,28 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, | |||
| 1687 | * D) IMPLEMENTATION NOTE: An implementation may choose to | 1686 | * D) IMPLEMENTATION NOTE: An implementation may choose to |
| 1688 | * send the Communication Up notification to the SCTP user | 1687 | * send the Communication Up notification to the SCTP user |
| 1689 | * upon reception of a valid COOKIE ECHO chunk. | 1688 | * upon reception of a valid COOKIE ECHO chunk. |
