aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)