diff options
-rw-r--r-- | Documentation/networking/dccp.txt | 14 | ||||
-rw-r--r-- | include/linux/dccp.h | 5 | ||||
-rw-r--r-- | net/dccp/ackvec.c | 9 | ||||
-rw-r--r-- | net/dccp/ackvec.h | 5 | ||||
-rw-r--r-- | net/dccp/feat.h | 2 | ||||
-rw-r--r-- | net/dccp/proto.c | 34 |
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 | |||
61 | supported by the endpoint (see include/linux/dccp.h for symbolic constants). | 61 | supported by the endpoint (see include/linux/dccp.h for symbolic constants). |
62 | The caller needs to provide a sufficiently large (> 2) array of type uint8_t. | 62 | The caller needs to provide a sufficiently large (> 2) array of type uint8_t. |
63 | 63 | ||
64 | DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same | ||
65 | time, combining the operation of the next two socket options. This option is | ||
66 | preferrable over the latter two, since often applications will use the same | ||
67 | type of CCID for both directions; and mixed use of CCIDs is not currently well | ||
68 | understood. This socket option takes as argument at least one uint8_t value, or | ||
69 | an array of uint8_t values, which must match available CCIDS (see above). CCIDs | ||
70 | must be registered on the socket before calling connect() or listen(). | ||
71 | |||
72 | DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets | ||
73 | the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID. | ||
74 | Please note that the getsockopt argument type here is `int', not uint8_t. | ||
75 | |||
76 | DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID. | ||
77 | |||
64 | DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold | 78 | DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold |
65 | timewait state when closing the connection (RFC 4340, 8.3). The usual case is | 79 | timewait state when closing the connection (RFC 4340, 8.3). The usual case is |
66 | that the closing server sends a CloseReq, whereupon the client holds timewait | 80 | that 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 */ |
173 | enum { | 175 | enum { |
@@ -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: | |||
432 | int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, | 431 | int 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 | ||
26 | enum dccp_feat_type { | 28 | enum 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 | ||
504 | static 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 | |||
504 | static int do_dccp_setsockopt(struct sock *sk, int level, int optname, | 534 | static 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)) |