aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-11-17 01:51:23 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-17 01:51:23 -0500
commit49aebc66d6b896f9c7c5739d85c4548c00015aa7 (patch)
tree0b12afdd2e742c3eb481aef8d2adcb7b1aeca9f1
parent0c1168398ecbfacbb27203b281bde20ec9f78017 (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>
-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 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
367int 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); 375int 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
413EXPORT_SYMBOL_GPL(dccp_feat_change); 386/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */
387int 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);
1112out: 1094out:
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
114extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 114extern 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);
116extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
116extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, 117extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
117 u8 *val, u8 len); 118 u8 *val, u8 len);
118extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 119extern 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 */
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)