aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r--net/dccp/proto.c53
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
41DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; 42DEFINE_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 */
260static 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
284out:
285 return rc;
286
287out_free_val:
288 kfree(val);
289 goto out;
290}
291
258int dccp_setsockopt(struct sock *sk, int level, int optname, 292int 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;