aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
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:28 -0400
commitfade756f18d42694e3acb00e3471ab43002cba16 (patch)
treef2ae912af9678315b672eb292ef17de42a97fbf3 /net/dccp
parent73bbe095bbb9ce5f94d5475bad54c7ccd8573b1b (diff)
dccp: Set per-connection CCIDs via socket options
With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which overrides the defaults set by the global sysctl variables for TX/RX CCIDs. To make full use of this facility, the remaining patches of this patch set are needed, which track dependencies and activate negotiated feature values. Note on the maximum number of CCIDs that can be registered: ----------------------------------------------------------- The maximum number of CCIDs that can be registered on the socket is constrained by the space in a Confirm/Change feature negotiation option. The space in these in turn depends on the size of header options as defined in RFC 4340, 5.8. Since this is a recurring constant, it has been moved from ackvec.h into linux/dccp.h, clarifying its purpose. Relative to this size, the maximum number of CCID identifiers that can be present in a Confirm option (which always consumes 1 byte more than a Change option, cf. 6.1) is 2 bytes less than the maximum TLV size: one for the CCID-feature-type and one for the selected value. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Diffstat (limited to 'net/dccp')
-rw-r--r--net/dccp/ackvec.c9
-rw-r--r--net/dccp/ackvec.h5
-rw-r--r--net/dccp/feat.h2
-rw-r--r--net/dccp/proto.c34
4 files changed, 42 insertions, 8 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 1e8be246ad15..01e4d39fa232 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -12,7 +12,6 @@
12#include "ackvec.h" 12#include "ackvec.h"
13#include "dccp.h" 13#include "dccp.h"
14 14
15#include <linux/dccp.h>
16#include <linux/init.h> 15#include <linux/init.h>
17#include <linux/errno.h> 16#include <linux/errno.h>
18#include <linux/kernel.h> 17#include <linux/kernel.h>
@@ -68,7 +67,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
68 struct dccp_sock *dp = dccp_sk(sk); 67 struct dccp_sock *dp = dccp_sk(sk);
69 struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; 68 struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
70 /* Figure out how many options do we need to represent the ackvec */ 69 /* Figure out how many options do we need to represent the ackvec */
71 const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN); 70 const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
72 u16 len = av->av_vec_len + 2 * nr_opts, i; 71 u16 len = av->av_vec_len + 2 * nr_opts, i;
73 u32 elapsed_time; 72 u32 elapsed_time;
74 const unsigned char *tail, *from; 73 const unsigned char *tail, *from;
@@ -100,8 +99,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
100 for (i = 0; i < nr_opts; ++i) { 99 for (i = 0; i < nr_opts; ++i) {
101 int copylen = len; 100 int copylen = len;
102 101
103 if (len > DCCP_MAX_ACKVEC_OPT_LEN) 102 if (len > DCCP_SINGLE_OPT_MAXLEN)
104 copylen = DCCP_MAX_ACKVEC_OPT_LEN; 103 copylen = DCCP_SINGLE_OPT_MAXLEN;
105 104
106 *to++ = DCCPO_ACK_VECTOR_0; 105 *to++ = DCCPO_ACK_VECTOR_0;
107 *to++ = copylen + 2; 106 *to++ = copylen + 2;
@@ -432,7 +431,7 @@ found:
432int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, 431int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
433 u64 *ackno, const u8 opt, const u8 *value, const u8 len) 432 u64 *ackno, const u8 opt, const u8 *value, const u8 len)
434{ 433{
435 if (len > DCCP_MAX_ACKVEC_OPT_LEN) 434 if (len > DCCP_SINGLE_OPT_MAXLEN)
436 return -1; 435 return -1;
437 436
438 /* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */ 437 /* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index bcb64fb4acef..4ccee030524e 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -11,15 +11,14 @@
11 * published by the Free Software Foundation. 11 * published by the Free Software Foundation.
12 */ 12 */
13 13
14#include <linux/dccp.h>
14#include <linux/compiler.h> 15#include <linux/compiler.h>
15#include <linux/ktime.h> 16#include <linux/ktime.h>
16#include <linux/list.h> 17#include <linux/list.h>
17#include <linux/types.h> 18#include <linux/types.h>
18 19
19/* Read about the ECN nonce to see why it is 253 */
20#define DCCP_MAX_ACKVEC_OPT_LEN 253
21/* We can spread an ack vector across multiple options */ 20/* We can spread an ack vector across multiple options */
22#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2) 21#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
23 22
24#define DCCP_ACKVEC_STATE_RECEIVED 0 23#define DCCP_ACKVEC_STATE_RECEIVED 0
25#define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6) 24#define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6)
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index 2c92bd18e5f4..b53b11717c40 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -22,6 +22,8 @@
22/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */ 22/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
23#define DCCPF_SEQ_WMIN 32 23#define DCCPF_SEQ_WMIN 32
24#define DCCPF_SEQ_WMAX 0x3FFFFFFFFFFFull 24#define DCCPF_SEQ_WMAX 0x3FFFFFFFFFFFull
25/* Maximum number of SP values that fit in a single (Confirm) option */
26#define DCCP_FEAT_MAX_SP_VALS (DCCP_SINGLE_OPT_MAXLEN - 2)
25 27
26enum dccp_feat_type { 28enum dccp_feat_type {
27 FEAT_AT_RX = 1, /* located at RX side of half-connection */ 29 FEAT_AT_RX = 1, /* located at RX side of half-connection */
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index e29bbf914057..2cd56df44d8e 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -506,6 +506,36 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
506 return rc; 506 return rc;
507} 507}
508 508
509static int dccp_setsockopt_ccid(struct sock *sk, int type,
510 char __user *optval, int optlen)
511{
512 u8 *val;
513 int rc = 0;
514
515 if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
516 return -EINVAL;
517
518 val = kmalloc(optlen, GFP_KERNEL);
519 if (val == NULL)
520 return -ENOMEM;
521
522 if (copy_from_user(val, optval, optlen)) {
523 kfree(val);
524 return -EFAULT;
525 }
526
527 lock_sock(sk);
528 if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
529 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
530
531 if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
532 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
533 release_sock(sk);
534
535 kfree(val);
536 return rc;
537}
538
509static int do_dccp_setsockopt(struct sock *sk, int level, int optname, 539static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
510 char __user *optval, int optlen) 540 char __user *optval, int optlen)
511{ 541{
@@ -520,6 +550,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
520 case DCCP_SOCKOPT_CHANGE_R: 550 case DCCP_SOCKOPT_CHANGE_R:
521 DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n"); 551 DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
522 return 0; 552 return 0;
553 case DCCP_SOCKOPT_CCID:
554 case DCCP_SOCKOPT_RX_CCID:
555 case DCCP_SOCKOPT_TX_CCID:
556 return dccp_setsockopt_ccid(sk, optname, optval, optlen);
523 } 557 }
524 558
525 if (optlen < (int)sizeof(int)) 559 if (optlen < (int)sizeof(int))