diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 304 |
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 | */ | ||
2956 | static 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 | */ | ||
2985 | static 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); | ||
3011 | out: | ||
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 | */ | ||
3022 | static 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); | ||
3049 | out: | ||
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 | */ | ||
3060 | static 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 | */ | ||
3085 | static 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 | ||
5016 | static 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 | |||
5035 | static 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 | |||
5058 | static 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 | |||
5092 | static 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 | |||
4843 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 5128 | SCTP_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; |