diff options
-rw-r--r-- | Documentation/networking/dccp.txt | 4 | ||||
-rw-r--r-- | include/linux/dccp.h | 1 | ||||
-rw-r--r-- | net/dccp/ccid.c | 48 | ||||
-rw-r--r-- | net/dccp/ccid.h | 5 | ||||
-rw-r--r-- | net/dccp/feat.c | 4 | ||||
-rw-r--r-- | net/dccp/proto.c | 2 |
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(). | |||
57 | DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet | 57 | DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet |
58 | size (application payload size) in bytes, see RFC 4340, section 14. | 58 | size (application payload size) in bytes, see RFC 4340, section 14. |
59 | 59 | ||
60 | 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). | ||
62 | The caller needs to provide a sufficiently large (> 2) array of type uint8_t. | ||
63 | |||
60 | DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold | 64 | DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold |
61 | timewait state when closing the connection (RFC 4340, 8.3). The usual case is | 65 | timewait state when closing the connection (RFC 4340, 8.3). The usual case is |
62 | that the closing server sends a CloseReq, whereupon the client holds timewait | 66 | 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 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 | ||
16 | static 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 | |||
16 | static struct ccid_operations *ccids[CCID_MAX]; | 23 | static struct ccid_operations *ccids[CCID_MAX]; |
17 | #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) | 24 | #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) |
18 | static atomic_t ccids_lockct = ATOMIC_INIT(0); | 25 | static 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 */ | ||
97 | bool 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 | */ | ||
116 | int 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 | |||
125 | int 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 | |||
89 | int ccid_register(struct ccid_operations *ccid_ops) | 137 | int 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 | ||
106 | extern bool ccid_support_check(u8 const *ccid_array, u8 array_len); | ||
107 | extern int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len); | ||
108 | extern int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, | ||
109 | char __user *, int __user *); | ||
110 | |||
106 | extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, | 111 | extern 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; |