diff options
Diffstat (limited to 'net/dccp/feat.c')
-rw-r--r-- | net/dccp/feat.c | 100 |
1 files changed, 99 insertions, 1 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) */ | ||
108 | static 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 */ |
108 | static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) | 115 | static 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 | ||
1101 | EXPORT_SYMBOL_GPL(dccp_feat_change_recv); | 1108 | EXPORT_SYMBOL_GPL(dccp_feat_change_recv); |
1102 | #endif /* (later) */ | ||
1103 | 1109 | ||
1104 | int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | 1110 | int 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 | ||
1156 | EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); | 1162 | EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); |
1163 | #endif /* (later) */ | ||
1157 | 1164 | ||
1158 | void dccp_feat_clean(struct dccp_minisock *dmsk) | 1165 | void 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 | */ | ||
1369 | static 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 | |||
1436 | confirmation_succeeded: | ||
1437 | entry->state = FEAT_STABLE; | ||
1438 | return 0; | ||
1439 | |||
1440 | confirmation_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 */ |