aboutsummaryrefslogtreecommitdiffstats
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,
2946 return 0; 2946 return 0;
2947} 2947}
2948 2948
2949/*
2950 * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK)
2951 *
2952 * This set option adds a chunk type that the user is requesting to be
2953 * received only in an authenticated way. Changes to the list of chunks
2954 * will only effect future associations on the socket.
2955 */
2956static int sctp_setsockopt_auth_chunk(struct sock *sk,
2957 char __user *optval,
2958 int optlen)
2959{
2960 struct sctp_authchunk val;
2961
2962 if (optlen != sizeof(struct sctp_authchunk))
2963 return -EINVAL;
2964 if (copy_from_user(&val, optval, optlen))
2965 return -EFAULT;
2966
2967 switch (val.sauth_chunk) {
2968 case SCTP_CID_INIT:
2969 case SCTP_CID_INIT_ACK:
2970 case SCTP_CID_SHUTDOWN_COMPLETE:
2971 case SCTP_CID_AUTH:
2972 return -EINVAL;
2973 }
2974
2975 /* add this chunk id to the endpoint */
2976 return sctp_auth_ep_add_chunkid(sctp_sk(sk)->ep, val.sauth_chunk);
2977}
2978
2979/*
2980 * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT)
2981 *
2982 * This option gets or sets the list of HMAC algorithms that the local
2983 * endpoint requires the peer to use.
2984 */
2985static int sctp_setsockopt_hmac_ident(struct sock *sk,
2986 char __user *optval,
2987 int optlen)
2988{
2989 struct sctp_hmacalgo *hmacs;
2990 int err;
2991
2992 if (optlen < sizeof(struct sctp_hmacalgo))
2993 return -EINVAL;
2994
2995 hmacs = kmalloc(optlen, GFP_KERNEL);
2996 if (!hmacs)
2997 return -ENOMEM;
2998
2999 if (copy_from_user(hmacs, optval, optlen)) {
3000 err = -EFAULT;
3001 goto out;
3002 }
3003
3004 if (hmacs->shmac_num_idents == 0 ||
3005 hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) {
3006 err = -EINVAL;
3007 goto out;
3008 }
3009
3010 err = sctp_auth_ep_set_hmacs(sctp_sk(sk)->ep, hmacs);
3011out:
3012 kfree(hmacs);
3013 return err;
3014}
3015
3016/*
3017 * 7.1.20. Set a shared key (SCTP_AUTH_KEY)
3018 *
3019 * This option will set a shared secret key which is used to build an
3020 * association shared key.
3021 */
3022static int sctp_setsockopt_auth_key(struct sock *sk,
3023 char __user *optval,
3024 int optlen)
3025{
3026 struct sctp_authkey *authkey;
3027 struct sctp_association *asoc;
3028 int ret;
3029
3030 if (optlen <= sizeof(struct sctp_authkey))
3031 return -EINVAL;
3032
3033 authkey = kmalloc(optlen, GFP_KERNEL);
3034 if (!authkey)
3035 return -ENOMEM;
3036
3037 if (copy_from_user(authkey, optval, optlen)) {
3038 ret = -EFAULT;
3039 goto out;
3040 }
3041
3042 asoc = sctp_id2assoc(sk, authkey->sca_assoc_id);
3043 if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) {
3044 ret = -EINVAL;
3045 goto out;
3046 }
3047
3048 ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey);
3049out:
3050 kfree(authkey);
3051 return ret;
3052}
3053
3054/*
3055 * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY)
3056 *
3057 * This option will get or set the active shared key to be used to build
3058 * the association shared key.
3059 */
3060static int sctp_setsockopt_active_key(struct sock *sk,
3061 char __user *optval,
3062 int optlen)
3063{
3064 struct sctp_authkeyid val;
3065 struct sctp_association *asoc;
3066
3067 if (optlen != sizeof(struct sctp_authkeyid))
3068 return -EINVAL;
3069 if (copy_from_user(&val, optval, optlen))
3070 return -EFAULT;
3071
3072 asoc = sctp_id2assoc(sk, val.scact_assoc_id);
3073 if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
3074 return -EINVAL;
3075
3076 return sctp_auth_set_active_key(sctp_sk(sk)->ep, asoc,
3077 val.scact_keynumber);
3078}
3079
3080/*
3081 * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY)
3082 *
3083 * This set option will delete a shared secret key from use.
3084 */
3085static int sctp_setsockopt_del_key(struct sock *sk,
3086 char __user *optval,
3087 int optlen)
3088{
3089 struct sctp_authkeyid val;
3090 struct sctp_association *asoc;
3091
3092 if (optlen != sizeof(struct sctp_authkeyid))
3093 return -EINVAL;
3094 if (copy_from_user(&val, optval, optlen))
3095 return -EFAULT;
3096
3097 asoc = sctp_id2assoc(sk, val.scact_assoc_id);
3098 if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
3099 return -EINVAL;
3100
3101 return sctp_auth_del_key_id(sctp_sk(sk)->ep, asoc,
3102 val.scact_keynumber);
3103
3104}
3105
3106
2949/* API 6.2 setsockopt(), getsockopt() 3107/* API 6.2 setsockopt(), getsockopt()
2950 * 3108 *
2951 * Applications use setsockopt() and getsockopt() to set or retrieve 3109 * 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,
3069 case SCTP_MAX_BURST: 3227 case SCTP_MAX_BURST:
3070 retval = sctp_setsockopt_maxburst(sk, optval, optlen); 3228 retval = sctp_setsockopt_maxburst(sk, optval, optlen);
3071 break; 3229 break;
3230 case SCTP_AUTH_CHUNK:
3231 retval = sctp_setsockopt_auth_chunk(sk, optval, optlen);
3232 break;
3233 case SCTP_HMAC_IDENT:
3234 retval = sctp_setsockopt_hmac_ident(sk, optval, optlen);
3235 break;
3236 case SCTP_AUTH_KEY:
3237 retval = sctp_setsockopt_auth_key(sk, optval, optlen);
3238 break;
3239 case SCTP_AUTH_ACTIVE_KEY:
3240 retval = sctp_setsockopt_active_key(sk, optval, optlen);
3241 break;
3242 case SCTP_AUTH_DELETE_KEY:
3243 retval = sctp_setsockopt_del_key(sk, optval, optlen);
3244 break;
3072 default: 3245 default:
3073 retval = -ENOPROTOOPT; 3246 retval = -ENOPROTOOPT;
3074 break; 3247 break;
@@ -4840,6 +5013,118 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
4840 return -ENOTSUPP; 5013 return -ENOTSUPP;
4841} 5014}
4842 5015
5016static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
5017 char __user *optval, int __user *optlen)
5018{
5019 struct sctp_hmac_algo_param *hmacs;
5020 __u16 param_len;
5021
5022 hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
5023 param_len = ntohs(hmacs->param_hdr.length);
5024
5025 if (len < param_len)
5026 return -EINVAL;
5027 if (put_user(len, optlen))
5028 return -EFAULT;
5029 if (copy_to_user(optval, hmacs->hmac_ids, len))
5030 return -EFAULT;
5031
5032 return 0;
5033}
5034
5035static int sctp_getsockopt_active_key(struct sock *sk, int len,
5036 char __user *optval, int __user *optlen)
5037{
5038 struct sctp_authkeyid val;
5039 struct sctp_association *asoc;
5040
5041 if (len < sizeof(struct sctp_authkeyid))
5042 return -EINVAL;
5043 if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid)))
5044 return -EFAULT;
5045
5046 asoc = sctp_id2assoc(sk, val.scact_assoc_id);
5047 if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
5048 return -EINVAL;
5049
5050 if (asoc)
5051 val.scact_keynumber = asoc->active_key_id;
5052 else
5053 val.scact_keynumber = sctp_sk(sk)->ep->active_key_id;
5054
5055 return 0;
5056}
5057
5058static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
5059 char __user *optval, int __user *optlen)
5060{
5061 struct sctp_authchunks val;
5062 struct sctp_association *asoc;
5063 struct sctp_chunks_param *ch;
5064 char __user *to;
5065
5066 if (len <= sizeof(struct sctp_authchunks))
5067 return -EINVAL;
5068
5069 if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
5070 return -EFAULT;
5071
5072 to = val.gauth_chunks;
5073 asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
5074 if (!asoc)
5075 return -EINVAL;
5076
5077 ch = asoc->peer.peer_chunks;
5078
5079 /* See if the user provided enough room for all the data */
5080 if (len < ntohs(ch->param_hdr.length))
5081 return -EINVAL;
5082
5083 len = ntohs(ch->param_hdr.length);
5084 if (put_user(len, optlen))
5085 return -EFAULT;
5086 if (copy_to_user(to, ch->chunks, len))
5087 return -EFAULT;
5088
5089 return 0;
5090}
5091
5092static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
5093 char __user *optval, int __user *optlen)
5094{
5095 struct sctp_authchunks val;
5096 struct sctp_association *asoc;
5097 struct sctp_chunks_param *ch;
5098 char __user *to;
5099
5100 if (len <= sizeof(struct sctp_authchunks))
5101 return -EINVAL;
5102
5103 if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
5104 return -EFAULT;
5105
5106 to = val.gauth_chunks;
5107 asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
5108 if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP))
5109 return -EINVAL;
5110
5111 if (asoc)
5112 ch = (struct sctp_chunks_param*)asoc->c.auth_chunks;
5113 else
5114 ch = sctp_sk(sk)->ep->auth_chunk_list;
5115
5116 if (len < ntohs(ch->param_hdr.length))
5117 return -EINVAL;
5118
5119 len = ntohs(ch->param_hdr.length);
5120 if (put_user(len, optlen))
5121 return -EFAULT;
5122 if (copy_to_user(to, ch->chunks, len))
5123 return -EFAULT;
5124
5125 return 0;
5126}
5127
4843SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, 5128SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
4844 char __user *optval, int __user *optlen) 5129 char __user *optval, int __user *optlen)
4845{ 5130{
@@ -4963,6 +5248,25 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
4963 case SCTP_MAX_BURST: 5248 case SCTP_MAX_BURST:
4964 retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); 5249 retval = sctp_getsockopt_maxburst(sk, len, optval, optlen);
4965 break; 5250 break;
5251 case SCTP_AUTH_KEY:
5252 case SCTP_AUTH_CHUNK:
5253 case SCTP_AUTH_DELETE_KEY:
5254 retval = -EOPNOTSUPP;
5255 break;
5256 case SCTP_HMAC_IDENT:
5257 retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen);
5258 break;
5259 case SCTP_AUTH_ACTIVE_KEY:
5260 retval = sctp_getsockopt_active_key(sk, len, optval, optlen);
5261 break;
5262 case SCTP_PEER_AUTH_CHUNKS:
5263 retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval,
5264 optlen);
5265 break;
5266 case SCTP_LOCAL_AUTH_CHUNKS:
5267 retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
5268 optlen);
5269 break;
4966 default: 5270 default:
4967 retval = -ENOPROTOOPT; 5271 retval = -ENOPROTOOPT;
4968 break; 5272 break;