diff options
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/ccids/ccid2.c | 6 | ||||
-rw-r--r-- | net/dccp/feat.c | 123 | ||||
-rw-r--r-- | net/dccp/feat.h | 25 | ||||
-rw-r--r-- | net/dccp/proto.c | 2 |
4 files changed, 128 insertions, 28 deletions
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 9a430734530c..c9ea19a4d85e 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c | |||
@@ -25,7 +25,7 @@ | |||
25 | /* | 25 | /* |
26 | * This implementation should follow RFC 4341 | 26 | * This implementation should follow RFC 4341 |
27 | */ | 27 | */ |
28 | 28 | #include "../feat.h" | |
29 | #include "../ccid.h" | 29 | #include "../ccid.h" |
30 | #include "../dccp.h" | 30 | #include "../dccp.h" |
31 | #include "ccid2.h" | 31 | #include "ccid2.h" |
@@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val) | |||
147 | DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio); | 147 | DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio); |
148 | val = max_ratio; | 148 | val = max_ratio; |
149 | } | 149 | } |
150 | if (val > 0xFFFF) /* RFC 4340, 11.3 */ | 150 | if (val > DCCPF_ACK_RATIO_MAX) |
151 | val = 0xFFFF; | 151 | val = DCCPF_ACK_RATIO_MAX; |
152 | 152 | ||
153 | if (val == dp->dccps_l_ack_ratio) | 153 | if (val == dp->dccps_l_ack_ratio) |
154 | return; | 154 | return; |
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 77ce2f6b0319..b859722fba72 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -300,6 +300,95 @@ cloning_failed: | |||
300 | return -ENOMEM; | 300 | return -ENOMEM; |
301 | } | 301 | } |
302 | 302 | ||
303 | static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) | ||
304 | { | ||
305 | switch (feat_num) { | ||
306 | case DCCPF_ACK_RATIO: | ||
307 | return val <= DCCPF_ACK_RATIO_MAX; | ||
308 | case DCCPF_SEQUENCE_WINDOW: | ||
309 | return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX; | ||
310 | } | ||
311 | return 0; /* feature unknown - so we can't tell */ | ||
312 | } | ||
313 | |||
314 | /* check that SP values are within the ranges defined in RFC 4340 */ | ||
315 | static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val) | ||
316 | { | ||
317 | switch (feat_num) { | ||
318 | case DCCPF_CCID: | ||
319 | return val == DCCPC_CCID2 || val == DCCPC_CCID3; | ||
320 | /* Type-check Boolean feature values: */ | ||
321 | case DCCPF_SHORT_SEQNOS: | ||
322 | case DCCPF_ECN_INCAPABLE: | ||
323 | case DCCPF_SEND_ACK_VECTOR: | ||
324 | case DCCPF_SEND_NDP_COUNT: | ||
325 | case DCCPF_DATA_CHECKSUM: | ||
326 | case DCCPF_SEND_LEV_RATE: | ||
327 | return val < 2; | ||
328 | case DCCPF_MIN_CSUM_COVER: | ||
329 | return val < 16; | ||
330 | } | ||
331 | return 0; /* feature unknown */ | ||
332 | } | ||
333 | |||
334 | static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len) | ||
335 | { | ||
336 | if (sp_list == NULL || sp_len < 1) | ||
337 | return 0; | ||
338 | while (sp_len--) | ||
339 | if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++)) | ||
340 | return 0; | ||
341 | return 1; | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * __feat_register_nn - Register new NN value on socket | ||
346 | * @fn: feature-negotiation list to register with | ||
347 | * @feat: an NN feature from %dccp_feature_numbers | ||
348 | * @mandatory: use Mandatory option if 1 | ||
349 | * @nn_val: value to register (restricted to 4 bytes) | ||
350 | * Note that NN features are local by definition (RFC 4340, 6.3.2). | ||
351 | */ | ||
352 | static int __feat_register_nn(struct list_head *fn, u8 feat, | ||
353 | u8 mandatory, u64 nn_val) | ||
354 | { | ||
355 | dccp_feat_val fval = { .nn = nn_val }; | ||
356 | |||
357 | if (dccp_feat_type(feat) != FEAT_NN || | ||
358 | !dccp_feat_is_valid_nn_val(feat, nn_val)) | ||
359 | return -EINVAL; | ||
360 | |||
361 | /* Don't bother with default values, they will be activated anyway. */ | ||
362 | if (nn_val - (u64)dccp_feat_default_value(feat) == 0) | ||
363 | return 0; | ||
364 | |||
365 | return dccp_feat_push_change(fn, feat, 1, mandatory, &fval); | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * __feat_register_sp - Register new SP value/list on socket | ||
370 | * @fn: feature-negotiation list to register with | ||
371 | * @feat: an SP feature from %dccp_feature_numbers | ||
372 | * @is_local: whether the local (1) or the remote (0) @feat is meant | ||
373 | * @mandatory: use Mandatory option if 1 | ||
374 | * @sp_val: SP value followed by optional preference list | ||
375 | * @sp_len: length of @sp_val in bytes | ||
376 | */ | ||
377 | static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local, | ||
378 | u8 mandatory, u8 const *sp_val, u8 sp_len) | ||
379 | { | ||
380 | dccp_feat_val fval; | ||
381 | |||
382 | if (dccp_feat_type(feat) != FEAT_SP || | ||
383 | !dccp_feat_sp_list_ok(feat, sp_val, sp_len)) | ||
384 | return -EINVAL; | ||
385 | |||
386 | if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len)) | ||
387 | return -ENOMEM; | ||
388 | |||
389 | return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); | ||
390 | } | ||
391 | |||
303 | int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, | 392 | int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, |
304 | u8 *val, u8 len, gfp_t gfp) | 393 | u8 *val, u8 len, gfp_t gfp) |
305 | { | 394 | { |
@@ -836,42 +925,30 @@ out_clean: | |||
836 | 925 | ||
837 | EXPORT_SYMBOL_GPL(dccp_feat_clone); | 926 | EXPORT_SYMBOL_GPL(dccp_feat_clone); |
838 | 927 | ||
839 | static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat, | 928 | int dccp_feat_init(struct sock *sk) |
840 | u8 *val, u8 len) | ||
841 | { | ||
842 | int rc = -ENOMEM; | ||
843 | u8 *copy = kmemdup(val, len, GFP_KERNEL); | ||
844 | |||
845 | if (copy != NULL) { | ||
846 | rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL); | ||
847 | if (rc) | ||
848 | kfree(copy); | ||
849 | } | ||
850 | return rc; | ||
851 | } | ||
852 | |||
853 | int dccp_feat_init(struct dccp_minisock *dmsk) | ||
854 | { | 929 | { |
930 | struct dccp_sock *dp = dccp_sk(sk); | ||
931 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
855 | int rc; | 932 | int rc; |
856 | 933 | ||
857 | INIT_LIST_HEAD(&dmsk->dccpms_pending); | 934 | INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */ |
858 | INIT_LIST_HEAD(&dmsk->dccpms_conf); | 935 | INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */ |
859 | 936 | ||
860 | /* CCID L */ | 937 | /* CCID L */ |
861 | rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID, | 938 | rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0, |
862 | &dmsk->dccpms_tx_ccid, 1); | 939 | &dmsk->dccpms_tx_ccid, 1); |
863 | if (rc) | 940 | if (rc) |
864 | goto out; | 941 | goto out; |
865 | 942 | ||
866 | /* CCID R */ | 943 | /* CCID R */ |
867 | rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID, | 944 | rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0, |
868 | &dmsk->dccpms_rx_ccid, 1); | 945 | &dmsk->dccpms_rx_ccid, 1); |
869 | if (rc) | 946 | if (rc) |
870 | goto out; | 947 | goto out; |
871 | 948 | ||
872 | /* Ack ratio */ | 949 | /* Ack ratio */ |
873 | rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO, | 950 | rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, |
874 | &dmsk->dccpms_ack_ratio, 1); | 951 | dmsk->dccpms_ack_ratio); |
875 | out: | 952 | out: |
876 | return rc; | 953 | return rc; |
877 | } | 954 | } |
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index 7e953fd0a79b..9eefdb43783e 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -14,6 +14,15 @@ | |||
14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | #include "dccp.h" | 15 | #include "dccp.h" |
16 | 16 | ||
17 | /* | ||
18 | * Known limit values | ||
19 | */ | ||
20 | /* Ack Ratio takes 2-byte integer values (11.3) */ | ||
21 | #define DCCPF_ACK_RATIO_MAX 0xFFFF | ||
22 | /* Wmin=32 and Wmax=2^46-1 from 7.5.2 */ | ||
23 | #define DCCPF_SEQ_WMIN 32 | ||
24 | #define DCCPF_SEQ_WMAX 0x3FFFFFFFFFFFull | ||
25 | |||
17 | enum dccp_feat_type { | 26 | enum dccp_feat_type { |
18 | FEAT_AT_RX = 1, /* located at RX side of half-connection */ | 27 | FEAT_AT_RX = 1, /* located at RX side of half-connection */ |
19 | FEAT_AT_TX = 2, /* located at TX side of half-connection */ | 28 | FEAT_AT_TX = 2, /* located at TX side of half-connection */ |
@@ -74,6 +83,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry) | |||
74 | return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R; | 83 | return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R; |
75 | } | 84 | } |
76 | 85 | ||
86 | /** | ||
87 | * struct ccid_dependency - Track changes resulting from choosing a CCID | ||
88 | * @dependent_feat: one of %dccp_feature_numbers | ||
89 | * @is_local: local (1) or remote (0) @dependent_feat | ||
90 | * @is_mandatory: whether presence of @dependent_feat is mission-critical or not | ||
91 | * @val: corresponding default value for @dependent_feat (u8 is sufficient here) | ||
92 | */ | ||
93 | struct ccid_dependency { | ||
94 | u8 dependent_feat; | ||
95 | bool is_local:1, | ||
96 | is_mandatory:1; | ||
97 | u8 val; | ||
98 | }; | ||
99 | |||
77 | #ifdef CONFIG_IP_DCCP_DEBUG | 100 | #ifdef CONFIG_IP_DCCP_DEBUG |
78 | extern const char *dccp_feat_typename(const u8 type); | 101 | extern const char *dccp_feat_typename(const u8 type); |
79 | extern const char *dccp_feat_name(const u8 feat); | 102 | extern const char *dccp_feat_name(const u8 feat); |
@@ -96,6 +119,6 @@ extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | |||
96 | extern void dccp_feat_clean(struct dccp_minisock *dmsk); | 119 | extern void dccp_feat_clean(struct dccp_minisock *dmsk); |
97 | extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); | 120 | extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); |
98 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); | 121 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); |
99 | extern int dccp_feat_init(struct dccp_minisock *dmsk); | 122 | extern int dccp_feat_init(struct sock *sk); |
100 | 123 | ||
101 | #endif /* _DCCP_FEAT_H */ | 124 | #endif /* _DCCP_FEAT_H */ |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index dafcefd86594..01332fe7a99a 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) | |||
202 | * setsockopt(CCIDs-I-want/accept). -acme | 202 | * setsockopt(CCIDs-I-want/accept). -acme |
203 | */ | 203 | */ |
204 | if (likely(ctl_sock_initialized)) { | 204 | if (likely(ctl_sock_initialized)) { |
205 | int rc = dccp_feat_init(dmsk); | 205 | int rc = dccp_feat_init(sk); |
206 | 206 | ||
207 | if (rc) | 207 | if (rc) |
208 | return rc; | 208 | return rc; |