aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/feat.c
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2011-07-24 22:27:59 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2011-08-01 09:52:34 -0400
commit44e6fd9e67c1043aaeed381c10b74e73807b7f26 (patch)
treea49baef6849d68cb7775eee77a51f435fd20dc32 /net/dccp/feat.c
parentd6916f87ca5e566786f1a935a7cabba54774bbda (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.c116
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 */
355static 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) */
348static inline int dccp_feat_must_be_understood(u8 feat_num) 362static 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 */
1285static 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
1353fast_path_unknown:
1354 if (!mandatory)
1355 return dccp_push_empty_confirm(fn, feat, local);
1356
1357fast_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}