mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
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:
commit
5483ecefe9
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
101
net/sctp/auth.c
101
net/sctp/auth.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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(¶ms, 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(¶ms, 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(¶ms, 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, ¶ms, 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(¶ms, 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, ¶ms, 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;
|
||||
|
Loading…
Reference in New Issue
Block a user