summaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r--net/sctp/socket.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7738915011a0..f3e1a9c811ad 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2946,6 +2946,164 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
return 0;
}
+/*
+ * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK)
+ *
+ * This set option adds a chunk type that the user is requesting to be
+ * received only in an authenticated way. Changes to the list of chunks
+ * will only effect future associations on the socket.
+ */
+static int sctp_setsockopt_auth_chunk(struct sock *sk,
+ char __user *optval,
+ int optlen)
+{
+ struct sctp_authchunk val;
+
+ if (optlen != sizeof(struct sctp_authchunk))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, optlen))
+ return -EFAULT;
+
+ switch (val.sauth_chunk) {
+ case SCTP_CID_INIT:
+ case SCTP_CID_INIT_ACK:
+ case SCTP_CID_SHUTDOWN_COMPLETE:
+ case SCTP_CID_AUTH:
+ return -EINVAL;
+ }
+
+ /* add this chunk id to the endpoint */
+ return sctp_auth_ep_add_chunkid(sctp_sk(sk)->ep, val.sauth_chunk);
+}
+
+/*
+ * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT)
+ *
+ * This option gets or sets the list of HMAC algorithms that the local
+ * endpoint requires the peer to use.
+ */
+static int sctp_setsockopt_hmac_ident(struct sock *sk,
+ char __user *optval,
+ int optlen)
+{
+ struct sctp_hmacalgo *hmacs;
+ int err;
+
+ if (optlen < sizeof(struct sctp_hmacalgo))
+ return -EINVAL;
+
+ hmacs = kmalloc(optlen, GFP_KERNEL);
+ if (!hmacs)
+ return -ENOMEM;
+
+ if (copy_from_user(hmacs, optval, optlen)) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ if (hmacs->shmac_num_idents == 0 ||
+ hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = sctp_auth_ep_set_hmacs(sctp_sk(sk)->ep, hmacs);
+out:
+ kfree(hmacs);
+ return err;
+}
+
+/*
+ * 7.1.20. Set a shared key (SCTP_AUTH_KEY)
+ *
+ * This option will set a shared secret key which is used to build an
+ * association shared key.
+ */
+static int sctp_setsockopt_auth_key(struct sock *sk,
+ char __user *optval,
+ int optlen)
+{
+ struct sctp_authkey *authkey;
+ struct sctp_association *asoc;
+ int ret;
+
+ if (optlen <= sizeof(struct sctp_authkey))
+ return -EINVAL;
+
+ authkey = kmalloc(optlen, GFP_KERNEL);
+ if (!authkey)
+ return -ENOMEM;
+
+ if (copy_from_user(authkey, optval, optlen)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ asoc = sctp_id2assoc(sk, authkey->sca_assoc_id);
+ if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey);
+out:
+ kfree(authkey);
+ return ret;
+}
+
+/*
+ * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY)
+ *
+ * This option will get or set the active shared key to be used to build
+ * the association shared key.
+ */
+static int sctp_setsockopt_active_key(struct sock *sk,
+ char __user *optval,
+ int optlen)
+{
+ struct sctp_authkeyid val;
+ struct sctp_association *asoc;
+
+ if (optlen != sizeof(struct sctp_authkeyid))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, optlen))
+ return -EFAULT;
+
+ asoc = sctp_id2assoc(sk, val.scact_assoc_id);
+ if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
+ return -EINVAL;
+
+ return sctp_auth_set_active_key(sctp_sk(sk)->ep, asoc,
+ val.scact_keynumber);
+}
+
+/*
+ * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY)
+ *
+ * This set option will delete a shared secret key from use.
+ */
+static int sctp_setsockopt_del_key(struct sock *sk,
+ char __user *optval,
+ int optlen)
+{
+ struct sctp_authkeyid val;
+ struct sctp_association *asoc;
+
+ if (optlen != sizeof(struct sctp_authkeyid))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, optlen))
+ return -EFAULT;
+
+ asoc = sctp_id2assoc(sk, val.scact_assoc_id);
+ if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
+ return -EINVAL;
+
+ return sctp_auth_del_key_id(sctp_sk(sk)->ep, asoc,
+ val.scact_keynumber);
+
+}
+
+
/* API 6.2 setsockopt(), getsockopt()
*
* Applications use setsockopt() and getsockopt() to set or retrieve
@@ -3069,6 +3227,21 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_MAX_BURST:
retval = sctp_setsockopt_maxburst(sk, optval, optlen);
break;
+ case SCTP_AUTH_CHUNK:
+ retval = sctp_setsockopt_auth_chunk(sk, optval, optlen);
+ break;
+ case SCTP_HMAC_IDENT:
+ retval = sctp_setsockopt_hmac_ident(sk, optval, optlen);
+ break;
+ case SCTP_AUTH_KEY:
+ retval = sctp_setsockopt_auth_key(sk, optval, optlen);
+ break;
+ case SCTP_AUTH_ACTIVE_KEY:
+ retval = sctp_setsockopt_active_key(sk, optval, optlen);
+ break;
+ case SCTP_AUTH_DELETE_KEY:
+ retval = sctp_setsockopt_del_key(sk, optval, optlen);
+ break;
default:
retval = -ENOPROTOOPT;
break;
@@ -4840,6 +5013,118 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
return -ENOTSUPP;
}
+static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+{
+ struct sctp_hmac_algo_param *hmacs;
+ __u16 param_len;
+
+ hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
+ param_len = ntohs(hmacs->param_hdr.length);
+
+ if (len < param_len)
+ return -EINVAL;
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, hmacs->hmac_ids, len))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int sctp_getsockopt_active_key(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+{
+ struct sctp_authkeyid val;
+ struct sctp_association *asoc;
+
+ if (len < sizeof(struct sctp_authkeyid))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid)))
+ return -EFAULT;
+
+ asoc = sctp_id2assoc(sk, val.scact_assoc_id);
+ if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
+ return -EINVAL;
+
+ if (asoc)
+ val.scact_keynumber = asoc->active_key_id;
+ else
+ val.scact_keynumber = sctp_sk(sk)->ep->active_key_id;
+
+ return 0;
+}
+
+static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+{
+ struct sctp_authchunks val;
+ struct sctp_association *asoc;
+ struct sctp_chunks_param *ch;
+ char __user *to;
+
+ if (len <= sizeof(struct sctp_authchunks))
+ return -EINVAL;
+
+ if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
+ return -EFAULT;
+
+ to = val.gauth_chunks;
+ asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
+ if (!asoc)
+ return -EINVAL;
+
+ ch = asoc->peer.peer_chunks;
+
+ /* See if the user provided enough room for all the data */
+ if (len < ntohs(ch->param_hdr.length))
+ return -EINVAL;
+
+ len = ntohs(ch->param_hdr.length);
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(to, ch->chunks, len))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+{
+ struct sctp_authchunks val;
+ struct sctp_association *asoc;
+ struct sctp_chunks_param *ch;
+ char __user *to;
+
+ if (len <= sizeof(struct sctp_authchunks))
+ return -EINVAL;
+
+ if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
+ return -EFAULT;
+
+ to = val.gauth_chunks;
+ asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
+ if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP))
+ return -EINVAL;
+
+ if (asoc)
+ ch = (struct sctp_chunks_param*)asoc->c.auth_chunks;
+ else
+ ch = sctp_sk(sk)->ep->auth_chunk_list;
+
+ if (len < ntohs(ch->param_hdr.length))
+ return -EINVAL;
+
+ len = ntohs(ch->param_hdr.length);
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(to, ch->chunks, len))
+ return -EFAULT;
+
+ return 0;
+}
+
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
@@ -4963,6 +5248,25 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_MAX_BURST:
retval = sctp_getsockopt_maxburst(sk, len, optval, optlen);
break;
+ case SCTP_AUTH_KEY:
+ case SCTP_AUTH_CHUNK:
+ case SCTP_AUTH_DELETE_KEY:
+ retval = -EOPNOTSUPP;
+ break;
+ case SCTP_HMAC_IDENT:
+ retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen);
+ break;
+ case SCTP_AUTH_ACTIVE_KEY:
+ retval = sctp_getsockopt_active_key(sk, len, optval, optlen);
+ break;
+ case SCTP_PEER_AUTH_CHUNKS:
+ retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval,
+ optlen);
+ break;
+ case SCTP_LOCAL_AUTH_CHUNKS:
+ retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
+ optlen);
+ break;
default:
retval = -ENOPROTOOPT;
break;