Commit 5483ecef authored by David S. Miller's avatar David S. Miller

Merge branch 'sctp-support-per-endpoint-auth-and-asconf-flags'

Xin Long says:

====================
sctp: support per endpoint auth and asconf flags

This patchset mostly does 3 things:

  1. add per endpint asconf flag and use asconf flag properly
     and add SCTP_ASCONF_SUPPORTED sockopt.
  2. use auth flag properly and add SCTP_AUTH_SUPPORTED sockopt.
  3. remove the 'global feature switch' to discard chunks.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents af809709 2f757634
...@@ -107,5 +107,7 @@ int sctp_auth_del_key_id(struct sctp_endpoint *ep, ...@@ -107,5 +107,7 @@ int sctp_auth_del_key_id(struct sctp_endpoint *ep,
struct sctp_association *asoc, __u16 key_id); struct sctp_association *asoc, __u16 key_id);
int sctp_auth_deact_key_id(struct sctp_endpoint *ep, int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
struct sctp_association *asoc, __u16 key_id); struct sctp_association *asoc, __u16 key_id);
int sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp);
void sctp_auth_free(struct sctp_endpoint *ep);
#endif #endif
...@@ -1325,6 +1325,7 @@ struct sctp_endpoint { ...@@ -1325,6 +1325,7 @@ struct sctp_endpoint {
__u8 auth_enable:1, __u8 auth_enable:1,
intl_enable:1, intl_enable:1,
prsctp_enable:1, prsctp_enable:1,
asconf_enable:1,
reconf_enable:1; reconf_enable:1;
__u8 strreset_enable; __u8 strreset_enable;
......
...@@ -134,6 +134,8 @@ typedef __s32 sctp_assoc_t; ...@@ -134,6 +134,8 @@ typedef __s32 sctp_assoc_t;
#define SCTP_INTERLEAVING_SUPPORTED 125 #define SCTP_INTERLEAVING_SUPPORTED 125
#define SCTP_SENDMSG_CONNECT 126 #define SCTP_SENDMSG_CONNECT 126
#define SCTP_EVENT 127 #define SCTP_EVENT 127
#define SCTP_ASCONF_SUPPORTED 128
#define SCTP_AUTH_SUPPORTED 129
/* PR-SCTP policies */ /* PR-SCTP policies */
#define SCTP_PR_SCTP_NONE 0x0000 #define SCTP_PR_SCTP_NONE 0x0000
......
...@@ -54,7 +54,6 @@ static struct sctp_association *sctp_association_init( ...@@ -54,7 +54,6 @@ static struct sctp_association *sctp_association_init(
const struct sock *sk, const struct sock *sk,
enum sctp_scope scope, gfp_t gfp) enum sctp_scope scope, gfp_t gfp)
{ {
struct net *net = sock_net(sk);
struct sctp_sock *sp; struct sctp_sock *sp;
struct sctp_paramhdr *p; struct sctp_paramhdr *p;
int i; int i;
...@@ -214,14 +213,6 @@ static struct sctp_association *sctp_association_init( ...@@ -214,14 +213,6 @@ static struct sctp_association *sctp_association_init(
asoc->peer.sack_needed = 1; asoc->peer.sack_needed = 1;
asoc->peer.sack_generation = 1; asoc->peer.sack_generation = 1;
/* Assume that the peer will tell us if he recognizes ASCONF
* as part of INIT exchange.
* The sctp_addip_noauth option is there for backward compatibility
* and will revert old behavior.
*/
if (net->sctp.addip_noauth)
asoc->peer.asconf_capable = 1;
/* Create an input queue. */ /* Create an input queue. */
sctp_inq_init(&asoc->base.inqueue); sctp_inq_init(&asoc->base.inqueue);
sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv); sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv);
......
...@@ -389,7 +389,7 @@ int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp) ...@@ -389,7 +389,7 @@ int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
/* If we don't support AUTH, or peer is not capable /* If we don't support AUTH, or peer is not capable
* we don't need to do anything. * we don't need to do anything.
*/ */
if (!asoc->ep->auth_enable || !asoc->peer.auth_capable) if (!asoc->peer.auth_capable)
return 0; return 0;
/* If the key_id is non-zero and we couldn't find an /* If the key_id is non-zero and we couldn't find an
...@@ -675,7 +675,7 @@ int sctp_auth_send_cid(enum sctp_cid chunk, const struct sctp_association *asoc) ...@@ -675,7 +675,7 @@ int sctp_auth_send_cid(enum sctp_cid chunk, const struct sctp_association *asoc)
if (!asoc) if (!asoc)
return 0; return 0;
if (!asoc->ep->auth_enable || !asoc->peer.auth_capable) if (!asoc->peer.auth_capable)
return 0; return 0;
return __sctp_auth_cid(chunk, asoc->peer.peer_chunks); return __sctp_auth_cid(chunk, asoc->peer.peer_chunks);
...@@ -687,7 +687,7 @@ int sctp_auth_recv_cid(enum sctp_cid chunk, const struct sctp_association *asoc) ...@@ -687,7 +687,7 @@ int sctp_auth_recv_cid(enum sctp_cid chunk, const struct sctp_association *asoc)
if (!asoc) if (!asoc)
return 0; return 0;
if (!asoc->ep->auth_enable) if (!asoc->peer.auth_capable)
return 0; return 0;
return __sctp_auth_cid(chunk, return __sctp_auth_cid(chunk,
...@@ -831,10 +831,15 @@ int sctp_auth_set_key(struct sctp_endpoint *ep, ...@@ -831,10 +831,15 @@ int sctp_auth_set_key(struct sctp_endpoint *ep,
/* Try to find the given key id to see if /* Try to find the given key id to see if
* we are doing a replace, or adding a new key * we are doing a replace, or adding a new key
*/ */
if (asoc) if (asoc) {
if (!asoc->peer.auth_capable)
return -EACCES;
sh_keys = &asoc->endpoint_shared_keys; sh_keys = &asoc->endpoint_shared_keys;
else } else {
if (!ep->auth_enable)
return -EACCES;
sh_keys = &ep->endpoint_shared_keys; sh_keys = &ep->endpoint_shared_keys;
}
key_for_each(shkey, sh_keys) { key_for_each(shkey, sh_keys) {
if (shkey->key_id == auth_key->sca_keynumber) { if (shkey->key_id == auth_key->sca_keynumber) {
...@@ -875,10 +880,15 @@ int sctp_auth_set_active_key(struct sctp_endpoint *ep, ...@@ -875,10 +880,15 @@ int sctp_auth_set_active_key(struct sctp_endpoint *ep,
int found = 0; int found = 0;
/* The key identifier MUST correst to an existing key */ /* The key identifier MUST correst to an existing key */
if (asoc) if (asoc) {
if (!asoc->peer.auth_capable)
return -EACCES;
sh_keys = &asoc->endpoint_shared_keys; sh_keys = &asoc->endpoint_shared_keys;
else } else {
if (!ep->auth_enable)
return -EACCES;
sh_keys = &ep->endpoint_shared_keys; sh_keys = &ep->endpoint_shared_keys;
}
key_for_each(key, sh_keys) { key_for_each(key, sh_keys) {
if (key->key_id == key_id) { if (key->key_id == key_id) {
...@@ -911,11 +921,15 @@ int sctp_auth_del_key_id(struct sctp_endpoint *ep, ...@@ -911,11 +921,15 @@ int sctp_auth_del_key_id(struct sctp_endpoint *ep,
* The key identifier MUST correst to an existing key * The key identifier MUST correst to an existing key
*/ */
if (asoc) { if (asoc) {
if (!asoc->peer.auth_capable)
return -EACCES;
if (asoc->active_key_id == key_id) if (asoc->active_key_id == key_id)
return -EINVAL; return -EINVAL;
sh_keys = &asoc->endpoint_shared_keys; sh_keys = &asoc->endpoint_shared_keys;
} else { } else {
if (!ep->auth_enable)
return -EACCES;
if (ep->active_key_id == key_id) if (ep->active_key_id == key_id)
return -EINVAL; return -EINVAL;
...@@ -950,11 +964,15 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep, ...@@ -950,11 +964,15 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
* The key identifier MUST correst to an existing key * The key identifier MUST correst to an existing key
*/ */
if (asoc) { if (asoc) {
if (!asoc->peer.auth_capable)
return -EACCES;
if (asoc->active_key_id == key_id) if (asoc->active_key_id == key_id)
return -EINVAL; return -EINVAL;
sh_keys = &asoc->endpoint_shared_keys; sh_keys = &asoc->endpoint_shared_keys;
} else { } else {
if (!ep->auth_enable)
return -EACCES;
if (ep->active_key_id == key_id) if (ep->active_key_id == key_id)
return -EINVAL; return -EINVAL;
...@@ -989,3 +1007,72 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep, ...@@ -989,3 +1007,72 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
return 0; return 0;
} }
int sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp)
{
int err = -ENOMEM;
/* Allocate space for HMACS and CHUNKS authentication
* variables. There are arrays that we encode directly
* into parameters to make the rest of the operations easier.
*/
if (!ep->auth_hmacs_list) {
struct sctp_hmac_algo_param *auth_hmacs;
auth_hmacs = kzalloc(struct_size(auth_hmacs, hmac_ids,
SCTP_AUTH_NUM_HMACS), gfp);
if (!auth_hmacs)
goto nomem;
/* Initialize the HMACS parameter.
* SCTP-AUTH: Section 3.3
* Every endpoint supporting SCTP chunk authentication MUST
* support the HMAC based on the SHA-1 algorithm.
*/
auth_hmacs->param_hdr.type = SCTP_PARAM_HMAC_ALGO;
auth_hmacs->param_hdr.length =
htons(sizeof(struct sctp_paramhdr) + 2);
auth_hmacs->hmac_ids[0] = htons(SCTP_AUTH_HMAC_ID_SHA1);
ep->auth_hmacs_list = auth_hmacs;
}
if (!ep->auth_chunk_list) {
struct sctp_chunks_param *auth_chunks;
auth_chunks = kzalloc(sizeof(*auth_chunks) +
SCTP_NUM_CHUNK_TYPES, gfp);
if (!auth_chunks)
goto nomem;
/* Initialize the CHUNKS parameter */
auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS;
auth_chunks->param_hdr.length =
htons(sizeof(struct sctp_paramhdr));
ep->auth_chunk_list = auth_chunks;
}
/* Allocate and initialize transorms arrays for supported
* HMACs.
*/
err = sctp_auth_init_hmacs(ep, gfp);
if (err)
goto nomem;
return 0;
nomem:
/* Free all allocations */
kfree(ep->auth_hmacs_list);
kfree(ep->auth_chunk_list);
ep->auth_hmacs_list = NULL;
ep->auth_chunk_list = NULL;
return err;
}
void sctp_auth_free(struct sctp_endpoint *ep)
{
kfree(ep->auth_hmacs_list);
kfree(ep->auth_chunk_list);
ep->auth_hmacs_list = NULL;
ep->auth_chunk_list = NULL;
sctp_auth_destroy_hmacs(ep->auth_hmacs);
ep->auth_hmacs = NULL;
}
...@@ -43,62 +43,21 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ...@@ -43,62 +43,21 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
gfp_t gfp) gfp_t gfp)
{ {
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct sctp_hmac_algo_param *auth_hmacs = NULL;
struct sctp_chunks_param *auth_chunks = NULL;
struct sctp_shared_key *null_key; struct sctp_shared_key *null_key;
int err;
ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp); ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp);
if (!ep->digest) if (!ep->digest)
return NULL; return NULL;
ep->asconf_enable = net->sctp.addip_enable;
ep->auth_enable = net->sctp.auth_enable; ep->auth_enable = net->sctp.auth_enable;
if (ep->auth_enable) { if (ep->auth_enable) {
/* Allocate space for HMACS and CHUNKS authentication if (sctp_auth_init(ep, gfp))
* variables. There are arrays that we encode directly
* into parameters to make the rest of the operations easier.
*/
auth_hmacs = kzalloc(struct_size(auth_hmacs, hmac_ids,
SCTP_AUTH_NUM_HMACS), gfp);
if (!auth_hmacs)
goto nomem;
auth_chunks = kzalloc(sizeof(*auth_chunks) +
SCTP_NUM_CHUNK_TYPES, gfp);
if (!auth_chunks)
goto nomem; goto nomem;
if (ep->asconf_enable) {
/* Initialize the HMACS parameter. sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
* SCTP-AUTH: Section 3.3 sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
* Every endpoint supporting SCTP chunk authentication MUST
* support the HMAC based on the SHA-1 algorithm.
*/
auth_hmacs->param_hdr.type = SCTP_PARAM_HMAC_ALGO;
auth_hmacs->param_hdr.length =
htons(sizeof(struct sctp_paramhdr) + 2);
auth_hmacs->hmac_ids[0] = htons(SCTP_AUTH_HMAC_ID_SHA1);
/* Initialize the CHUNKS parameter */
auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS;
auth_chunks->param_hdr.length =
htons(sizeof(struct sctp_paramhdr));
/* If the Add-IP functionality is enabled, we must
* authenticate, ASCONF and ASCONF-ACK chunks
*/
if (net->sctp.addip_enable) {
auth_chunks->chunks[0] = SCTP_CID_ASCONF;
auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK;
auth_chunks->param_hdr.length =
htons(sizeof(struct sctp_paramhdr) + 2);
} }
/* Allocate and initialize transorms arrays for supported
* HMACs.
*/
err = sctp_auth_init_hmacs(ep, gfp);
if (err)
goto nomem;
} }
/* Initialize the base structure. */ /* Initialize the base structure. */
...@@ -145,8 +104,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ...@@ -145,8 +104,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
/* Add the null key to the endpoint shared keys list and /* Add the null key to the endpoint shared keys list and
* set the hmcas and chunks pointers. * set the hmcas and chunks pointers.
*/ */
ep->auth_hmacs_list = auth_hmacs;
ep->auth_chunk_list = auth_chunks;
ep->prsctp_enable = net->sctp.prsctp_enable; ep->prsctp_enable = net->sctp.prsctp_enable;
ep->reconf_enable = net->sctp.reconf_enable; ep->reconf_enable = net->sctp.reconf_enable;
...@@ -157,11 +114,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ...@@ -157,11 +114,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
return ep; return ep;
nomem_shkey: nomem_shkey:
sctp_auth_destroy_hmacs(ep->auth_hmacs); sctp_auth_free(ep);
nomem: nomem:
/* Free all allocations */
kfree(auth_hmacs);
kfree(auth_chunks);
kfree(ep->digest); kfree(ep->digest);
return NULL; return NULL;
...@@ -244,11 +198,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) ...@@ -244,11 +198,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
* chunks and hmacs arrays that were allocated * chunks and hmacs arrays that were allocated
*/ */
sctp_auth_destroy_keys(&ep->endpoint_shared_keys); sctp_auth_destroy_keys(&ep->endpoint_shared_keys);
kfree(ep->auth_hmacs_list); sctp_auth_free(ep);
kfree(ep->auth_chunk_list);
/* AUTH - Free any allocated HMAC transform containers */
sctp_auth_destroy_hmacs(ep->auth_hmacs);
/* Cleanup. */ /* Cleanup. */
sctp_inq_free(&ep->base.inqueue); sctp_inq_free(&ep->base.inqueue);
......
...@@ -207,7 +207,6 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, ...@@ -207,7 +207,6 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
const struct sctp_bind_addr *bp, const struct sctp_bind_addr *bp,
gfp_t gfp, int vparam_len) gfp_t gfp, int vparam_len)
{ {
struct net *net = sock_net(asoc->base.sk);
struct sctp_supported_ext_param ext_param; struct sctp_supported_ext_param ext_param;
struct sctp_adaptation_ind_param aiparam; struct sctp_adaptation_ind_param aiparam;
struct sctp_paramhdr *auth_chunks = NULL; struct sctp_paramhdr *auth_chunks = NULL;
...@@ -255,7 +254,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, ...@@ -255,7 +254,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
* the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and * the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and
* INIT-ACK parameters. * INIT-ACK parameters.
*/ */
if (net->sctp.addip_enable) { if (asoc->ep->asconf_enable) {
extensions[num_ext] = SCTP_CID_ASCONF; extensions[num_ext] = SCTP_CID_ASCONF;
extensions[num_ext+1] = SCTP_CID_ASCONF_ACK; extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
num_ext += 2; num_ext += 2;
...@@ -1964,7 +1963,9 @@ static int sctp_process_hn_param(const struct sctp_association *asoc, ...@@ -1964,7 +1963,9 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
return 0; return 0;
} }
static int sctp_verify_ext_param(struct net *net, union sctp_params param) static int sctp_verify_ext_param(struct net *net,
const struct sctp_endpoint *ep,
union sctp_params param)
{ {
__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); __u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
int have_asconf = 0; int have_asconf = 0;
...@@ -1991,7 +1992,7 @@ static int sctp_verify_ext_param(struct net *net, union sctp_params param) ...@@ -1991,7 +1992,7 @@ static int sctp_verify_ext_param(struct net *net, union sctp_params param)
if (net->sctp.addip_noauth) if (net->sctp.addip_noauth)
return 1; return 1;
if (net->sctp.addip_enable && !have_auth && have_asconf) if (ep->asconf_enable && !have_auth && have_asconf)
return 0; return 0;
return 1; return 1;
...@@ -2001,7 +2002,6 @@ static void sctp_process_ext_param(struct sctp_association *asoc, ...@@ -2001,7 +2002,6 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
union sctp_params param) union sctp_params param)
{ {
__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); __u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
struct net *net = sock_net(asoc->base.sk);
int i; int i;
for (i = 0; i < num_ext; i++) { for (i = 0; i < num_ext; i++) {
...@@ -2023,7 +2023,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc, ...@@ -2023,7 +2023,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
break; break;
case SCTP_CID_ASCONF: case SCTP_CID_ASCONF:
case SCTP_CID_ASCONF_ACK: case SCTP_CID_ASCONF_ACK:
if (net->sctp.addip_enable) if (asoc->ep->asconf_enable)
asoc->peer.asconf_capable = 1; asoc->peer.asconf_capable = 1;
break; break;
case SCTP_CID_I_DATA: case SCTP_CID_I_DATA:
...@@ -2145,12 +2145,12 @@ static enum sctp_ierror sctp_verify_param(struct net *net, ...@@ -2145,12 +2145,12 @@ static enum sctp_ierror sctp_verify_param(struct net *net,
break; break;
case SCTP_PARAM_SUPPORTED_EXT: case SCTP_PARAM_SUPPORTED_EXT:
if (!sctp_verify_ext_param(net, param)) if (!sctp_verify_ext_param(net, ep, param))
return SCTP_IERROR_ABORT; return SCTP_IERROR_ABORT;
break; break;
case SCTP_PARAM_SET_PRIMARY: case SCTP_PARAM_SET_PRIMARY:
if (net->sctp.addip_enable) if (ep->asconf_enable)
break; break;
goto fallthrough; goto fallthrough;
...@@ -2605,7 +2605,7 @@ static int sctp_process_param(struct sctp_association *asoc, ...@@ -2605,7 +2605,7 @@ static int sctp_process_param(struct sctp_association *asoc,
break; break;
case SCTP_PARAM_SET_PRIMARY: case SCTP_PARAM_SET_PRIMARY:
if (!net->sctp.addip_enable) if (!ep->asconf_enable)
goto fall_through; goto fall_through;
addr_param = param.v + sizeof(struct sctp_addip_param); addr_param = param.v + sizeof(struct sctp_addip_param);
......
...@@ -3721,7 +3721,8 @@ enum sctp_disposition sctp_sf_do_asconf(struct net *net, ...@@ -3721,7 +3721,8 @@ enum sctp_disposition sctp_sf_do_asconf(struct net *net,
* is received unauthenticated it MUST be silently discarded as * is received unauthenticated it MUST be silently discarded as
* described in [I-D.ietf-tsvwg-sctp-auth]. * described in [I-D.ietf-tsvwg-sctp-auth].
*/ */
if (!net->sctp.addip_noauth && !chunk->auth) if (!asoc->peer.asconf_capable ||
(!net->sctp.addip_noauth && !chunk->auth))
return sctp_sf_discard_chunk(net, ep, asoc, type, arg, return sctp_sf_discard_chunk(net, ep, asoc, type, arg,
commands); commands);
...@@ -3863,7 +3864,8 @@ enum sctp_disposition sctp_sf_do_asconf_ack(struct net *net, ...@@ -3863,7 +3864,8 @@ enum sctp_disposition sctp_sf_do_asconf_ack(struct net *net,
* is received unauthenticated it MUST be silently discarded as * is received unauthenticated it MUST be silently discarded as
* described in [I-D.ietf-tsvwg-sctp-auth]. * described in [I-D.ietf-tsvwg-sctp-auth].
*/ */
if (!net->sctp.addip_noauth && !asconf_ack->auth) if (!asoc->peer.asconf_capable ||
(!net->sctp.addip_noauth && !asconf_ack->auth))
return sctp_sf_discard_chunk(net, ep, asoc, type, arg, return sctp_sf_discard_chunk(net, ep, asoc, type, arg,
commands); commands);
......
...@@ -976,26 +976,22 @@ static const struct sctp_sm_table_entry *sctp_chunk_event_lookup( ...@@ -976,26 +976,22 @@ static const struct sctp_sm_table_entry *sctp_chunk_event_lookup(
if (cid <= SCTP_CID_BASE_MAX) if (cid <= SCTP_CID_BASE_MAX)
return &chunk_event_table[cid][state]; return &chunk_event_table[cid][state];
if (net->sctp.prsctp_enable) { switch ((u16)cid) {
if (cid == SCTP_CID_FWD_TSN || cid == SCTP_CID_I_FWD_TSN) case SCTP_CID_FWD_TSN:
return &prsctp_chunk_event_table[0][state]; case SCTP_CID_I_FWD_TSN:
} return &prsctp_chunk_event_table[0][state];
if (net->sctp.addip_enable) { case SCTP_CID_ASCONF:
if (cid == SCTP_CID_ASCONF) return &addip_chunk_event_table[0][state];
return &addip_chunk_event_table[0][state];
if (cid == SCTP_CID_ASCONF_ACK) case SCTP_CID_ASCONF_ACK:
return &addip_chunk_event_table[1][state]; return &addip_chunk_event_table[1][state];
}
if (net->sctp.reconf_enable) case SCTP_CID_RECONF:
if (cid == SCTP_CID_RECONF) return &reconf_chunk_event_table[0][state];
return &reconf_chunk_event_table[0][state];
if (net->sctp.auth_enable) { case SCTP_CID_AUTH:
if (cid == SCTP_CID_AUTH) return &auth_chunk_event_table[0][state];
return &auth_chunk_event_table[0][state];
} }
return &chunk_event_table_unknown[state]; return &chunk_event_table_unknown[state];
......
...@@ -524,7 +524,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk, ...@@ -524,7 +524,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
struct sockaddr *addrs, struct sockaddr *addrs,
int addrcnt) int addrcnt)
{ {
struct net *net = sock_net(sk);
struct sctp_sock *sp; struct sctp_sock *sp;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
struct sctp_association *asoc; struct sctp_association *asoc;
...@@ -539,12 +538,12 @@ static int sctp_send_asconf_add_ip(struct sock *sk, ...@@ -539,12 +538,12 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
int i; int i;
int retval = 0; int retval = 0;
if (!net->sctp.addip_enable)
return retval;
sp = sctp_sk(sk); sp = sctp_sk(sk);
ep = sp->ep; ep = sp->ep;
if (!ep->asconf_enable)
return retval;
pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
__func__, sk, addrs, addrcnt); __func__, sk, addrs, addrcnt);
...@@ -727,7 +726,6 @@ static int sctp_send_asconf_del_ip(struct sock *sk, ...@@ -727,7 +726,6 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
struct sockaddr *addrs, struct sockaddr *addrs,
int addrcnt) int addrcnt)
{ {
struct net *net = sock_net(sk);
struct sctp_sock *sp; struct sctp_sock *sp;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
struct sctp_association *asoc; struct sctp_association *asoc;
...@@ -743,12 +741,12 @@ static int sctp_send_asconf_del_ip(struct sock *sk, ...@@ -743,12 +741,12 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
int stored = 0; int stored = 0;
chunk = NULL; chunk = NULL;
if (!net->sctp.addip_enable)
return retval;
sp = sctp_sk(sk); sp = sctp_sk(sk);
ep = sp->ep; ep = sp->ep;
if (!ep->asconf_enable)
return retval;
pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
__func__, sk, addrs, addrcnt); __func__, sk, addrs, addrcnt);
...@@ -3330,7 +3328,6 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned ...@@ -3330,7 +3328,6 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval, static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval,
unsigned int optlen) unsigned int optlen)
{ {
struct net *net = sock_net(sk);
struct sctp_sock *sp; struct sctp_sock *sp;
struct sctp_association *asoc = NULL; struct sctp_association *asoc = NULL;
struct sctp_setpeerprim prim; struct sctp_setpeerprim prim;
...@@ -3340,7 +3337,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva ...@@ -3340,7 +3337,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
sp = sctp_sk(sk); sp = sctp_sk(sk);
if (!net->sctp.addip_enable) if (!sp->ep->asconf_enable)
return -EPERM; return -EPERM;
if (optlen != sizeof(struct sctp_setpeerprim)) if (optlen != sizeof(struct sctp_setpeerprim))
...@@ -3690,9 +3687,6 @@ static int sctp_setsockopt_auth_key(struct sock *sk, ...@@ -3690,9 +3687,6 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
struct sctp_association *asoc; struct sctp_association *asoc;
int ret = -EINVAL; int ret = -EINVAL;
if (!ep->auth_enable)
return -EACCES;
if (optlen <= sizeof(struct sctp_authkey)) if (optlen <= sizeof(struct sctp_authkey))
return -EINVAL; return -EINVAL;
/* authkey->sca_keylength is u16, so optlen can't be bigger than /* authkey->sca_keylength is u16, so optlen can't be bigger than
...@@ -3759,9 +3753,6 @@ static int sctp_setsockopt_active_key(struct sock *sk, ...@@ -3759,9 +3753,6 @@ static int sctp_setsockopt_active_key(struct sock *sk,
struct sctp_authkeyid val; struct sctp_authkeyid val;
int ret = 0; int ret = 0;
if (!ep->auth_enable)
return -EACCES;
if (optlen != sizeof(struct sctp_authkeyid)) if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL; return -EINVAL;
if (copy_from_user(&val, optval, optlen)) if (copy_from_user(&val, optval, optlen))
...@@ -3813,9 +3804,6 @@ static int sctp_setsockopt_del_key(struct sock *sk, ...@@ -3813,9 +3804,6 @@ static int sctp_setsockopt_del_key(struct sock *sk,
struct sctp_authkeyid val; struct sctp_authkeyid val;
int ret = 0; int ret = 0;
if (!ep->auth_enable)
return -EACCES;
if (optlen != sizeof(struct sctp_authkeyid)) if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL; return -EINVAL;
if (copy_from_user(&val, optval, optlen)) if (copy_from_user(&val, optval, optlen))
...@@ -3866,9 +3854,6 @@ static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval, ...@@ -3866,9 +3854,6 @@ static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval,
struct sctp_authkeyid val; struct sctp_authkeyid val;
int ret = 0; int ret = 0;
if (!ep->auth_enable)
return -EACCES;
if (optlen != sizeof(struct sctp_authkeyid)) if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL; return -EINVAL;
if (copy_from_user(&val, optval, optlen)) if (copy_from_user(&val, optval, optlen))
...@@ -4499,6 +4484,82 @@ static int sctp_setsockopt_event(struct sock *sk, char __user *optval, ...@@ -4499,6 +4484,82 @@ static int sctp_setsockopt_event(struct sock *sk, char __user *optval,
return retval; return retval;
} }
static int sctp_setsockopt_asconf_supported(struct sock *sk,
char __user *optval,
unsigned int optlen)
{
struct sctp_assoc_value params;
struct sctp_association *asoc;
struct sctp_endpoint *ep;
int retval = -EINVAL;
if (optlen != sizeof(params))
goto out;
if (copy_from_user(&params, optval, optlen)) {
retval = -EFAULT;
goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
goto out;
ep = sctp_sk(sk)->ep;
ep->asconf_enable = !!params.assoc_value;
if (ep->asconf_enable && ep->auth_enable) {
sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
}
retval = 0;
out:
return retval;
}
static int sctp_setsockopt_auth_supported(struct sock *sk,
char __user *optval,
unsigned int optlen)
{
struct sctp_assoc_value params;
struct sctp_association *asoc;
struct sctp_endpoint *ep;
int retval = -EINVAL;
if (optlen != sizeof(params))
goto out;
if (copy_from_user(&params, optval, optlen)) {
retval = -EFAULT;
goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
goto out;
ep = sctp_sk(sk)->ep;
if (params.assoc_value) {
retval = sctp_auth_init(ep, GFP_KERNEL);
if (retval)
goto out;
if (ep->asconf_enable) {
sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
}
}
ep->auth_enable = !!params.assoc_value;
retval = 0;
out:
return retval;
}
/* API 6.2 setsockopt(), getsockopt() /* API 6.2 setsockopt(), getsockopt()
* *
* Applications use setsockopt() and getsockopt() to set or retrieve * Applications use setsockopt() and getsockopt() to set or retrieve
...@@ -4699,6 +4760,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -4699,6 +4760,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_EVENT: case SCTP_EVENT:
retval = sctp_setsockopt_event(sk, optval, optlen); retval = sctp_setsockopt_event(sk, optval, optlen);
break; break;
case SCTP_ASCONF_SUPPORTED:
retval = sctp_setsockopt_asconf_supported(sk, optval, optlen);
break;
case SCTP_AUTH_SUPPORTED:
retval = sctp_setsockopt_auth_supported(sk, optval, optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -6836,9 +6903,6 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len, ...@@ -6836,9 +6903,6 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
struct sctp_authkeyid val; struct sctp_authkeyid val;
struct sctp_association *asoc; struct sctp_association *asoc;
if (!ep->auth_enable)
return -EACCES;
if (len < sizeof(struct sctp_authkeyid)) if (len < sizeof(struct sctp_authkeyid))
return -EINVAL; return -EINVAL;
...@@ -6850,10 +6914,15 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len, ...@@ -6850,10 +6914,15 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) if (asoc) {
if (!asoc->peer.auth_capable)
return -EACCES;
val.scact_keynumber = asoc->active_key_id; val.scact_keynumber = asoc->active_key_id;
else } else {
if (!ep->auth_enable)
return -EACCES;
val.scact_keynumber = ep->active_key_id; val.scact_keynumber = ep->active_key_id;
}
if (put_user(len, optlen)) if (put_user(len, optlen))
return -EFAULT; return -EFAULT;
...@@ -6866,7 +6935,6 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len, ...@@ -6866,7 +6935,6 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_authchunks __user *p = (void __user *)optval; struct sctp_authchunks __user *p = (void __user *)optval;
struct sctp_authchunks val; struct sctp_authchunks val;
struct sctp_association *asoc; struct sctp_association *asoc;
...@@ -6874,9 +6942,6 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, ...@@ -6874,9 +6942,6 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
u32 num_chunks = 0; u32 num_chunks = 0;
char __user *to; char __user *to;
if (!ep->auth_enable)
return -EACCES;
if (len < sizeof(struct sctp_authchunks)) if (len < sizeof(struct sctp_authchunks))
return -EINVAL; return -EINVAL;
...@@ -6888,6 +6953,9 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, ...@@ -6888,6 +6953,9 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
if (!asoc) if (!asoc)
return -EINVAL; return -EINVAL;
if (!asoc->peer.auth_capable)
return -EACCES;
ch = asoc->peer.peer_chunks; ch = asoc->peer.peer_chunks;
if (!ch) if (!ch)
goto num; goto num;
...@@ -6919,9 +6987,6 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, ...@@ -6919,9 +6987,6 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
u32 num_chunks = 0; u32 num_chunks = 0;
char __user *to; char __user *to;
if (!ep->auth_enable)
return -EACCES;
if (len < sizeof(struct sctp_authchunks)) if (len < sizeof(struct sctp_authchunks))
return -EINVAL; return -EINVAL;
...@@ -6934,8 +6999,15 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, ...@@ -6934,8 +6999,15 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
ch = asoc ? (struct sctp_chunks_param *)asoc->c.auth_chunks if (asoc) {
: ep->auth_chunk_list; if (!asoc->peer.auth_capable)
return -EACCES;
ch = (struct sctp_chunks_param *)asoc->c.auth_chunks;
} else {
if (!ep->auth_enable)
return -EACCES;
ch = ep->auth_chunk_list;
}
if (!ch) if (!ch)
goto num; goto num;
...@@ -7678,6 +7750,84 @@ static int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval, ...@@ -7678,6 +7750,84 @@ static int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval,
return 0; return 0;
} }
static int sctp_getsockopt_asconf_supported(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
{
struct sctp_assoc_value params;
struct sctp_association *asoc;
int retval = -EFAULT;
if (len < sizeof(params)) {
retval = -EINVAL;
goto out;
}
len = sizeof(params);
if (copy_from_user(&params, optval, len))
goto out;
asoc = sctp_id2assoc(sk, params.assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) {
retval = -EINVAL;
goto out;
}
params.assoc_value = asoc ? asoc->peer.asconf_capable
: sctp_sk(sk)->ep->asconf_enable;
if (put_user(len, optlen))
goto out;
if (copy_to_user(optval, &params, len))
goto out;
retval = 0;
out:
return retval;
}
static int sctp_getsockopt_auth_supported(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
{
struct sctp_assoc_value params;
struct sctp_association *asoc;
int retval = -EFAULT;
if (len < sizeof(params)) {
retval = -EINVAL;
goto out;
}
len = sizeof(params);
if (copy_from_user(&params, optval, len))
goto out;
asoc = sctp_id2assoc(sk, params.assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) {
retval = -EINVAL;
goto out;
}
params.assoc_value = asoc ? asoc->peer.auth_capable
: sctp_sk(sk)->ep->auth_enable;
if (put_user(len, optlen))
goto out;
if (copy_to_user(optval, &params, len))
goto out;
retval = 0;
out:
return retval;
}
static int sctp_getsockopt(struct sock *sk, int level, int optname, static int sctp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
...@@ -7879,6 +8029,14 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -7879,6 +8029,14 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_EVENT: case SCTP_EVENT:
retval = sctp_getsockopt_event(sk, len, optval, optlen); retval = sctp_getsockopt_event(sk, len, optval, optlen);
break; break;
case SCTP_ASCONF_SUPPORTED:
retval = sctp_getsockopt_asconf_supported(sk, len, optval,
optlen);
break;
case SCTP_AUTH_SUPPORTED:
retval = sctp_getsockopt_auth_supported(sk, len, optval,
optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment