diff options
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r-- | net/dccp/proto.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 81ad24953710..1a8cf8ecfe63 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | #include "ccid.h" | 38 | #include "ccid.h" |
39 | #include "dccp.h" | 39 | #include "dccp.h" |
40 | #include "feat.h" | ||
40 | 41 | ||
41 | DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; | 42 | DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; |
42 | 43 | ||
@@ -255,6 +256,39 @@ static int dccp_setsockopt_service(struct sock *sk, const u32 service, | |||
255 | return 0; | 256 | return 0; |
256 | } | 257 | } |
257 | 258 | ||
259 | /* byte 1 is feature. the rest is the preference list */ | ||
260 | static int dccp_setsockopt_change(struct sock *sk, int type, | ||
261 | struct dccp_so_feat __user *optval) | ||
262 | { | ||
263 | struct dccp_so_feat opt; | ||
264 | u8 *val; | ||
265 | int rc; | ||
266 | |||
267 | if (copy_from_user(&opt, optval, sizeof(opt))) | ||
268 | return -EFAULT; | ||
269 | |||
270 | val = kmalloc(opt.dccpsf_len, GFP_KERNEL); | ||
271 | if (!val) | ||
272 | return -ENOMEM; | ||
273 | |||
274 | if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) { | ||
275 | rc = -EFAULT; | ||
276 | goto out_free_val; | ||
277 | } | ||
278 | |||
279 | rc = dccp_feat_change(sk, type, opt.dccpsf_feat, val, opt.dccpsf_len, | ||
280 | GFP_KERNEL); | ||
281 | if (rc) | ||
282 | goto out_free_val; | ||
283 | |||
284 | out: | ||
285 | return rc; | ||
286 | |||
287 | out_free_val: | ||
288 | kfree(val); | ||
289 | goto out; | ||
290 | } | ||
291 | |||
258 | int dccp_setsockopt(struct sock *sk, int level, int optname, | 292 | int dccp_setsockopt(struct sock *sk, int level, int optname, |
259 | char __user *optval, int optlen) | 293 | char __user *optval, int optlen) |
260 | { | 294 | { |
@@ -284,6 +318,25 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, | |||
284 | case DCCP_SOCKOPT_PACKET_SIZE: | 318 | case DCCP_SOCKOPT_PACKET_SIZE: |
285 | dp->dccps_packet_size = val; | 319 | dp->dccps_packet_size = val; |
286 | break; | 320 | break; |
321 | |||
322 | case DCCP_SOCKOPT_CHANGE_L: | ||
323 | if (optlen != sizeof(struct dccp_so_feat)) | ||
324 | err = -EINVAL; | ||
325 | else | ||
326 | err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L, | ||
327 | (struct dccp_so_feat *) | ||
328 | optval); | ||
329 | break; | ||
330 | |||
331 | case DCCP_SOCKOPT_CHANGE_R: | ||
332 | if (optlen != sizeof(struct dccp_so_feat)) | ||
333 | err = -EINVAL; | ||
334 | else | ||
335 | err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R, | ||
336 | (struct dccp_so_feat *) | ||
337 | optval); | ||
338 | break; | ||
339 | |||
287 | default: | 340 | default: |
288 | err = -ENOPROTOOPT; | 341 | err = -ENOPROTOOPT; |
289 | break; | 342 | break; |