diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:30:19 -0400 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:45:27 -0400 |
commit | 86349c8d9c6892b57aff4549256ab1aa65aed0f0 (patch) | |
tree | 7fdd7a5d44b7999c8426012c83705cd3fec92cf7 /net/dccp/feat.c | |
parent | 5591d286281fdfb57914f5fad3ca001d44ce8fc6 (diff) |
dccp: Registration routines for changing feature values
Two registration routines, for SP and NN features, are provided by this patch,
replacing a previous routine which was used for both feature types.
These are internal-only routines and therefore start with `__feat_register'.
It further exports the known limits of Sequence Window and Ack Ratio as symbolic
constants.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Diffstat (limited to 'net/dccp/feat.c')
-rw-r--r-- | net/dccp/feat.c | 123 |
1 files changed, 100 insertions, 23 deletions
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 | } |