diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-11-17 01:51:23 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-17 01:51:23 -0500 |
commit | 49aebc66d6b896f9c7c5739d85c4548c00015aa7 (patch) | |
tree | 0b12afdd2e742c3eb481aef8d2adcb7b1aeca9f1 /net/dccp | |
parent | 0c1168398ecbfacbb27203b281bde20ec9f78017 (diff) |
dccp: Deprecate old setsockopt framework
The previous setsockopt interface, which passed socket options via struct
dccp_so_feat, is complicated/difficult to use. Continuing to support it leads to
ugly code since the old approach did not distinguish between NN and SP values.
This patch removes the old setsockopt interface and replaces it with two new
functions to register NN/SP values for feature negotiation.
These are essentially wrappers around the internal __feat_register functions,
with checking added to avoid
* wrong usage (type);
* changing values while the connection is in progress.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/feat.c | 72 | ||||
-rw-r--r-- | net/dccp/feat.h | 5 | ||||
-rw-r--r-- | net/dccp/proto.c | 53 |
3 files changed, 32 insertions, 98 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 4f86a48723f6..47ce9abaf72b 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -364,53 +364,35 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local, | |||
364 | return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); | 364 | return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); |
365 | } | 365 | } |
366 | 366 | ||
367 | int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, | 367 | /** |
368 | u8 *val, u8 len, gfp_t gfp) | 368 | * dccp_feat_register_sp - Register requests to change SP feature values |
369 | { | 369 | * @sk: client or listening socket |
370 | struct dccp_opt_pend *opt; | 370 | * @feat: one of %dccp_feature_numbers |
371 | 371 | * @is_local: whether the local (1) or remote (0) @feat is meant | |
372 | dccp_feat_debug(type, feature, *val); | 372 | * @list: array of preferred values, in descending order of preference |
373 | 373 | * @len: length of @list in bytes | |
374 | if (len > 3) { | 374 | */ |
375 | DCCP_WARN("invalid length %d\n", len); | 375 | int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, |
376 | u8 const *list, u8 len) | ||
377 | { /* any changes must be registered before establishing the connection */ | ||
378 | if (sk->sk_state != DCCP_CLOSED) | ||
379 | return -EISCONN; | ||
380 | if (dccp_feat_type(feat) != FEAT_SP) | ||
376 | return -EINVAL; | 381 | return -EINVAL; |
377 | } | 382 | return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local, |
378 | /* XXX add further sanity checks */ | 383 | 0, list, len); |
379 | |||
380 | /* check if that feature is already being negotiated */ | ||
381 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | ||
382 | /* ok we found a negotiation for this option already */ | ||
383 | if (opt->dccpop_feat == feature && opt->dccpop_type == type) { | ||
384 | dccp_pr_debug("Replacing old\n"); | ||
385 | /* replace */ | ||
386 | BUG_ON(opt->dccpop_val == NULL); | ||
387 | kfree(opt->dccpop_val); | ||
388 | opt->dccpop_val = val; | ||
389 | opt->dccpop_len = len; | ||
390 | opt->dccpop_conf = 0; | ||
391 | return 0; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | /* negotiation for a new feature */ | ||
396 | opt = kmalloc(sizeof(*opt), gfp); | ||
397 | if (opt == NULL) | ||
398 | return -ENOMEM; | ||
399 | |||
400 | opt->dccpop_type = type; | ||
401 | opt->dccpop_feat = feature; | ||
402 | opt->dccpop_len = len; | ||
403 | opt->dccpop_val = val; | ||
404 | opt->dccpop_conf = 0; | ||
405 | opt->dccpop_sc = NULL; | ||
406 | |||
407 | BUG_ON(opt->dccpop_val == NULL); | ||
408 | |||
409 | list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending); | ||
410 | return 0; | ||
411 | } | 384 | } |
412 | 385 | ||
413 | EXPORT_SYMBOL_GPL(dccp_feat_change); | 386 | /* Analogous to dccp_feat_register_sp(), but for non-negotiable values */ |
387 | int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val) | ||
388 | { | ||
389 | /* any changes must be registered before establishing the connection */ | ||
390 | if (sk->sk_state != DCCP_CLOSED) | ||
391 | return -EISCONN; | ||
392 | if (dccp_feat_type(feat) != FEAT_NN) | ||
393 | return -EINVAL; | ||
394 | return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val); | ||
395 | } | ||
414 | 396 | ||
415 | /* | 397 | /* |
416 | * Tracking features whose value depend on the choice of CCID | 398 | * Tracking features whose value depend on the choice of CCID |
@@ -1108,7 +1090,7 @@ int dccp_feat_init(struct sock *sk) | |||
1108 | 1090 | ||
1109 | /* Ack ratio */ | 1091 | /* Ack ratio */ |
1110 | rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, | 1092 | rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, |
1111 | dmsk->dccpms_ack_ratio); | 1093 | dp->dccps_l_ack_ratio); |
1112 | out: | 1094 | out: |
1113 | return rc; | 1095 | return rc; |
1114 | } | 1096 | } |
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index 232c653e69c5..4d172822df17 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -111,8 +111,9 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val) | |||
111 | #define dccp_feat_debug(type, feat, val) | 111 | #define dccp_feat_debug(type, feat, val) |
112 | #endif /* CONFIG_IP_DCCP_DEBUG */ | 112 | #endif /* CONFIG_IP_DCCP_DEBUG */ |
113 | 113 | ||
114 | extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, | 114 | extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, |
115 | u8 *val, u8 len, gfp_t gfp); | 115 | u8 const *list, u8 len); |
116 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); | ||
116 | extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, | 117 | extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, |
117 | u8 *val, u8 len); | 118 | u8 *val, u8 len); |
118 | extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | 119 | extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 1117d4d8c8f1..3090fc40eebd 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -470,44 +470,6 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service, | |||
470 | return 0; | 470 | return 0; |
471 | } | 471 | } |
472 | 472 | ||
473 | /* byte 1 is feature. the rest is the preference list */ | ||
474 | static int dccp_setsockopt_change(struct sock *sk, int type, | ||
475 | struct dccp_so_feat __user *optval) | ||
476 | { | ||
477 | struct dccp_so_feat opt; | ||
478 | u8 *val; | ||
479 | int rc; | ||
480 | |||
481 | if (copy_from_user(&opt, optval, sizeof(opt))) | ||
482 | return -EFAULT; | ||
483 | /* | ||
484 | * rfc4340: 6.1. Change Options | ||
485 | */ | ||
486 | if (opt.dccpsf_len < 1) | ||
487 | return -EINVAL; | ||
488 | |||
489 | val = kmalloc(opt.dccpsf_len, GFP_KERNEL); | ||
490 | if (!val) | ||
491 | return -ENOMEM; | ||
492 | |||
493 | if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) { | ||
494 | rc = -EFAULT; | ||
495 | goto out_free_val; | ||
496 | } | ||
497 | |||
498 | rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat, | ||
499 | val, opt.dccpsf_len, GFP_KERNEL); | ||
500 | if (rc) | ||
501 | goto out_free_val; | ||
502 | |||
503 | out: | ||
504 | return rc; | ||
505 | |||
506 | out_free_val: | ||
507 | kfree(val); | ||
508 | goto out; | ||
509 | } | ||
510 | |||
511 | static int do_dccp_setsockopt(struct sock *sk, int level, int optname, | 473 | static int do_dccp_setsockopt(struct sock *sk, int level, int optname, |
512 | char __user *optval, int optlen) | 474 | char __user *optval, int optlen) |
513 | { | 475 | { |
@@ -530,20 +492,9 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, | |||
530 | err = 0; | 492 | err = 0; |
531 | break; | 493 | break; |
532 | case DCCP_SOCKOPT_CHANGE_L: | 494 | case DCCP_SOCKOPT_CHANGE_L: |
533 | if (optlen != sizeof(struct dccp_so_feat)) | ||
534 | err = -EINVAL; | ||
535 | else | ||
536 | err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L, | ||
537 | (struct dccp_so_feat __user *) | ||
538 | optval); | ||
539 | break; | ||
540 | case DCCP_SOCKOPT_CHANGE_R: | 495 | case DCCP_SOCKOPT_CHANGE_R: |
541 | if (optlen != sizeof(struct dccp_so_feat)) | 496 | DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n"); |
542 | err = -EINVAL; | 497 | err = 0; |
543 | else | ||
544 | err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R, | ||
545 | (struct dccp_so_feat __user *) | ||
546 | optval); | ||
547 | break; | 498 | break; |
548 | case DCCP_SOCKOPT_SERVER_TIMEWAIT: | 499 | case DCCP_SOCKOPT_SERVER_TIMEWAIT: |
549 | if (dp->dccps_role != DCCP_ROLE_SERVER) | 500 | if (dp->dccps_role != DCCP_ROLE_SERVER) |