aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 283c7fb8c7dc..bc00c038e4a5 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -104,6 +104,13 @@ static int dccp_feat_default_value(u8 feat_num)
104 return idx < 0 ? 0 : dccp_feat_table[idx].default_value; 104 return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
105} 105}
106 106
107/* Test for "Req'd" feature (RFC 4340, 6.4) */
108static inline int dccp_feat_must_be_understood(u8 feat_num)
109{
110 return feat_num == DCCPF_CCID || feat_num == DCCPF_SHORT_SEQNOS ||
111 feat_num == DCCPF_SEQUENCE_WINDOW;
112}
113
107/* copy constructor, fval must not already contain allocated memory */ 114/* copy constructor, fval must not already contain allocated memory */
108static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) 115static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
109{ 116{
@@ -1099,7 +1106,6 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
1099} 1106}
1100 1107
1101EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 1108EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
1102#endif /* (later) */
1103 1109
1104int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 1110int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
1105 u8 *val, u8 len) 1111 u8 *val, u8 len)
@@ -1154,6 +1160,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
1154} 1160}
1155 1161
1156EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); 1162EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
1163#endif /* (later) */
1157 1164
1158void dccp_feat_clean(struct dccp_minisock *dmsk) 1165void dccp_feat_clean(struct dccp_minisock *dmsk)
1159{ 1166{
@@ -1350,6 +1357,93 @@ not_valid_or_not_known:
1350} 1357}
1351 1358
1352/** 1359/**
1360 * dccp_feat_confirm_recv - Process received Confirm options
1361 * @fn: feature-negotiation list to update
1362 * @is_mandatory: whether @opt was preceded by a Mandatory option
1363 * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R
1364 * @feat: one of %dccp_feature_numbers
1365 * @val: NN value or SP value/preference list
1366 * @len: length of @val in bytes
1367 * @server: whether this node is server (1) or client (0)
1368 */
1369static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
1370 u8 feat, u8 *val, u8 len, const bool server)
1371{
1372 u8 *plist, plen, type = dccp_feat_type(feat);
1373 const bool local = (opt == DCCPO_CONFIRM_R);
1374 struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
1375
1376 if (entry == NULL) { /* nothing queued: ignore or handle error */
1377 if (is_mandatory && type == FEAT_UNKNOWN)
1378 return DCCP_RESET_CODE_MANDATORY_ERROR;
1379
1380 if (!local && type == FEAT_NN) /* 6.3.2 */
1381 goto confirmation_failed;
1382 return 0;
1383 }
1384
1385 if (entry->state != FEAT_CHANGING) /* 6.6.2 */
1386 return 0;
1387
1388 if (len == 0) {
1389 if (dccp_feat_must_be_understood(feat)) /* 6.6.7 */
1390 goto confirmation_failed;
1391 /*
1392 * Empty Confirm during connection setup: this means reverting
1393 * to the `old' value, which in this case is the default. Since
1394 * we handle default values automatically when no other values
1395 * have been set, we revert to the old value by removing this
1396 * entry from the list.
1397 */
1398 dccp_feat_list_pop(entry);
1399 return 0;
1400 }
1401
1402 if (type == FEAT_NN) {
1403 if (len > sizeof(entry->val.nn))
1404 goto confirmation_failed;
1405
1406 if (entry->val.nn == dccp_decode_value_var(val, len))
1407 goto confirmation_succeeded;
1408
1409 DCCP_WARN("Bogus Confirm for non-existing value\n");
1410 goto confirmation_failed;
1411 }
1412
1413 /*
1414 * Parsing SP Confirms: the first element of @val is the preferred
1415 * SP value which the peer confirms, the remainder depends on @len.
1416 * Note that only the confirmed value need to be a valid SP value.
1417 */
1418 if (!dccp_feat_is_valid_sp_val(feat, *val))
1419 goto confirmation_failed;
1420
1421 if (len == 1) { /* peer didn't supply a preference list */
1422 plist = val;
1423 plen = len;
1424 } else { /* preferred value + preference list */
1425 plist = val + 1;
1426 plen = len - 1;
1427 }
1428
1429 /* Check whether the peer got the reconciliation right (6.6.8) */
1430 if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) {
1431 DCCP_WARN("Confirm selected the wrong value %u\n", *val);
1432 return DCCP_RESET_CODE_OPTION_ERROR;
1433 }
1434 entry->val.sp.vec[0] = *val;
1435
1436confirmation_succeeded:
1437 entry->state = FEAT_STABLE;
1438 return 0;
1439
1440confirmation_failed:
1441 DCCP_WARN("Confirmation failed\n");
1442 return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
1443 : DCCP_RESET_CODE_OPTION_ERROR;
1444}
1445
1446/**
1353 * dccp_feat_parse_options - Process Feature-Negotiation Options 1447 * dccp_feat_parse_options - Process Feature-Negotiation Options
1354 * @sk: for general use and used by the client during connection setup 1448 * @sk: for general use and used by the client during connection setup
1355 * @dreq: used by the server during connection setup 1449 * @dreq: used by the server during connection setup
@@ -1379,6 +1473,10 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
1379 case DCCPO_CHANGE_R: 1473 case DCCPO_CHANGE_R:
1380 return dccp_feat_change_recv(fn, mandatory, opt, feat, 1474 return dccp_feat_change_recv(fn, mandatory, opt, feat,
1381 val, len, server); 1475 val, len, server);
1476 case DCCPO_CONFIRM_R:
1477 case DCCPO_CONFIRM_L:
1478 return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
1479 val, len, server);
1382 } 1480 }
1383 } 1481 }
1384 return 0; /* ignore FN options in all other states */ 1482 return 0; /* ignore FN options in all other states */
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index 8dc4b42ef172..f749610ae383 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -118,8 +118,6 @@ extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
118extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); 118extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
119extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, 119extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
120 u8 mand, u8 opt, u8 feat, u8 *val, u8 len); 120 u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
121extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
122 u8 *val, u8 len);
123extern void dccp_feat_clean(struct dccp_minisock *dmsk); 121extern void dccp_feat_clean(struct dccp_minisock *dmsk);
124extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); 122extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
125extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); 123extern 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 2c444c199725..debb1008c7ad 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 */