aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/dccp.txt14
-rw-r--r--include/linux/dccp.h5
-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
6 files changed, 61 insertions, 8 deletions
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
index 43df4487379b..610083ff73f6 100644
--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
61supported by the endpoint (see include/linux/dccp.h for symbolic constants). 61supported by the endpoint (see include/linux/dccp.h for symbolic constants).
62The caller needs to provide a sufficiently large (> 2) array of type uint8_t. 62The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
63 63
64DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
65time, combining the operation of the next two socket options. This option is
66preferrable over the latter two, since often applications will use the same
67type of CCID for both directions; and mixed use of CCIDs is not currently well
68understood. This socket option takes as argument at least one uint8_t value, or
69an array of uint8_t values, which must match available CCIDS (see above). CCIDs
70must be registered on the socket before calling connect() or listen().
71
72DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
73the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
74Please note that the getsockopt argument type here is `int', not uint8_t.
75
76DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
77
64DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold 78DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
65timewait state when closing the connection (RFC 4340, 8.3). The usual case is 79timewait state when closing the connection (RFC 4340, 8.3). The usual case is
66that the closing server sends a CloseReq, whereupon the client holds timewait 80that the closing server sends a CloseReq, whereupon the client holds timewait
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index eda389ce04f4..6a72ff52a8a4 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -168,6 +168,8 @@ enum {
168 DCCPO_MIN_CCID_SPECIFIC = 128, 168 DCCPO_MIN_CCID_SPECIFIC = 128,
169 DCCPO_MAX_CCID_SPECIFIC = 255, 169 DCCPO_MAX_CCID_SPECIFIC = 255,
170}; 170};
171/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */
172#define DCCP_SINGLE_OPT_MAXLEN 253
171 173
172/* DCCP CCIDS */ 174/* DCCP CCIDS */
173enum { 175enum {
@@ -203,6 +205,9 @@ enum dccp_feature_numbers {
203#define DCCP_SOCKOPT_SEND_CSCOV 10 205#define DCCP_SOCKOPT_SEND_CSCOV 10
204#define DCCP_SOCKOPT_RECV_CSCOV 11 206#define DCCP_SOCKOPT_RECV_CSCOV 11
205#define DCCP_SOCKOPT_AVAILABLE_CCIDS 12 207#define DCCP_SOCKOPT_AVAILABLE_CCIDS 12
208#define DCCP_SOCKOPT_CCID 13
209#define DCCP_SOCKOPT_TX_CCID 14
210#define DCCP_SOCKOPT_RX_CCID 15
206#define DCCP_SOCKOPT_CCID_RX_INFO 128 211#define DCCP_SOCKOPT_CCID_RX_INFO 128
207#define DCCP_SOCKOPT_CCID_TX_INFO 192 212#define DCCP_SOCKOPT_CCID_TX_INFO 192
208 213
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))