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: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-08-19 18:27:29 -07:00
commit 5483ecefe9
10 changed files with 325 additions and 136 deletions

View File

@ -107,5 +107,7 @@ int sctp_auth_del_key_id(struct sctp_endpoint *ep,
struct sctp_association *asoc, __u16 key_id);
int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
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

View File

@ -1325,6 +1325,7 @@ struct sctp_endpoint {
__u8 auth_enable:1,
intl_enable:1,
prsctp_enable:1,
asconf_enable:1,
reconf_enable:1;
__u8 strreset_enable;

View File

@ -134,6 +134,8 @@ typedef __s32 sctp_assoc_t;
#define SCTP_INTERLEAVING_SUPPORTED 125
#define SCTP_SENDMSG_CONNECT 126
#define SCTP_EVENT 127
#define SCTP_ASCONF_SUPPORTED 128
#define SCTP_AUTH_SUPPORTED 129
/* PR-SCTP policies */
#define SCTP_PR_SCTP_NONE 0x0000

View File

@ -54,7 +54,6 @@ static struct sctp_association *sctp_association_init(
const struct sock *sk,
enum sctp_scope scope, gfp_t gfp)
{
struct net *net = sock_net(sk);
struct sctp_sock *sp;
struct sctp_paramhdr *p;
int i;
@ -214,14 +213,6 @@ static struct sctp_association *sctp_association_init(
asoc->peer.sack_needed = 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. */
sctp_inq_init(&asoc->base.inqueue);
sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv);

View File

@ -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
* we don't need to do anything.
*/
if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
if (!asoc->peer.auth_capable)
return 0;
/* 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)
if (!asoc)
return 0;
if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
if (!asoc->peer.auth_capable)
return 0;
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)
if (!asoc)
return 0;
if (!asoc->ep->auth_enable)
if (!asoc->peer.auth_capable)
return 0;
return __sctp_auth_cid(chunk,
@ -831,10 +831,15 @@ int sctp_auth_set_key(struct sctp_endpoint *ep,
/* Try to find the given key id to see if
* 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;
else
} else {
if (!ep->auth_enable)
return -EACCES;
sh_keys = &ep->endpoint_shared_keys;
}
key_for_each(shkey, sh_keys) {
if (shkey->key_id == auth_key->sca_keynumber) {
@ -875,10 +880,15 @@ int sctp_auth_set_active_key(struct sctp_endpoint *ep,
int found = 0;
/* 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;
else
} else {
if (!ep->auth_enable)
return -EACCES;
sh_keys = &ep->endpoint_shared_keys;
}
key_for_each(key, sh_keys) {
if (key->key_id == key_id) {
@ -911,11 +921,15 @@ int sctp_auth_del_key_id(struct sctp_endpoint *ep,
* The key identifier MUST correst to an existing key
*/
if (asoc) {
if (!asoc->peer.auth_capable)
return -EACCES;
if (asoc->active_key_id == key_id)
return -EINVAL;
sh_keys = &asoc->endpoint_shared_keys;
} else {
if (!ep->auth_enable)
return -EACCES;
if (ep->active_key_id == key_id)
return -EINVAL;
@ -950,11 +964,15 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
* The key identifier MUST correst to an existing key
*/
if (asoc) {
if (!asoc->peer.auth_capable)
return -EACCES;
if (asoc->active_key_id == key_id)
return -EINVAL;
sh_keys = &asoc->endpoint_shared_keys;
} else {
if (!ep->auth_enable)
return -EACCES;
if (ep->active_key_id == key_id)
return -EINVAL;
@ -989,3 +1007,72 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
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;
}

View File

@ -43,62 +43,21 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
gfp_t gfp)
{
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;
int err;
ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp);
if (!ep->digest)
return NULL;
ep->asconf_enable = net->sctp.addip_enable;
ep->auth_enable = net->sctp.auth_enable;
if (ep->auth_enable) {
/* 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.
*/
auth_hmacs = kzalloc(struct_size(auth_hmacs, hmac_ids,
SCTP_AUTH_NUM_HMACS), gfp);
if (!auth_hmacs)
if (sctp_auth_init(ep, gfp))
goto nomem;
auth_chunks = kzalloc(sizeof(*auth_chunks) +
SCTP_NUM_CHUNK_TYPES, gfp);
if (!auth_chunks)
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);
/* 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);
if (ep->asconf_enable) {
sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
}
/* Allocate and initialize transorms arrays for supported
* HMACs.
*/
err = sctp_auth_init_hmacs(ep, gfp);
if (err)
goto nomem;
}
/* Initialize the base structure. */
@ -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
* 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->reconf_enable = net->sctp.reconf_enable;
@ -157,11 +114,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
return ep;
nomem_shkey:
sctp_auth_destroy_hmacs(ep->auth_hmacs);
sctp_auth_free(ep);
nomem:
/* Free all allocations */
kfree(auth_hmacs);
kfree(auth_chunks);
kfree(ep->digest);
return NULL;
@ -244,11 +198,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
* chunks and hmacs arrays that were allocated
*/
sctp_auth_destroy_keys(&ep->endpoint_shared_keys);
kfree(ep->auth_hmacs_list);
kfree(ep->auth_chunk_list);
/* AUTH - Free any allocated HMAC transform containers */
sctp_auth_destroy_hmacs(ep->auth_hmacs);
sctp_auth_free(ep);
/* Cleanup. */
sctp_inq_free(&ep->base.inqueue);

View File

@ -207,7 +207,6 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
const struct sctp_bind_addr *bp,
gfp_t gfp, int vparam_len)
{
struct net *net = sock_net(asoc->base.sk);
struct sctp_supported_ext_param ext_param;
struct sctp_adaptation_ind_param aiparam;
struct sctp_paramhdr *auth_chunks = NULL;
@ -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
* INIT-ACK parameters.
*/
if (net->sctp.addip_enable) {
if (asoc->ep->asconf_enable) {
extensions[num_ext] = SCTP_CID_ASCONF;
extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
num_ext += 2;
@ -1964,7 +1963,9 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
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);
int have_asconf = 0;
@ -1991,7 +1992,7 @@ static int sctp_verify_ext_param(struct net *net, union sctp_params param)
if (net->sctp.addip_noauth)
return 1;
if (net->sctp.addip_enable && !have_auth && have_asconf)
if (ep->asconf_enable && !have_auth && have_asconf)
return 0;
return 1;
@ -2001,7 +2002,6 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
union sctp_params param)
{
__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
struct net *net = sock_net(asoc->base.sk);
int i;
for (i = 0; i < num_ext; i++) {
@ -2023,7 +2023,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
break;
case SCTP_CID_ASCONF:
case SCTP_CID_ASCONF_ACK:
if (net->sctp.addip_enable)
if (asoc->ep->asconf_enable)
asoc->peer.asconf_capable = 1;
break;
case SCTP_CID_I_DATA:
@ -2145,12 +2145,12 @@ static enum sctp_ierror sctp_verify_param(struct net *net,
break;
case SCTP_PARAM_SUPPORTED_EXT:
if (!sctp_verify_ext_param(net, param))
if (!sctp_verify_ext_param(net, ep, param))
return SCTP_IERROR_ABORT;
break;
case SCTP_PARAM_SET_PRIMARY:
if (net->sctp.addip_enable)
if (ep->asconf_enable)
break;
goto fallthrough;
@ -2605,7 +2605,7 @@ do_addr_param:
break;
case SCTP_PARAM_SET_PRIMARY:
if (!net->sctp.addip_enable)
if (!ep->asconf_enable)
goto fall_through;
addr_param = param.v + sizeof(struct sctp_addip_param);

View File

@ -3721,7 +3721,8 @@ enum sctp_disposition sctp_sf_do_asconf(struct net *net,
* is received unauthenticated it MUST be silently discarded as
* 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,
commands);
@ -3863,7 +3864,8 @@ enum sctp_disposition sctp_sf_do_asconf_ack(struct net *net,
* is received unauthenticated it MUST be silently discarded as
* 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,
commands);

View File

@ -976,26 +976,22 @@ static const struct sctp_sm_table_entry *sctp_chunk_event_lookup(
if (cid <= SCTP_CID_BASE_MAX)
return &chunk_event_table[cid][state];
if (net->sctp.prsctp_enable) {
if (cid == SCTP_CID_FWD_TSN || cid == SCTP_CID_I_FWD_TSN)
return &prsctp_chunk_event_table[0][state];
}
switch ((u16)cid) {
case SCTP_CID_FWD_TSN:
case SCTP_CID_I_FWD_TSN:
return &prsctp_chunk_event_table[0][state];
if (net->sctp.addip_enable) {
if (cid == SCTP_CID_ASCONF)
return &addip_chunk_event_table[0][state];
case SCTP_CID_ASCONF:
return &addip_chunk_event_table[0][state];
if (cid == SCTP_CID_ASCONF_ACK)
return &addip_chunk_event_table[1][state];
}
case SCTP_CID_ASCONF_ACK:
return &addip_chunk_event_table[1][state];
if (net->sctp.reconf_enable)
if (cid == SCTP_CID_RECONF)
return &reconf_chunk_event_table[0][state];
case SCTP_CID_RECONF:
return &reconf_chunk_event_table[0][state];
if (net->sctp.auth_enable) {
if (cid == SCTP_CID_AUTH)
return &auth_chunk_event_table[0][state];
case SCTP_CID_AUTH:
return &auth_chunk_event_table[0][state];
}
return &chunk_event_table_unknown[state];

View File

@ -524,7 +524,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
struct sockaddr *addrs,
int addrcnt)
{
struct net *net = sock_net(sk);
struct sctp_sock *sp;
struct sctp_endpoint *ep;
struct sctp_association *asoc;
@ -539,12 +538,12 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
int i;
int retval = 0;
if (!net->sctp.addip_enable)
return retval;
sp = sctp_sk(sk);
ep = sp->ep;
if (!ep->asconf_enable)
return retval;
pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
__func__, sk, addrs, addrcnt);
@ -727,7 +726,6 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
struct sockaddr *addrs,
int addrcnt)
{
struct net *net = sock_net(sk);
struct sctp_sock *sp;
struct sctp_endpoint *ep;
struct sctp_association *asoc;
@ -743,12 +741,12 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
int stored = 0;
chunk = NULL;
if (!net->sctp.addip_enable)
return retval;
sp = sctp_sk(sk);
ep = sp->ep;
if (!ep->asconf_enable)
return retval;
pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
__func__, sk, addrs, addrcnt);
@ -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,
unsigned int optlen)
{
struct net *net = sock_net(sk);
struct sctp_sock *sp;
struct sctp_association *asoc = NULL;
struct sctp_setpeerprim prim;
@ -3340,7 +3337,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
sp = sctp_sk(sk);
if (!net->sctp.addip_enable)
if (!sp->ep->asconf_enable)
return -EPERM;
if (optlen != sizeof(struct sctp_setpeerprim))
@ -3690,9 +3687,6 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
struct sctp_association *asoc;
int ret = -EINVAL;
if (!ep->auth_enable)
return -EACCES;
if (optlen <= sizeof(struct sctp_authkey))
return -EINVAL;
/* 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,
struct sctp_authkeyid val;
int ret = 0;
if (!ep->auth_enable)
return -EACCES;
if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL;
if (copy_from_user(&val, optval, optlen))
@ -3813,9 +3804,6 @@ static int sctp_setsockopt_del_key(struct sock *sk,
struct sctp_authkeyid val;
int ret = 0;
if (!ep->auth_enable)
return -EACCES;
if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL;
if (copy_from_user(&val, optval, optlen))
@ -3866,9 +3854,6 @@ static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval,
struct sctp_authkeyid val;
int ret = 0;
if (!ep->auth_enable)
return -EACCES;
if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL;
if (copy_from_user(&val, optval, optlen))
@ -4499,6 +4484,82 @@ static int sctp_setsockopt_event(struct sock *sk, char __user *optval,
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()
*
* Applications use setsockopt() and getsockopt() to set or retrieve
@ -4699,6 +4760,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_EVENT:
retval = sctp_setsockopt_event(sk, optval, optlen);
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:
retval = -ENOPROTOOPT;
break;
@ -6836,9 +6903,6 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
struct sctp_authkeyid val;
struct sctp_association *asoc;
if (!ep->auth_enable)
return -EACCES;
if (len < sizeof(struct sctp_authkeyid))
return -EINVAL;
@ -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))
return -EINVAL;
if (asoc)
if (asoc) {
if (!asoc->peer.auth_capable)
return -EACCES;
val.scact_keynumber = asoc->active_key_id;
else
} else {
if (!ep->auth_enable)
return -EACCES;
val.scact_keynumber = ep->active_key_id;
}
if (put_user(len, optlen))
return -EFAULT;
@ -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,
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 val;
struct sctp_association *asoc;
@ -6874,9 +6942,6 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
u32 num_chunks = 0;
char __user *to;
if (!ep->auth_enable)
return -EACCES;
if (len < sizeof(struct sctp_authchunks))
return -EINVAL;
@ -6888,6 +6953,9 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
if (!asoc)
return -EINVAL;
if (!asoc->peer.auth_capable)
return -EACCES;
ch = asoc->peer.peer_chunks;
if (!ch)
goto num;
@ -6919,9 +6987,6 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
u32 num_chunks = 0;
char __user *to;
if (!ep->auth_enable)
return -EACCES;
if (len < sizeof(struct sctp_authchunks))
return -EINVAL;
@ -6934,8 +6999,15 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
sctp_style(sk, UDP))
return -EINVAL;
ch = asoc ? (struct sctp_chunks_param *)asoc->c.auth_chunks
: ep->auth_chunk_list;
if (asoc) {
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)
goto num;
@ -7678,6 +7750,84 @@ static int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval,
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,
char __user *optval, int __user *optlen)
{
@ -7879,6 +8029,14 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_EVENT:
retval = sctp_getsockopt_event(sk, len, optval, optlen);
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:
retval = -ENOPROTOOPT;
break;