diff options
| author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2007-11-09 11:43:41 -0500 |
|---|---|---|
| committer | Vlad Yasevich <vladislav.yasevich@hp.com> | 2007-11-09 11:43:41 -0500 |
| commit | 7ab9080467040054e27ae54d67cc185f24d881ae (patch) | |
| tree | 7364119d931501db9d8794294d037096a48d0863 | |
| parent | d970dbf8455eb1b8cebd3cde6e18f73dd1b3ce38 (diff) | |
SCTP: Make sctp_verify_param return multiple indications.
SCTP-AUTH and future ADD-IP updates have a requirement to
do additional verification of parameters and an ability to
ABORT the association if verification fails. So, introduce
additional return code so that we can clear signal a required
action.
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
| -rw-r--r-- | include/net/sctp/constants.h | 2 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 149 |
2 files changed, 77 insertions, 74 deletions
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 73fbdf6a24f8..f30b537d6952 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h | |||
| @@ -186,6 +186,8 @@ typedef enum { | |||
| 186 | SCTP_IERROR_AUTH_BAD_HMAC, | 186 | SCTP_IERROR_AUTH_BAD_HMAC, |
| 187 | SCTP_IERROR_AUTH_BAD_KEYID, | 187 | SCTP_IERROR_AUTH_BAD_KEYID, |
| 188 | SCTP_IERROR_PROTO_VIOLATION, | 188 | SCTP_IERROR_PROTO_VIOLATION, |
| 189 | SCTP_IERROR_ERROR, | ||
| 190 | SCTP_IERROR_ABORT, | ||
| 189 | } sctp_ierror_t; | 191 | } sctp_ierror_t; |
| 190 | 192 | ||
| 191 | 193 | ||
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 43e8de1228f9..5a9783c38de1 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
| @@ -1788,9 +1788,14 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc, | |||
| 1788 | sizeof(sctp_paramhdr_t); | 1788 | sizeof(sctp_paramhdr_t); |
| 1789 | 1789 | ||
| 1790 | 1790 | ||
| 1791 | /* This is a fatal error. Any accumulated non-fatal errors are | ||
| 1792 | * not reported. | ||
| 1793 | */ | ||
| 1794 | if (*errp) | ||
| 1795 | sctp_chunk_free(*errp); | ||
| 1796 | |||
| 1791 | /* Create an error chunk and fill it in with our payload. */ | 1797 | /* Create an error chunk and fill it in with our payload. */ |
| 1792 | if (!*errp) | 1798 | *errp = sctp_make_op_error_space(asoc, chunk, payload_len); |
| 1793 | *errp = sctp_make_op_error_space(asoc, chunk, payload_len); | ||
| 1794 | 1799 | ||
| 1795 | if (*errp) { | 1800 | if (*errp) { |
| 1796 | sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, | 1801 | sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, |
| @@ -1813,9 +1818,15 @@ static int sctp_process_hn_param(const struct sctp_association *asoc, | |||
| 1813 | { | 1818 | { |
| 1814 | __u16 len = ntohs(param.p->length); | 1819 | __u16 len = ntohs(param.p->length); |
| 1815 | 1820 | ||
| 1816 | /* Make an ERROR chunk. */ | 1821 | /* Processing of the HOST_NAME parameter will generate an |
| 1817 | if (!*errp) | 1822 | * ABORT. If we've accumulated any non-fatal errors, they |
| 1818 | *errp = sctp_make_op_error_space(asoc, chunk, len); | 1823 | * would be unrecognized parameters and we should not include |
| 1824 | * them in the ABORT. | ||
| 1825 | */ | ||
| 1826 | if (*errp) | ||
| 1827 | sctp_chunk_free(*errp); | ||
| 1828 | |||
| 1829 | *errp = sctp_make_op_error_space(asoc, chunk, len); | ||
| 1819 | 1830 | ||
| 1820 | if (*errp) { | 1831 | if (*errp) { |
| 1821 | sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len); | 1832 | sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len); |
| @@ -1862,56 +1873,40 @@ static void sctp_process_ext_param(struct sctp_association *asoc, | |||
| 1862 | * taken if the processing endpoint does not recognize the | 1873 | * taken if the processing endpoint does not recognize the |
| 1863 | * Parameter Type. | 1874 | * Parameter Type. |
| 1864 | * | 1875 | * |
| 1865 | * 00 - Stop processing this SCTP chunk and discard it, | 1876 | * 00 - Stop processing this parameter; do not process any further |
| 1866 | * do not process any further chunks within it. | 1877 | * parameters within this chunk |
| 1867 | * | 1878 | * |
| 1868 | * 01 - Stop processing this SCTP chunk and discard it, | 1879 | * 01 - Stop processing this parameter, do not process any further |
| 1869 | * do not process any further chunks within it, and report | 1880 | * parameters within this chunk, and report the unrecognized |
| 1870 | * the unrecognized parameter in an 'Unrecognized | 1881 | * parameter in an 'Unrecognized Parameter' ERROR chunk. |
| 1871 | * Parameter Type' (in either an ERROR or in the INIT ACK). | ||
| 1872 | * | 1882 | * |
| 1873 | * 10 - Skip this parameter and continue processing. | 1883 | * 10 - Skip this parameter and continue processing. |
| 1874 | * | 1884 | * |
| 1875 | * 11 - Skip this parameter and continue processing but | 1885 | * 11 - Skip this parameter and continue processing but |
| 1876 | * report the unrecognized parameter in an | 1886 | * report the unrecognized parameter in an |
| 1877 | * 'Unrecognized Parameter Type' (in either an ERROR or in | 1887 | * 'Unrecognized Parameter' ERROR chunk. |
| 1878 | * the INIT ACK). | ||
| 1879 | * | 1888 | * |
| 1880 | * Return value: | 1889 | * Return value: |
| 1881 | * 0 - discard the chunk | 1890 | * SCTP_IERROR_NO_ERROR - continue with the chunk |
| 1882 | * 1 - continue with the chunk | 1891 | * SCTP_IERROR_ERROR - stop and report an error. |
| 1892 | * SCTP_IERROR_NOMEME - out of memory. | ||
| 1883 | */ | 1893 | */ |
| 1884 | static int sctp_process_unk_param(const struct sctp_association *asoc, | 1894 | static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc, |
| 1885 | union sctp_params param, | 1895 | union sctp_params param, |
| 1886 | struct sctp_chunk *chunk, | 1896 | struct sctp_chunk *chunk, |
| 1887 | struct sctp_chunk **errp) | 1897 | struct sctp_chunk **errp) |
| 1888 | { | 1898 | { |
| 1889 | int retval = 1; | 1899 | int retval = SCTP_IERROR_NO_ERROR; |
| 1890 | 1900 | ||
| 1891 | switch (param.p->type & SCTP_PARAM_ACTION_MASK) { | 1901 | switch (param.p->type & SCTP_PARAM_ACTION_MASK) { |
| 1892 | case SCTP_PARAM_ACTION_DISCARD: | 1902 | case SCTP_PARAM_ACTION_DISCARD: |
| 1893 | retval = 0; | 1903 | retval = SCTP_IERROR_ERROR; |
| 1894 | break; | ||
| 1895 | case SCTP_PARAM_ACTION_DISCARD_ERR: | ||
| 1896 | retval = 0; | ||
| 1897 | /* Make an ERROR chunk, preparing enough room for | ||
| 1898 | * returning multiple unknown parameters. | ||
| 1899 | */ | ||
| 1900 | if (NULL == *errp) | ||
| 1901 | *errp = sctp_make_op_error_space(asoc, chunk, | ||
| 1902 | ntohs(chunk->chunk_hdr->length)); | ||
| 1903 | |||
| 1904 | if (*errp) { | ||
| 1905 | sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, | ||
| 1906 | WORD_ROUND(ntohs(param.p->length))); | ||
| 1907 | sctp_addto_chunk(*errp, | ||
| 1908 | WORD_ROUND(ntohs(param.p->length)), | ||
| 1909 | param.v); | ||
| 1910 | } | ||
| 1911 | |||
| 1912 | break; | 1904 | break; |
| 1913 | case SCTP_PARAM_ACTION_SKIP: | 1905 | case SCTP_PARAM_ACTION_SKIP: |
| 1914 | break; | 1906 | break; |
| 1907 | case SCTP_PARAM_ACTION_DISCARD_ERR: | ||
| 1908 | retval = SCTP_IERROR_ERROR; | ||
| 1909 | /* Fall through */ | ||
| 1915 | case SCTP_PARAM_ACTION_SKIP_ERR: | 1910 | case SCTP_PARAM_ACTION_SKIP_ERR: |
| 1916 | /* Make an ERROR chunk, preparing enough room for | 1911 | /* Make an ERROR chunk, preparing enough room for |
| 1917 | * returning multiple unknown parameters. | 1912 | * returning multiple unknown parameters. |
| @@ -1932,9 +1927,8 @@ static int sctp_process_unk_param(const struct sctp_association *asoc, | |||
| 1932 | * to the peer and the association won't be | 1927 | * to the peer and the association won't be |
| 1933 | * established. | 1928 | * established. |
| 1934 | */ | 1929 | */ |
| 1935 | retval = 0; | 1930 | retval = SCTP_IERROR_NOMEM; |
| 1936 | } | 1931 | } |
| 1937 | |||
| 1938 | break; | 1932 | break; |
| 1939 | default: | 1933 | default: |
| 1940 | break; | 1934 | break; |
| @@ -1943,18 +1937,20 @@ static int sctp_process_unk_param(const struct sctp_association *asoc, | |||
| 1943 | return retval; | 1937 | return retval; |
| 1944 | } | 1938 | } |
| 1945 | 1939 | ||
| 1946 | /* Find unrecognized parameters in the chunk. | 1940 | /* Verify variable length parameters |
| 1947 | * Return values: | 1941 | * Return values: |
| 1948 | * 0 - discard the chunk | 1942 | * SCTP_IERROR_ABORT - trigger an ABORT |
| 1949 | * 1 - continue with the chunk | 1943 | * SCTP_IERROR_NOMEM - out of memory (abort) |
| 1944 | * SCTP_IERROR_ERROR - stop processing, trigger an ERROR | ||
| 1945 | * SCTP_IERROR_NO_ERROR - continue with the chunk | ||
| 1950 | */ | 1946 | */ |
| 1951 | static int sctp_verify_param(const struct sctp_association *asoc, | 1947 | static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc, |
| 1952 | union sctp_params param, | 1948 | union sctp_params param, |
| 1953 | sctp_cid_t cid, | 1949 | sctp_cid_t cid, |
| 1954 | struct sctp_chunk *chunk, | 1950 | struct sctp_chunk *chunk, |
| 1955 | struct sctp_chunk **err_chunk) | 1951 | struct sctp_chunk **err_chunk) |
| 1956 | { | 1952 | { |
| 1957 | int retval = 1; | 1953 | int retval = SCTP_IERROR_NO_ERROR; |
| 1958 | 1954 | ||
| 1959 | /* FIXME - This routine is not looking at each parameter per the | 1955 | /* FIXME - This routine is not looking at each parameter per the |
| 1960 | * chunk type, i.e., unrecognized parameters should be further | 1956 | * chunk type, i.e., unrecognized parameters should be further |
| @@ -1976,7 +1972,9 @@ static int sctp_verify_param(const struct sctp_association *asoc, | |||
| 1976 | 1972 | ||
| 1977 | case SCTP_PARAM_HOST_NAME_ADDRESS: | 1973 | case SCTP_PARAM_HOST_NAME_ADDRESS: |
| 1978 | /* Tell the peer, we won't support this param. */ | 1974 | /* Tell the peer, we won't support this param. */ |
| 1979 | return sctp_process_hn_param(asoc, param, chunk, err_chunk); | 1975 | sctp_process_hn_param(asoc, param, chunk, err_chunk); |
| 1976 | retval = SCTP_IERROR_ABORT; | ||
| 1977 | break; | ||
| 1980 | 1978 | ||
| 1981 | case SCTP_PARAM_FWD_TSN_SUPPORT: | 1979 | case SCTP_PARAM_FWD_TSN_SUPPORT: |
| 1982 | if (sctp_prsctp_enable) | 1980 | if (sctp_prsctp_enable) |
| @@ -1993,9 +1991,11 @@ static int sctp_verify_param(const struct sctp_association *asoc, | |||
| 1993 | * cause 'Protocol Violation'. | 1991 | * cause 'Protocol Violation'. |
| 1994 | */ | 1992 | */ |
| 1995 | if (SCTP_AUTH_RANDOM_LENGTH != | 1993 | if (SCTP_AUTH_RANDOM_LENGTH != |
| 1996 | ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) | 1994 | ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) { |
| 1997 | return sctp_process_inv_paramlength(asoc, param.p, | 1995 | sctp_process_inv_paramlength(asoc, param.p, |
| 1998 | chunk, err_chunk); | 1996 | chunk, err_chunk); |
| 1997 | retval = SCTP_IERROR_ABORT; | ||
| 1998 | } | ||
| 1999 | break; | 1999 | break; |
| 2000 | 2000 | ||
| 2001 | case SCTP_PARAM_CHUNKS: | 2001 | case SCTP_PARAM_CHUNKS: |
| @@ -2007,9 +2007,11 @@ static int sctp_verify_param(const struct sctp_association *asoc, | |||
| 2007 | * INIT-ACK chunk if the sender wants to receive authenticated | 2007 | * INIT-ACK chunk if the sender wants to receive authenticated |
| 2008 | * chunks. Its maximum length is 260 bytes. | 2008 | * chunks. Its maximum length is 260 bytes. |
| 2009 | */ | 2009 | */ |
| 2010 | if (260 < ntohs(param.p->length)) | 2010 | if (260 < ntohs(param.p->length)) { |
| 2011 | return sctp_process_inv_paramlength(asoc, param.p, | 2011 | sctp_process_inv_paramlength(asoc, param.p, |
| 2012 | chunk, err_chunk); | 2012 | chunk, err_chunk); |
| 2013 | retval = SCTP_IERROR_ABORT; | ||
| 2014 | } | ||
| 2013 | break; | 2015 | break; |
| 2014 | 2016 | ||
| 2015 | case SCTP_PARAM_HMAC_ALGO: | 2017 | case SCTP_PARAM_HMAC_ALGO: |
| @@ -2020,8 +2022,7 @@ fallthrough: | |||
| 2020 | default: | 2022 | default: |
| 2021 | SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", | 2023 | SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", |
| 2022 | ntohs(param.p->type), cid); | 2024 | ntohs(param.p->type), cid); |
| 2023 | return sctp_process_unk_param(asoc, param, chunk, err_chunk); | 2025 | retval = sctp_process_unk_param(asoc, param, chunk, err_chunk); |
| 2024 | |||
| 2025 | break; | 2026 | break; |
| 2026 | } | 2027 | } |
| 2027 | return retval; | 2028 | return retval; |
| @@ -2036,6 +2037,7 @@ int sctp_verify_init(const struct sctp_association *asoc, | |||
| 2036 | { | 2037 | { |
| 2037 | union sctp_params param; | 2038 | union sctp_params param; |
| 2038 | int has_cookie = 0; | 2039 | int has_cookie = 0; |
| 2040 | int result; | ||
| 2039 | 2041 | ||
| 2040 | /* Verify stream values are non-zero. */ | 2042 | /* Verify stream values are non-zero. */ |
| 2041 | if ((0 == peer_init->init_hdr.num_outbound_streams) || | 2043 | if ((0 == peer_init->init_hdr.num_outbound_streams) || |
| @@ -2043,8 +2045,7 @@ int sctp_verify_init(const struct sctp_association *asoc, | |||
| 2043 | (0 == peer_init->init_hdr.init_tag) || | 2045 | (0 == peer_init->init_hdr.init_tag) || |
| 2044 | (SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) { | 2046 | (SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) { |
| 2045 | 2047 | ||
| 2046 | sctp_process_inv_mandatory(asoc, chunk, errp); | 2048 | return sctp_process_inv_mandatory(asoc, chunk, errp); |
| 2047 | return 0; | ||
| 2048 | } | 2049 | } |
| 2049 | 2050 | ||
| 2050 | /* Check for missing mandatory parameters. */ | 2051 | /* Check for missing mandatory parameters. */ |
| @@ -2062,29 +2063,29 @@ int sctp_verify_init(const struct sctp_association *asoc, | |||
| 2062 | * VIOLATION error. We build the ERROR chunk here and let the normal | 2063 | * VIOLATION error. We build the ERROR chunk here and let the normal |
| 2063 | * error handling code build and send the packet. | 2064 | * error handling code build and send the packet. |
| 2064 | */ | 2065 | */ |
| 2065 | if (param.v != (void*)chunk->chunk_end) { | 2066 | if (param.v != (void*)chunk->chunk_end) |
| 2066 | sctp_process_inv_paramlength(asoc, param.p, chunk, errp); | 2067 | return sctp_process_inv_paramlength(asoc, param.p, chunk, errp); |
| 2067 | return 0; | ||
| 2068 | } | ||
| 2069 | 2068 | ||
| 2070 | /* The only missing mandatory param possible today is | 2069 | /* The only missing mandatory param possible today is |
| 2071 | * the state cookie for an INIT-ACK chunk. | 2070 | * the state cookie for an INIT-ACK chunk. |
| 2072 | */ | 2071 | */ |
| 2073 | if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) { | 2072 | if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) |
| 2074 | sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, | 2073 | return sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, |
| 2075 | chunk, errp); | 2074 | chunk, errp); |
| 2076 | return 0; | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | /* Find unrecognized parameters. */ | ||
| 2080 | 2075 | ||
| 2076 | /* Verify all the variable length parameters */ | ||
| 2081 | sctp_walk_params(param, peer_init, init_hdr.params) { | 2077 | sctp_walk_params(param, peer_init, init_hdr.params) { |
| 2082 | 2078 | ||
| 2083 | if (!sctp_verify_param(asoc, param, cid, chunk, errp)) { | 2079 | result = sctp_verify_param(asoc, param, cid, chunk, errp); |
| 2084 | if (SCTP_PARAM_HOST_NAME_ADDRESS == param.p->type) | 2080 | switch (result) { |
| 2081 | case SCTP_IERROR_ABORT: | ||
| 2082 | case SCTP_IERROR_NOMEM: | ||
| 2085 | return 0; | 2083 | return 0; |
| 2086 | else | 2084 | case SCTP_IERROR_ERROR: |
| 2087 | return 1; | 2085 | return 1; |
| 2086 | case SCTP_IERROR_NO_ERROR: | ||
| 2087 | default: | ||
| 2088 | break; | ||
| 2088 | } | 2089 | } |
| 2089 | 2090 | ||
| 2090 | } /* for (loop through all parameters) */ | 2091 | } /* for (loop through all parameters) */ |
