aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:27 -0400
commit668144f7b41716a9efe1b398e15ead32a26cd101 (patch)
treeed535a5e2e2dc2dd8509336d2682aeaae66e4c00
parentd4c8741c431e07cfc66eb2b4c3a17b8d4975d9c0 (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>
-rw-r--r--include/linux/dccp.h7
-rw-r--r--net/dccp/feat.c72
-rw-r--r--net/dccp/feat.h5
-rw-r--r--net/dccp/proto.c53
4 files changed, 32 insertions, 105 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index d3ac1bde60b4..6eaaca9b037a 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -193,13 +193,6 @@ enum dccp_feature_numbers {
193 DCCPF_MAX_CCID_SPECIFIC = 255, 193 DCCPF_MAX_CCID_SPECIFIC = 255,
194}; 194};
195 195
196/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
197struct dccp_so_feat {
198 __u8 dccpsf_feat;
199 __u8 __user *dccpsf_val;
200 __u8 dccpsf_len;
201};
202
203/* DCCP socket options */ 196/* DCCP socket options */
204#define DCCP_SOCKOPT_PACKET_SIZE 1 /* XXX deprecated, without effect */ 197#define DCCP_SOCKOPT_PACKET_SIZE 1 /* XXX deprecated, without effect */
205#define DCCP_SOCKOPT_SERVICE 2 198#define DCCP_SOCKOPT_SERVICE 2
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 6852960bb0a9..44b10afd3fb6 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -393,53 +393,35 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
393 return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); 393 return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
394} 394}
395 395
396int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 396/**
397 u8 *val, u8 len, gfp_t gfp) 397 * dccp_feat_register_sp - Register requests to change SP feature values
398{ 398 * @sk: client or listening socket
399 struct dccp_opt_pend *opt; 399 * @feat: one of %dccp_feature_numbers
400 400 * @is_local: whether the local (1) or remote (0) @feat is meant
401 dccp_feat_debug(type, feature, *val); 401 * @list: array of preferred values, in descending order of preference
402 402 * @len: length of @list in bytes
403 if (len > 3) { 403 */
404 DCCP_WARN("invalid length %d\n", len); 404int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
405 u8 const *list, u8 len)
406{ /* any changes must be registered before establishing the connection */
407 if (sk->sk_state != DCCP_CLOSED)
408 return -EISCONN;
409 if (dccp_feat_type(feat) != FEAT_SP)
405 return -EINVAL; 410 return -EINVAL;
406 } 411 return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local,
407 /* XXX add further sanity checks */ 412 0, list, len);
408
409 /* check if that feature is already being negotiated */
410 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
411 /* ok we found a negotiation for this option already */
412 if (opt->dccpop_feat == feature && opt->dccpop_type == type) {
413 dccp_pr_debug("Replacing old\n");
414 /* replace */
415 BUG_ON(opt->dccpop_val == NULL);
416 kfree(opt->dccpop_val);
417 opt->dccpop_val = val;
418 opt->dccpop_len = len;
419 opt->dccpop_conf = 0;
420 return 0;
421 }
422 }
423
424 /* negotiation for a new feature */
425 opt = kmalloc(sizeof(*opt), gfp);
426 if (opt == NULL)
427 return -ENOMEM;
428
429 opt->dccpop_type = type;
430 opt->dccpop_feat = feature;
431 opt->dccpop_len = len;
432 opt->dccpop_val = val;
433 opt->dccpop_conf = 0;
434 opt->dccpop_sc = NULL;
435
436 BUG_ON(opt->dccpop_val == NULL);
437
438 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending);
439 return 0;
440} 413}
441 414
442EXPORT_SYMBOL_GPL(dccp_feat_change); 415/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */
416int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
417{
418 /* any changes must be registered before establishing the connection */
419 if (sk->sk_state != DCCP_CLOSED)
420 return -EISCONN;
421 if (dccp_feat_type(feat) != FEAT_NN)
422 return -EINVAL;
423 return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
424}
443 425
444/* 426/*
445 * Tracking features whose value depend on the choice of CCID 427 * Tracking features whose value depend on the choice of CCID
@@ -1137,7 +1119,7 @@ int dccp_feat_init(struct sock *sk)
1137 1119
1138 /* Ack ratio */ 1120 /* Ack ratio */
1139 rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, 1121 rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
1140 dmsk->dccpms_ack_ratio); 1122 dp->dccps_l_ack_ratio);
1141out: 1123out:
1142 return rc; 1124 return rc;
1143} 1125}
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index 9eefdb43783e..2c92bd18e5f4 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -110,8 +110,9 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
110#define dccp_feat_debug(type, feat, val) 110#define dccp_feat_debug(type, feat, val)
111#endif /* CONFIG_IP_DCCP_DEBUG */ 111#endif /* CONFIG_IP_DCCP_DEBUG */
112 112
113extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 113extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
114 u8 *val, u8 len, gfp_t gfp); 114 u8 const *list, u8 len);
115extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
115extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, 116extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
116 u8 *val, u8 len); 117 u8 *val, u8 len);
117extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 118extern 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 46cb3490d48e..108d56bd25c5 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 */
474static 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
503out:
504 return rc;
505
506out_free_val:
507 kfree(val);
508 goto out;
509}
510
511static int do_dccp_setsockopt(struct sock *sk, int level, int optname, 473static 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)