aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/dccp.txt4
-rw-r--r--include/linux/dccp.h1
-rw-r--r--net/dccp/ccid.c48
-rw-r--r--net/dccp/ccid.h5
-rw-r--r--net/dccp/feat.c4
-rw-r--r--net/dccp/proto.c2
6 files changed, 64 insertions, 0 deletions
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
index 39131a3c78f8..f0aeb20fa63b 100644
--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,10 @@ can be set before calling bind().
57DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet 57DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
58size (application payload size) in bytes, see RFC 4340, section 14. 58size (application payload size) in bytes, see RFC 4340, section 14.
59 59
60DCCP_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).
62The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
63
60DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold 64DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
61timewait state when closing the connection (RFC 4340, 8.3). The usual case is 65timewait state when closing the connection (RFC 4340, 8.3). The usual case is
62that the closing server sends a CloseReq, whereupon the client holds timewait 66that the closing server sends a CloseReq, whereupon the client holds timewait
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 484b8a1fb023..d3ac1bde60b4 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -209,6 +209,7 @@ struct dccp_so_feat {
209#define DCCP_SOCKOPT_SERVER_TIMEWAIT 6 209#define DCCP_SOCKOPT_SERVER_TIMEWAIT 6
210#define DCCP_SOCKOPT_SEND_CSCOV 10 210#define DCCP_SOCKOPT_SEND_CSCOV 10
211#define DCCP_SOCKOPT_RECV_CSCOV 11 211#define DCCP_SOCKOPT_RECV_CSCOV 11
212#define DCCP_SOCKOPT_AVAILABLE_CCIDS 12
212#define DCCP_SOCKOPT_CCID_RX_INFO 128 213#define DCCP_SOCKOPT_CCID_RX_INFO 128
213#define DCCP_SOCKOPT_CCID_TX_INFO 192 214#define DCCP_SOCKOPT_CCID_TX_INFO 192
214 215
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c
index 8fe931a3d7a1..647cb0614f84 100644
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,13 @@
13 13
14#include "ccid.h" 14#include "ccid.h"
15 15
16static u8 builtin_ccids[] = {
17 DCCPC_CCID2, /* CCID2 is supported by default */
18#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
19 DCCPC_CCID3,
20#endif
21};
22
16static struct ccid_operations *ccids[CCID_MAX]; 23static struct ccid_operations *ccids[CCID_MAX];
17#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) 24#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
18static atomic_t ccids_lockct = ATOMIC_INIT(0); 25static atomic_t ccids_lockct = ATOMIC_INIT(0);
@@ -86,6 +93,47 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
86 } 93 }
87} 94}
88 95
96/* check that up to @array_len members in @ccid_array are supported */
97bool ccid_support_check(u8 const *ccid_array, u8 array_len)
98{
99 u8 i, j, found;
100
101 for (i = 0, found = 0; i < array_len; i++, found = 0) {
102 for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
103 found = (ccid_array[i] == builtin_ccids[j]);
104 if (!found)
105 return false;
106 }
107 return true;
108}
109
110/**
111 * ccid_get_builtin_ccids - Provide copy of `builtin' CCID array
112 * @ccid_array: pointer to copy into
113 * @array_len: value to return length into
114 * This function allocates memory - caller must see that it is freed after use.
115 */
116int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
117{
118 *ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
119 if (*ccid_array == NULL)
120 return -ENOBUFS;
121 *array_len = ARRAY_SIZE(builtin_ccids);
122 return 0;
123}
124
125int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
126 char __user *optval, int __user *optlen)
127{
128 if (len < sizeof(builtin_ccids))
129 return -EINVAL;
130
131 if (put_user(sizeof(builtin_ccids), optlen) ||
132 copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
133 return -EFAULT;
134 return 0;
135}
136
89int ccid_register(struct ccid_operations *ccid_ops) 137int ccid_register(struct ccid_operations *ccid_ops)
90{ 138{
91 int err = -ENOBUFS; 139 int err = -ENOBUFS;
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h
index fdeae7b57319..259f5469d7d0 100644
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -103,6 +103,11 @@ static inline void *ccid_priv(const struct ccid *ccid)
103 return (void *)ccid->ccid_priv; 103 return (void *)ccid->ccid_priv;
104} 104}
105 105
106extern bool ccid_support_check(u8 const *ccid_array, u8 array_len);
107extern int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
108extern int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
109 char __user *, int __user *);
110
106extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, 111extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
107 gfp_t gfp); 112 gfp_t gfp);
108 113
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 192d494a3816..f79fb5e33f5e 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -342,6 +342,10 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
342 !dccp_feat_sp_list_ok(feat, sp_val, sp_len)) 342 !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
343 return -EINVAL; 343 return -EINVAL;
344 344
345 /* Avoid negotiating alien CCIDs by only advertising supported ones */
346 if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
347 return -EOPNOTSUPP;
348
345 if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len)) 349 if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
346 return -ENOMEM; 350 return -ENOMEM;
347 351
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 01332fe7a99a..b4b10cbd8880 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -649,6 +649,8 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
649 case DCCP_SOCKOPT_GET_CUR_MPS: 649 case DCCP_SOCKOPT_GET_CUR_MPS:
650 val = dp->dccps_mss_cache; 650 val = dp->dccps_mss_cache;
651 break; 651 break;
652 case DCCP_SOCKOPT_AVAILABLE_CCIDS:
653 return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
652 case DCCP_SOCKOPT_SERVER_TIMEWAIT: 654 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
653 val = dp->dccps_server_timewait; 655 val = dp->dccps_server_timewait;
654 break; 656 break;