diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2006-11-14 09:48:10 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:22:29 -0500 |
commit | c02fdc0e81e9c735d8d895af1e201b235df326d8 (patch) | |
tree | f30af6744e4ecea9e5bb12483addb306d49ce458 | |
parent | 6a128e053e75a5f1be9fb53d0d53159f88197c61 (diff) |
[DCCP]: Make feature negotiation more readable
This patch replaces cryptic feature negotiation messages of type
Oct 31 15:42:20 kernel: dccp_feat_change: feat change type=32 feat=1
Oct 31 15:42:21 kernel: dccp_feat_change: feat change type=34 feat=1
Oct 31 15:42:21 kernel: dccp_feat_change: feat change type=32 feat=5
into ones of type:
Nov 2 13:54:45 kernel: dccp_feat_change: ChangeL(CCID (1), 3)
Nov 2 13:54:45 kernel: dccp_feat_change: ChangeR(CCID (1), 3)
Nov 2 13:54:45 kernel: dccp_feat_change: ChangeL(Ack Ratio (5), 2)
Also,
* completed the feature number list wrt RFC 4340 sec. 6.4
* annotating which ones have been implemented so far
* implemented rudimentary sanity checking in feat.c (FIXMEs)
* some minor fixes
Commiter note: uninlined dccp_feat_name and dccp_feat_typename, for
consistency with dccp_{state,packet}_name, that, BTW,
should be compiled only if CONFIG_IP_DCCP_DEBUG is
selected, leaving this to another cset tho. Also
shortened dccp_feat_negotiation_debug to dccp_feat_debug.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
-rw-r--r-- | include/linux/dccp.h | 25 | ||||
-rw-r--r-- | net/dccp/feat.c | 116 | ||||
-rw-r--r-- | net/dccp/feat.h | 41 | ||||
-rw-r--r-- | net/dccp/options.c | 4 |
4 files changed, 145 insertions, 41 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 0502dfa7f32c..696319ee2d5b 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -175,18 +175,21 @@ enum { | |||
175 | DCCPC_CCID3 = 3, | 175 | DCCPC_CCID3 = 3, |
176 | }; | 176 | }; |
177 | 177 | ||
178 | /* DCCP features */ | 178 | /* DCCP features (RFC 4340 section 6.4) */ |
179 | enum { | 179 | enum { |
180 | DCCPF_RESERVED = 0, | 180 | DCCPF_RESERVED = 0, |
181 | DCCPF_CCID = 1, | 181 | DCCPF_CCID = 1, |
182 | DCCPF_SEQUENCE_WINDOW = 3, | 182 | DCCPF_SHORT_SEQNOS = 2, /* XXX: not yet implemented */ |
183 | DCCPF_ACK_RATIO = 5, | 183 | DCCPF_SEQUENCE_WINDOW = 3, |
184 | DCCPF_SEND_ACK_VECTOR = 6, | 184 | DCCPF_ECN_INCAPABLE = 4, /* XXX: not yet implemented */ |
185 | DCCPF_SEND_NDP_COUNT = 7, | 185 | DCCPF_ACK_RATIO = 5, |
186 | DCCPF_SEND_ACK_VECTOR = 6, | ||
187 | DCCPF_SEND_NDP_COUNT = 7, | ||
186 | DCCPF_MIN_CSUM_COVER = 8, | 188 | DCCPF_MIN_CSUM_COVER = 8, |
187 | /* 10-127 reserved */ | 189 | DCCPF_DATA_CHECKSUM = 9, /* XXX: not yet implemented */ |
188 | DCCPF_MIN_CCID_SPECIFIC = 128, | 190 | /* 10-127 reserved */ |
189 | DCCPF_MAX_CCID_SPECIFIC = 255, | 191 | DCCPF_MIN_CCID_SPECIFIC = 128, |
192 | DCCPF_MAX_CCID_SPECIFIC = 255, | ||
190 | }; | 193 | }; |
191 | 194 | ||
192 | /* this structure is argument to DCCP_SOCKOPT_CHANGE_X */ | 195 | /* this structure is argument to DCCP_SOCKOPT_CHANGE_X */ |
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index a1b0682ee77c..12cde2f2f13b 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -12,7 +12,6 @@ | |||
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | 14 | ||
15 | #include "dccp.h" | ||
16 | #include "ccid.h" | 15 | #include "ccid.h" |
17 | #include "feat.h" | 16 | #include "feat.h" |
18 | 17 | ||
@@ -23,9 +22,17 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, | |||
23 | { | 22 | { |
24 | struct dccp_opt_pend *opt; | 23 | struct dccp_opt_pend *opt; |
25 | 24 | ||
26 | dccp_pr_debug("feat change type=%d feat=%d\n", type, feature); | 25 | dccp_feat_debug(type, feature, *val); |
27 | 26 | ||
28 | /* XXX sanity check feat change request */ | 27 | if (!dccp_feat_is_valid_type(type)) { |
28 | pr_info("option type %d invalid in negotiation\n", type); | ||
29 | return 1; | ||
30 | } | ||
31 | if (!dccp_feat_is_valid_length(type, feature, len)) { | ||
32 | pr_info("invalid length %d\n", len); | ||
33 | return 1; | ||
34 | } | ||
35 | /* XXX add further sanity checks */ | ||
29 | 36 | ||
30 | /* check if that feature is already being negotiated */ | 37 | /* check if that feature is already being negotiated */ |
31 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | 38 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { |
@@ -95,14 +102,14 @@ static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) | |||
95 | /* XXX taking only u8 vals */ | 102 | /* XXX taking only u8 vals */ |
96 | static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) | 103 | static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) |
97 | { | 104 | { |
98 | dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val); | 105 | dccp_feat_debug(type, feat, val); |
99 | 106 | ||
100 | switch (feat) { | 107 | switch (feat) { |
101 | case DCCPF_CCID: | 108 | case DCCPF_CCID: |
102 | return dccp_feat_update_ccid(sk, type, val); | 109 | return dccp_feat_update_ccid(sk, type, val); |
103 | default: | 110 | default: |
104 | dccp_pr_debug("IMPLEMENT changing [%d] feat %d to %d\n", | 111 | dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n", |
105 | type, feat, val); | 112 | dccp_feat_typename(type), feat); |
106 | break; | 113 | break; |
107 | } | 114 | } |
108 | return 0; | 115 | return 0; |
@@ -265,10 +272,10 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | |||
265 | u8 *copy; | 272 | u8 *copy; |
266 | int rc; | 273 | int rc; |
267 | 274 | ||
268 | /* NN features must be change L */ | 275 | /* NN features must be Change L (sec. 6.3.2) */ |
269 | if (type == DCCPO_CHANGE_R) { | 276 | if (type != DCCPO_CHANGE_L) { |
270 | dccp_pr_debug("received CHANGE_R %d for NN feat %d\n", | 277 | dccp_pr_debug("received %s for NN feature %d\n", |
271 | type, feature); | 278 | dccp_feat_typename(type), feature); |
272 | return -EFAULT; | 279 | return -EFAULT; |
273 | } | 280 | } |
274 | 281 | ||
@@ -299,7 +306,8 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | |||
299 | return rc; | 306 | return rc; |
300 | } | 307 | } |
301 | 308 | ||
302 | dccp_pr_debug("Confirming NN feature %d (val=%d)\n", feature, *copy); | 309 | dccp_feat_debug(type, feature, *copy); |
310 | |||
303 | list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); | 311 | list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); |
304 | 312 | ||
305 | return 0; | 313 | return 0; |
@@ -318,14 +326,19 @@ static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, | |||
318 | return; | 326 | return; |
319 | } | 327 | } |
320 | 328 | ||
321 | opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R : | 329 | switch (type) { |
322 | DCCPO_CONFIRM_L; | 330 | case DCCPO_CHANGE_L: opt->dccpop_type = DCCPO_CONFIRM_R; break; |
331 | case DCCPO_CHANGE_R: opt->dccpop_type = DCCPO_CONFIRM_L; break; | ||
332 | default: pr_info("invalid type %d\n", type); return; | ||
333 | |||
334 | } | ||
323 | opt->dccpop_feat = feature; | 335 | opt->dccpop_feat = feature; |
324 | opt->dccpop_val = NULL; | 336 | opt->dccpop_val = NULL; |
325 | opt->dccpop_len = 0; | 337 | opt->dccpop_len = 0; |
326 | 338 | ||
327 | /* change feature */ | 339 | /* change feature */ |
328 | dccp_pr_debug("Empty confirm feature %d type %d\n", feature, type); | 340 | dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); |
341 | |||
329 | list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); | 342 | list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); |
330 | } | 343 | } |
331 | 344 | ||
@@ -359,7 +372,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | |||
359 | { | 372 | { |
360 | int rc; | 373 | int rc; |
361 | 374 | ||
362 | dccp_pr_debug("got feat change type=%d feat=%d\n", type, feature); | 375 | dccp_feat_debug(type, feature, *val); |
363 | 376 | ||
364 | /* figure out if it's SP or NN feature */ | 377 | /* figure out if it's SP or NN feature */ |
365 | switch (feature) { | 378 | switch (feature) { |
@@ -375,6 +388,8 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | |||
375 | 388 | ||
376 | /* XXX implement other features */ | 389 | /* XXX implement other features */ |
377 | default: | 390 | default: |
391 | dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", | ||
392 | dccp_feat_typename(type), feature); | ||
378 | rc = -EFAULT; | 393 | rc = -EFAULT; |
379 | break; | 394 | break; |
380 | } | 395 | } |
@@ -403,20 +418,27 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | |||
403 | u8 t; | 418 | u8 t; |
404 | struct dccp_opt_pend *opt; | 419 | struct dccp_opt_pend *opt; |
405 | struct dccp_minisock *dmsk = dccp_msk(sk); | 420 | struct dccp_minisock *dmsk = dccp_msk(sk); |
406 | int rc = 1; | 421 | int found = 0; |
407 | int all_confirmed = 1; | 422 | int all_confirmed = 1; |
408 | 423 | ||
409 | dccp_pr_debug("got feat confirm type=%d feat=%d\n", type, feature); | 424 | dccp_feat_debug(type, feature, *val); |
410 | |||
411 | /* XXX sanity check type & feat */ | ||
412 | 425 | ||
413 | /* locate our change request */ | 426 | /* locate our change request */ |
414 | t = type == DCCPO_CONFIRM_L ? DCCPO_CHANGE_R : DCCPO_CHANGE_L; | 427 | switch (type) { |
428 | case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; | ||
429 | case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; | ||
430 | default: pr_info("invalid type %d\n", type); | ||
431 | return 1; | ||
432 | |||
433 | } | ||
434 | /* XXX sanity check feature value */ | ||
415 | 435 | ||
416 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | 436 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { |
417 | if (!opt->dccpop_conf && opt->dccpop_type == t && | 437 | if (!opt->dccpop_conf && opt->dccpop_type == t && |
418 | opt->dccpop_feat == feature) { | 438 | opt->dccpop_feat == feature) { |
419 | /* we found it */ | 439 | found = 1; |
440 | dccp_pr_debug("feature %d found\n", opt->dccpop_feat); | ||
441 | |||
420 | /* XXX do sanity check */ | 442 | /* XXX do sanity check */ |
421 | 443 | ||
422 | opt->dccpop_conf = 1; | 444 | opt->dccpop_conf = 1; |
@@ -425,9 +447,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | |||
425 | dccp_feat_update(sk, opt->dccpop_type, | 447 | dccp_feat_update(sk, opt->dccpop_type, |
426 | opt->dccpop_feat, *val); | 448 | opt->dccpop_feat, *val); |
427 | 449 | ||
428 | dccp_pr_debug("feat %d type %d confirmed %d\n", | 450 | /* XXX check the return value of dccp_feat_update */ |
429 | feature, type, *val); | ||
430 | rc = 0; | ||
431 | break; | 451 | break; |
432 | } | 452 | } |
433 | 453 | ||
@@ -446,9 +466,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | |||
446 | inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); | 466 | inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); |
447 | } | 467 | } |
448 | 468 | ||
449 | if (rc) | 469 | if (!found) |
450 | dccp_pr_debug("feat %d type %d never requested\n", | 470 | dccp_pr_debug("%s(%d, ...) never requested\n", |
451 | feature, type); | 471 | dccp_feat_typename(type), feature); |
452 | return 0; | 472 | return 0; |
453 | } | 473 | } |
454 | 474 | ||
@@ -583,3 +603,45 @@ out: | |||
583 | } | 603 | } |
584 | 604 | ||
585 | EXPORT_SYMBOL_GPL(dccp_feat_init); | 605 | EXPORT_SYMBOL_GPL(dccp_feat_init); |
606 | |||
607 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
608 | const char *dccp_feat_typename(const u8 type) | ||
609 | { | ||
610 | switch(type) { | ||
611 | case DCCPO_CHANGE_L: return("ChangeL"); | ||
612 | case DCCPO_CONFIRM_L: return("ConfirmL"); | ||
613 | case DCCPO_CHANGE_R: return("ChangeR"); | ||
614 | case DCCPO_CONFIRM_R: return("ConfirmR"); | ||
615 | /* the following case must not appear in feature negotation */ | ||
616 | default: dccp_pr_debug("unknown type %d [BUG!]\n", type); | ||
617 | } | ||
618 | return NULL; | ||
619 | } | ||
620 | |||
621 | EXPORT_SYMBOL_GPL(dccp_feat_typename); | ||
622 | |||
623 | const char *dccp_feat_name(const u8 feat) | ||
624 | { | ||
625 | static const char *feature_names[] = { | ||
626 | [DCCPF_RESERVED] = "Reserved", | ||
627 | [DCCPF_CCID] = "CCID", | ||
628 | [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", | ||
629 | [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", | ||
630 | [DCCPF_ECN_INCAPABLE] = "ECN Incapable", | ||
631 | [DCCPF_ACK_RATIO] = "Ack Ratio", | ||
632 | [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", | ||
633 | [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", | ||
634 | [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", | ||
635 | [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", | ||
636 | }; | ||
637 | if (feat >= DCCPF_MIN_CCID_SPECIFIC) | ||
638 | return "CCID-specific"; | ||
639 | |||
640 | if (dccp_feat_is_reserved(feat)) | ||
641 | return feature_names[DCCPF_RESERVED]; | ||
642 | |||
643 | return feature_names[feat]; | ||
644 | } | ||
645 | |||
646 | EXPORT_SYMBOL_GPL(dccp_feat_name); | ||
647 | #endif /* CONFIG_IP_DCCP_DEBUG */ | ||
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index 6048373c7186..2c373ad7edcf 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -12,9 +12,46 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | #include "dccp.h" | ||
15 | 16 | ||
16 | struct sock; | 17 | static inline int dccp_feat_is_valid_length(u8 type, u8 feature, u8 len) |
17 | struct dccp_minisock; | 18 | { |
19 | /* sec. 6.1: Confirm has at least length 3, | ||
20 | * sec. 6.2: Change has at least length 4 */ | ||
21 | if (len < 3) | ||
22 | return 1; | ||
23 | if (len < 4 && (type == DCCPO_CHANGE_L || type == DCCPO_CHANGE_R)) | ||
24 | return 1; | ||
25 | /* XXX: add per-feature length validation (sec. 6.6.8) */ | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | static inline int dccp_feat_is_reserved(const u8 feat) | ||
30 | { | ||
31 | return (feat > DCCPF_DATA_CHECKSUM && | ||
32 | feat < DCCPF_MIN_CCID_SPECIFIC) || | ||
33 | feat == DCCPF_RESERVED; | ||
34 | } | ||
35 | |||
36 | /* feature negotiation knows only these four option types (RFC 4340, sec. 6) */ | ||
37 | static inline int dccp_feat_is_valid_type(const u8 optnum) | ||
38 | { | ||
39 | return optnum >= DCCPO_CHANGE_L && optnum <= DCCPO_CONFIRM_R; | ||
40 | |||
41 | } | ||
42 | |||
43 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
44 | extern const char *dccp_feat_typename(const u8 type); | ||
45 | extern const char *dccp_feat_name(const u8 feat); | ||
46 | |||
47 | static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val) | ||
48 | { | ||
49 | dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type), | ||
50 | dccp_feat_name(feat), feat, val); | ||
51 | } | ||
52 | #else | ||
53 | #define dccp_feat_debug(type, feat, val) | ||
54 | #endif /* CONFIG_IP_DCCP_DEBUG */ | ||
18 | 55 | ||
19 | extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, | 56 | extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, |
20 | u8 *val, u8 len, gfp_t gfp); | 57 | u8 *val, u8 len, gfp_t gfp); |
diff --git a/net/dccp/options.c b/net/dccp/options.c index 121e794fe454..2d0ef27f4ab9 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -465,8 +465,10 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, | |||
465 | 465 | ||
466 | if (len) | 466 | if (len) |
467 | memcpy(to, val, len); | 467 | memcpy(to, val, len); |
468 | dccp_pr_debug("option %d feat %d len %d\n", type, feat, len); | ||
469 | 468 | ||
469 | dccp_pr_debug("%s(%s (%d), ...), length %d\n", | ||
470 | dccp_feat_typename(type), | ||
471 | dccp_feat_name(feat), feat, len); | ||
470 | return 0; | 472 | return 0; |
471 | } | 473 | } |
472 | 474 | ||