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:29 -0400 |
commit | d2150b7bff3d397692cf0dc890f198d23564de5f (patch) | |
tree | 6916928ec289c46bca21c8a99640048e308fef3e | |
parent | 5a146b97d5e93db2df075c0d820f492bb996d0e3 (diff) |
dccp: Processing Confirm options
Analogous to the previous patch, this adds code to interpret incoming Confirm
feature-negotiation options. Both functions operate on the feature-negotiation
list of either the request_sock (server) or the dccp_sock (client).
Thanks to Wei Yongjun for pointing out that it is overly restrictive to check
the entire list of confirmed SP values.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
-rw-r--r-- | net/dccp/feat.c | 100 | ||||
-rw-r--r-- | net/dccp/feat.h | 2 | ||||
-rw-r--r-- | net/dccp/options.c | 16 |
3 files changed, 101 insertions, 17 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 01b4da7007b2..da3bbad9d50d 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -99,6 +99,13 @@ static int dccp_feat_default_value(u8 feat_num) | |||
99 | return idx < 0 ? : dccp_feat_table[idx].default_value; | 99 | return idx < 0 ? : dccp_feat_table[idx].default_value; |
100 | } | 100 | } |
101 | 101 | ||
102 | /* Test for "Req'd" feature (RFC 4340, 6.4) */ | ||
103 | static inline int dccp_feat_must_be_understood(u8 feat_num) | ||
104 | { | ||
105 | return feat_num == DCCPF_CCID || feat_num == DCCPF_SHORT_SEQNOS || | ||
106 | feat_num == DCCPF_SEQUENCE_WINDOW; | ||
107 | } | ||
108 | |||
102 | /* copy constructor, fval must not already contain allocated memory */ | 109 | /* copy constructor, fval must not already contain allocated memory */ |
103 | static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) | 110 | static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) |
104 | { | 111 | { |
@@ -1093,7 +1100,6 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | |||
1093 | } | 1100 | } |
1094 | 1101 | ||
1095 | EXPORT_SYMBOL_GPL(dccp_feat_change_recv); | 1102 | EXPORT_SYMBOL_GPL(dccp_feat_change_recv); |
1096 | #endif /* (later) */ | ||
1097 | 1103 | ||
1098 | int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | 1104 | int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, |
1099 | u8 *val, u8 len) | 1105 | u8 *val, u8 len) |
@@ -1148,6 +1154,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | |||
1148 | } | 1154 | } |
1149 | 1155 | ||
1150 | EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); | 1156 | EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); |
1157 | #endif /* (later) */ | ||
1151 | 1158 | ||
1152 | void dccp_feat_clean(struct dccp_minisock *dmsk) | 1159 | void dccp_feat_clean(struct dccp_minisock *dmsk) |
1153 | { | 1160 | { |
@@ -1344,6 +1351,93 @@ not_valid_or_not_known: | |||
1344 | } | 1351 | } |
1345 | 1352 | ||
1346 | /** | 1353 | /** |
1354 | * dccp_feat_confirm_recv - Process received Confirm options | ||
1355 | * @fn: feature-negotiation list to update | ||
1356 | * @is_mandatory: whether @opt was preceded by a Mandatory option | ||
1357 | * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R | ||
1358 | * @feat: one of %dccp_feature_numbers | ||
1359 | * @val: NN value or SP value/preference list | ||
1360 | * @len: length of @val in bytes | ||
1361 | * @server: whether this node is server (1) or client (0) | ||
1362 | */ | ||
1363 | static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt, | ||
1364 | u8 feat, u8 *val, u8 len, const bool server) | ||
1365 | { | ||
1366 | u8 *plist, plen, type = dccp_feat_type(feat); | ||
1367 | const bool local = (opt == DCCPO_CONFIRM_R); | ||
1368 | struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local); | ||
1369 | |||
1370 | if (entry == NULL) { /* nothing queued: ignore or handle error */ | ||
1371 | if (is_mandatory && type == FEAT_UNKNOWN) | ||
1372 | return DCCP_RESET_CODE_MANDATORY_ERROR; | ||
1373 | |||
1374 | if (!local && type == FEAT_NN) /* 6.3.2 */ | ||
1375 | goto confirmation_failed; | ||
1376 | return 0; | ||
1377 | } | ||
1378 | |||
1379 | if (entry->state != FEAT_CHANGING) /* 6.6.2 */ | ||
1380 | return 0; | ||
1381 | |||
1382 | if (len == 0) { | ||
1383 | if (dccp_feat_must_be_understood(feat)) /* 6.6.7 */ | ||
1384 | goto confirmation_failed; | ||
1385 | /* | ||
1386 | * Empty Confirm during connection setup: this means reverting | ||
1387 | * to the `old' value, which in this case is the default. Since | ||
1388 | * we handle default values automatically when no other values | ||
1389 | * have been set, we revert to the old value by removing this | ||
1390 | * entry from the list. | ||
1391 | */ | ||
1392 | dccp_feat_list_pop(entry); | ||
1393 | return 0; | ||
1394 | } | ||
1395 | |||
1396 | if (type == FEAT_NN) { | ||
1397 | if (len > sizeof(entry->val.nn)) | ||
1398 | goto confirmation_failed; | ||
1399 | |||
1400 | if (entry->val.nn == dccp_decode_value_var(val, len)) | ||
1401 | goto confirmation_succeeded; | ||
1402 | |||
1403 | DCCP_WARN("Bogus Confirm for non-existing value\n"); | ||
1404 | goto confirmation_failed; | ||
1405 | } | ||
1406 | |||
1407 | /* | ||
1408 | * Parsing SP Confirms: the first element of @val is the preferred | ||
1409 | * SP value which the peer confirms, the remainder depends on @len. | ||
1410 | * Note that only the confirmed value need to be a valid SP value. | ||
1411 | */ | ||
1412 | if (!dccp_feat_is_valid_sp_val(feat, *val)) | ||
1413 | goto confirmation_failed; | ||
1414 | |||
1415 | if (len == 1) { /* peer didn't supply a preference list */ | ||
1416 | plist = val; | ||
1417 | plen = len; | ||
1418 | } else { /* preferred value + preference list */ | ||
1419 | plist = val + 1; | ||
1420 | plen = len - 1; | ||
1421 | } | ||
1422 | |||
1423 | /* Check whether the peer got the reconciliation right (6.6.8) */ | ||
1424 | if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) { | ||
1425 | DCCP_WARN("Confirm selected the wrong value %u\n", *val); | ||
1426 | return DCCP_RESET_CODE_OPTION_ERROR; | ||
1427 | } | ||
1428 | entry->val.sp.vec[0] = *val; | ||
1429 | |||
1430 | confirmation_succeeded: | ||
1431 | entry->state = FEAT_STABLE; | ||
1432 | return 0; | ||
1433 | |||
1434 | confirmation_failed: | ||
1435 | DCCP_WARN("Confirmation failed\n"); | ||
1436 | return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR | ||
1437 | : DCCP_RESET_CODE_OPTION_ERROR; | ||
1438 | } | ||
1439 | |||
1440 | /** | ||
1347 | * dccp_feat_parse_options - Process Feature-Negotiation Options | 1441 | * dccp_feat_parse_options - Process Feature-Negotiation Options |
1348 | * @sk: for general use and used by the client during connection setup | 1442 | * @sk: for general use and used by the client during connection setup |
1349 | * @dreq: used by the server during connection setup | 1443 | * @dreq: used by the server during connection setup |
@@ -1373,6 +1467,10 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
1373 | case DCCPO_CHANGE_R: | 1467 | case DCCPO_CHANGE_R: |
1374 | return dccp_feat_change_recv(fn, mandatory, opt, feat, | 1468 | return dccp_feat_change_recv(fn, mandatory, opt, feat, |
1375 | val, len, server); | 1469 | val, len, server); |
1470 | case DCCPO_CONFIRM_R: | ||
1471 | case DCCPO_CONFIRM_L: | ||
1472 | return dccp_feat_confirm_recv(fn, mandatory, opt, feat, | ||
1473 | val, len, server); | ||
1376 | } | 1474 | } |
1377 | } | 1475 | } |
1378 | return 0; /* ignore FN options in all other states */ | 1476 | return 0; /* ignore FN options in all other states */ |
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index ce97f3fe7687..618bed935b33 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -117,8 +117,6 @@ extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, | |||
117 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); | 117 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); |
118 | extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, | 118 | extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, |
119 | u8 mand, u8 opt, u8 feat, u8 *val, u8 len); | 119 | u8 mand, u8 opt, u8 feat, u8 *val, u8 len); |
120 | extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | ||
121 | u8 *val, u8 len); | ||
122 | extern void dccp_feat_clean(struct dccp_minisock *dmsk); | 120 | extern void dccp_feat_clean(struct dccp_minisock *dmsk); |
123 | extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); | 121 | extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); |
124 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); | 122 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); |
diff --git a/net/dccp/options.c b/net/dccp/options.c index fb8466ea467a..3a9a22f0ac1a 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -134,26 +134,14 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
134 | dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk), | 134 | dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk), |
135 | (unsigned long long)opt_recv->dccpor_ndp); | 135 | (unsigned long long)opt_recv->dccpor_ndp); |
136 | break; | 136 | break; |
137 | case DCCPO_CHANGE_L: | 137 | case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R: |
138 | case DCCPO_CHANGE_R: | 138 | if (pkt_type == DCCP_PKT_DATA) /* RFC 4340, 6 */ |
139 | if (pkt_type == DCCP_PKT_DATA) | ||
140 | break; | 139 | break; |
141 | rc = dccp_feat_parse_options(sk, dreq, mandatory, opt, | 140 | rc = dccp_feat_parse_options(sk, dreq, mandatory, opt, |
142 | *value, value + 1, len - 1); | 141 | *value, value + 1, len - 1); |
143 | if (rc) | 142 | if (rc) |
144 | goto out_featneg_failed; | 143 | goto out_featneg_failed; |
145 | break; | 144 | break; |
146 | case DCCPO_CONFIRM_L: | ||
147 | /* fall through */ | ||
148 | case DCCPO_CONFIRM_R: | ||
149 | if (pkt_type == DCCP_PKT_DATA) | ||
150 | break; | ||
151 | if (len < 2) /* FIXME this disallows empty confirm */ | ||
152 | goto out_invalid_option; | ||
153 | if (dccp_feat_confirm_recv(sk, opt, *value, | ||
154 | value + 1, len - 1)) | ||
155 | goto out_invalid_option; | ||
156 | break; | ||
157 | case DCCPO_ACK_VECTOR_0: | 145 | case DCCPO_ACK_VECTOR_0: |
158 | case DCCPO_ACK_VECTOR_1: | 146 | case DCCPO_ACK_VECTOR_1: |
159 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | 147 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ |