aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:29 -0400
commitd2150b7bff3d397692cf0dc890f198d23564de5f (patch)
tree6916928ec289c46bca21c8a99640048e308fef3e /net
parent5a146b97d5e93db2df075c0d820f492bb996d0e3 (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>
Diffstat (limited to 'net')
-rw-r--r--net/dccp/feat.c100
-rw-r--r--net/dccp/feat.h2
-rw-r--r--net/dccp/options.c16
3 files changed, 101 insertions, 17 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 01b4da7007b..da3bbad9d50 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) */
103static 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 */
103static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) 110static 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
1095EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 1102EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
1096#endif /* (later) */
1097 1103
1098int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 1104int 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
1150EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); 1156EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
1157#endif /* (later) */
1151 1158
1152void dccp_feat_clean(struct dccp_minisock *dmsk) 1159void 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 */
1363static 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
1430confirmation_succeeded:
1431 entry->state = FEAT_STABLE;
1432 return 0;
1433
1434confirmation_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 ce97f3fe768..618bed935b3 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,
117extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); 117extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
118extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, 118extern 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);
120extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
121 u8 *val, u8 len);
122extern void dccp_feat_clean(struct dccp_minisock *dmsk); 120extern void dccp_feat_clean(struct dccp_minisock *dmsk);
123extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); 121extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
124extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); 122extern 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 fb8466ea467..3a9a22f0ac1 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 */