aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-11-23 19:02:31 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-23 19:02:31 -0500
commitb20a9c24d5c5d466d7e4a25c6f1bedbd2d16ad4f (patch)
tree17789215657f693caf36e22d3e724cc1b1e07ba6 /net
parent2c62ad7b56fa8e2658253c0256ef4c4de228a0b9 (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. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-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 4d172822df17..093af1610d11 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 8b63394ec24c..445884cf1c29 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -501,6 +501,36 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
501 return rc; 501 return rc;
502} 502}
503 503
504static int dccp_setsockopt_ccid(struct sock *sk, int type,
505 char __user *optval, int optlen)
506{
507 u8 *val;
508 int rc = 0;
509
510 if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
511 return -EINVAL;
512
513 val = kmalloc(optlen, GFP_KERNEL);
514 if (val == NULL)
515 return -ENOMEM;
516
517 if (copy_from_user(val, optval, optlen)) {
518 kfree(val);
519 return -EFAULT;
520 }
521
522 lock_sock(sk);
523 if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
524 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
525
526 if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
527 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
528 release_sock(sk);
529
530 kfree(val);
531 return rc;
532}
533
504static int do_dccp_setsockopt(struct sock *sk, int level, int optname, 534static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
505 char __user *optval, int optlen) 535 char __user *optval, int optlen)
506{ 536{
@@ -515,6 +545,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
515 case DCCP_SOCKOPT_CHANGE_R: 545 case DCCP_SOCKOPT_CHANGE_R:
516 DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n"); 546 DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
517 return 0; 547 return 0;
548 case DCCP_SOCKOPT_CCID:
549 case DCCP_SOCKOPT_RX_CCID:
550 case DCCP_SOCKOPT_TX_CCID:
551 return dccp_setsockopt_ccid(sk, optname, optval, optlen);
518 } 552 }
519 553
520 if (optlen < (int)sizeof(int)) 554 if (optlen < (int)sizeof(int))