diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2011-07-24 22:27:59 -0400 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2011-08-01 09:52:34 -0400 |
commit | 44e6fd9e67c1043aaeed381c10b74e73807b7f26 (patch) | |
tree | a49baef6849d68cb7775eee77a51f435fd20dc32 /net/dccp/feat.c | |
parent | d6916f87ca5e566786f1a935a7cabba54774bbda (diff) |
dccp: support for exchanging of NN options in established state 2/2
This patch adds the receiver side and the (fast-path) activation part for
dynamic changes of non-negotiable (NN) parameters in (PART)OPEN state.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Samuel Jero <sj323707@ohio.edu>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.uk>
Diffstat (limited to 'net/dccp/feat.c')
-rw-r--r-- | net/dccp/feat.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 8bd28f244fef..ad6f9e2cac1a 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -344,6 +344,20 @@ static int __dccp_feat_activate(struct sock *sk, const int idx, | |||
344 | return dccp_feat_table[idx].activation_hdlr(sk, val, rx); | 344 | return dccp_feat_table[idx].activation_hdlr(sk, val, rx); |
345 | } | 345 | } |
346 | 346 | ||
347 | /** | ||
348 | * dccp_feat_activate - Activate feature value on socket | ||
349 | * @sk: fully connected DCCP socket (after handshake is complete) | ||
350 | * @feat_num: feature to activate, one of %dccp_feature_numbers | ||
351 | * @local: whether local (1) or remote (0) @feat_num is meant | ||
352 | * @fval: the value (SP or NN) to activate, or NULL to use the default value | ||
353 | * For general use this function is preferable over __dccp_feat_activate(). | ||
354 | */ | ||
355 | static int dccp_feat_activate(struct sock *sk, u8 feat_num, bool local, | ||
356 | dccp_feat_val const *fval) | ||
357 | { | ||
358 | return __dccp_feat_activate(sk, dccp_feat_index(feat_num), local, fval); | ||
359 | } | ||
360 | |||
347 | /* Test for "Req'd" feature (RFC 4340, 6.4) */ | 361 | /* Test for "Req'd" feature (RFC 4340, 6.4) */ |
348 | static inline int dccp_feat_must_be_understood(u8 feat_num) | 362 | static inline int dccp_feat_must_be_understood(u8 feat_num) |
349 | { | 363 | { |
@@ -1252,6 +1266,100 @@ confirmation_failed: | |||
1252 | } | 1266 | } |
1253 | 1267 | ||
1254 | /** | 1268 | /** |
1269 | * dccp_feat_handle_nn_established - Fast-path reception of NN options | ||
1270 | * @sk: socket of an established DCCP connection | ||
1271 | * @mandatory: whether @opt was preceded by a Mandatory option | ||
1272 | * @opt: %DCCPO_CHANGE_L | %DCCPO_CONFIRM_R (NN only) | ||
1273 | * @feat: NN number, one of %dccp_feature_numbers | ||
1274 | * @val: NN value | ||
1275 | * @len: length of @val in bytes | ||
1276 | * This function combines the functionality of change_recv/confirm_recv, with | ||
1277 | * the following differences (reset codes are the same): | ||
1278 | * - cleanup after receiving the Confirm; | ||
1279 | * - values are directly activated after successful parsing; | ||
1280 | * - deliberately restricted to NN features. | ||
1281 | * The restriction to NN features is essential since SP features can have non- | ||
1282 | * predictable outcomes (depending on the remote configuration), and are inter- | ||
1283 | * dependent (CCIDs for instance cause further dependencies). | ||
1284 | */ | ||
1285 | static u8 dccp_feat_handle_nn_established(struct sock *sk, u8 mandatory, u8 opt, | ||
1286 | u8 feat, u8 *val, u8 len) | ||
1287 | { | ||
1288 | struct list_head *fn = &dccp_sk(sk)->dccps_featneg; | ||
1289 | const bool local = (opt == DCCPO_CONFIRM_R); | ||
1290 | struct dccp_feat_entry *entry; | ||
1291 | u8 type = dccp_feat_type(feat); | ||
1292 | dccp_feat_val fval; | ||
1293 | |||
1294 | dccp_feat_print_opt(opt, feat, val, len, mandatory); | ||
1295 | |||
1296 | /* Ignore non-mandatory unknown and non-NN features */ | ||
1297 | if (type == FEAT_UNKNOWN) { | ||
1298 | if (local && !mandatory) | ||
1299 | return 0; | ||
1300 | goto fast_path_unknown; | ||
1301 | } else if (type != FEAT_NN) { | ||
1302 | return 0; | ||
1303 | } | ||
1304 | |||
1305 | /* | ||
1306 | * We don't accept empty Confirms, since in fast-path feature | ||
1307 | * negotiation the values are enabled immediately after sending | ||
1308 | * the Change option. | ||
1309 | * Empty Changes on the other hand are invalid (RFC 4340, 6.1). | ||
1310 | */ | ||
1311 | if (len == 0 || len > sizeof(fval.nn)) | ||
1312 | goto fast_path_unknown; | ||
1313 | |||
1314 | if (opt == DCCPO_CHANGE_L) { | ||
1315 | fval.nn = dccp_decode_value_var(val, len); | ||
1316 | if (!dccp_feat_is_valid_nn_val(feat, fval.nn)) | ||
1317 | goto fast_path_unknown; | ||
1318 | |||
1319 | if (dccp_feat_push_confirm(fn, feat, local, &fval) || | ||
1320 | dccp_feat_activate(sk, feat, local, &fval)) | ||
1321 | return DCCP_RESET_CODE_TOO_BUSY; | ||
1322 | |||
1323 | /* set the `Ack Pending' flag to piggyback a Confirm */ | ||
1324 | inet_csk_schedule_ack(sk); | ||
1325 | |||
1326 | } else if (opt == DCCPO_CONFIRM_R) { | ||
1327 | entry = dccp_feat_list_lookup(fn, feat, local); | ||
1328 | if (entry == NULL || entry->state != FEAT_CHANGING) | ||
1329 | return 0; | ||
1330 | |||
1331 | fval.nn = dccp_decode_value_var(val, len); | ||
1332 | /* | ||
1333 | * Just ignore a value that doesn't match our current value. | ||
1334 | * If the option changes twice within two RTTs, then at least | ||
1335 | * one CONFIRM will be received for the old value after a | ||
1336 | * new CHANGE was sent. | ||
1337 | */ | ||
1338 | if (fval.nn != entry->val.nn) | ||
1339 | return 0; | ||
1340 | |||
1341 | /* Only activate after receiving the Confirm option (6.6.1). */ | ||
1342 | dccp_feat_activate(sk, feat, local, &fval); | ||
1343 | |||
1344 | /* It has been confirmed - so remove the entry */ | ||
1345 | dccp_feat_list_pop(entry); | ||
1346 | |||
1347 | } else { | ||
1348 | DCCP_WARN("Received illegal option %u\n", opt); | ||
1349 | goto fast_path_failed; | ||
1350 | } | ||
1351 | return 0; | ||
1352 | |||
1353 | fast_path_unknown: | ||
1354 | if (!mandatory) | ||
1355 | return dccp_push_empty_confirm(fn, feat, local); | ||
1356 | |||
1357 | fast_path_failed: | ||
1358 | return mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR | ||
1359 | : DCCP_RESET_CODE_OPTION_ERROR; | ||
1360 | } | ||
1361 | |||
1362 | /** | ||
1255 | * dccp_feat_parse_options - Process Feature-Negotiation Options | 1363 | * dccp_feat_parse_options - Process Feature-Negotiation Options |
1256 | * @sk: for general use and used by the client during connection setup | 1364 | * @sk: for general use and used by the client during connection setup |
1257 | * @dreq: used by the server during connection setup | 1365 | * @dreq: used by the server during connection setup |
@@ -1286,6 +1394,14 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
1286 | return dccp_feat_confirm_recv(fn, mandatory, opt, feat, | 1394 | return dccp_feat_confirm_recv(fn, mandatory, opt, feat, |
1287 | val, len, server); | 1395 | val, len, server); |
1288 | } | 1396 | } |
1397 | break; | ||
1398 | /* | ||
1399 | * Support for exchanging NN options on an established connection. | ||
1400 | */ | ||
1401 | case DCCP_OPEN: | ||
1402 | case DCCP_PARTOPEN: | ||
1403 | return dccp_feat_handle_nn_established(sk, mandatory, opt, feat, | ||
1404 | val, len); | ||
1289 | } | 1405 | } |
1290 | return 0; /* ignore FN options in all other states */ | 1406 | return 0; /* ignore FN options in all other states */ |
1291 | } | 1407 | } |