]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
dccp: Support for exchanging of NN options in established state
authorGerrit Renker <gerrit@erg.abdn.ac.uk>
Thu, 4 Sep 2008 05:30:19 +0000 (07:30 +0200)
committerGerrit Renker <gerrit@erg.abdn.ac.uk>
Thu, 4 Sep 2008 05:45:32 +0000 (07:45 +0200)
This patch provides support for the reception of NN options in (PART)OPEN state.

It is a combination of change_recv() and confirm_recv(), specifically geared
towards receiving the `fast-path' NN options.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
net/dccp/feat.c

index 5be8b85ac74bbfc0a3a24bda1e49af1f85f18016..c847c80d1b97e1f9865c4a1e3a54f4869b35dc99 100644 (file)
@@ -1246,6 +1246,93 @@ confirmation_failed:
                            : DCCP_RESET_CODE_OPTION_ERROR;
 }
 
+/**
+ * dccp_feat_handle_nn_established  -  Fast-path reception of NN options
+ * @sk:                socket of an established DCCP connection
+ * @mandatory: whether @opt was preceded by a Mandatory option
+ * @opt:       %DCCPO_CHANGE_L | %DCCPO_CONFIRM_R (NN only)
+ * @feat:      NN number, one of %dccp_feature_numbers
+ * @val:       NN value
+ * @len:       length of @val in bytes
+ * This function combines the functionality of change_recv/confirm_recv, with
+ * the following differences (reset codes are the same):
+ *    - cleanup after receiving the Confirm;
+ *    - values are directly activated after successful parsing;
+ *    - deliberately restricted to NN features.
+ * The restriction to NN features is essential since SP features can have non-
+ * predictable outcomes (depending on the remote configuration), and are inter-
+ * dependent (CCIDs for instance cause further dependencies).
+ */
+static u8 dccp_feat_handle_nn_established(struct sock *sk, u8 mandatory, u8 opt,
+                                         u8 feat, u8 *val, u8 len)
+{
+       struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
+       const bool local = (opt == DCCPO_CONFIRM_R);
+       struct dccp_feat_entry *entry;
+       u8 type = dccp_feat_type(feat);
+       dccp_feat_val fval;
+
+       dccp_feat_print_opt(opt, feat, val, len, mandatory);
+
+       /* Ignore non-mandatory unknown and non-NN features */
+       if (type == FEAT_UNKNOWN) {
+               if (local && !mandatory)
+                       return 0;
+               goto fast_path_unknown;
+       } else if (type != FEAT_NN) {
+               return 0;
+       }
+
+       /*
+        * We don't accept empty Confirms, since in fast-path feature
+        * negotiation the values are enabled immediately after sending
+        * the Change option.
+        * Empty Changes on the other hand are invalid (RFC 4340, 6.1).
+        */
+       if (len == 0 || len > sizeof(fval.nn))
+               goto fast_path_unknown;
+
+       if (opt == DCCPO_CHANGE_L) {
+               fval.nn = dccp_decode_value_var(val, len);
+               if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
+                       goto fast_path_unknown;
+
+               if (dccp_feat_push_confirm(fn, feat, local, &fval) ||
+                   dccp_feat_activate(sk, feat, local, &fval))
+                       return DCCP_RESET_CODE_TOO_BUSY;
+
+               /* set the `Ack Pending' flag to piggyback a Confirm */
+               inet_csk_schedule_ack(sk);
+
+       } else if (opt == DCCPO_CONFIRM_R) {
+               entry = dccp_feat_list_lookup(fn, feat, local);
+               if (entry == NULL || entry->state != FEAT_CHANGING)
+                       return 0;
+
+               fval.nn = dccp_decode_value_var(val, len);
+               if (fval.nn != entry->val.nn) {
+                       DCCP_WARN("Bogus Confirm for non-existing value\n");
+                       goto fast_path_failed;
+               }
+
+               /* It has been confirmed - so remove the entry */
+               dccp_feat_list_pop(entry);
+
+       } else {
+               DCCP_WARN("Received illegal option %u\n", opt);
+               goto fast_path_failed;
+       }
+       return 0;
+
+fast_path_unknown:
+       if (!mandatory)
+               return dccp_push_empty_confirm(fn, feat, local);
+
+fast_path_failed:
+       return mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+                        : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
 /**
  * dccp_feat_parse_options  -  Process Feature-Negotiation Options
  * @sk: for general use and used by the client during connection setup
@@ -1281,6 +1368,15 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                        return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
                                                      val, len, server);
                }
+               break;
+       /*
+        *      Support for exchanging NN options on an established connection
+        *      This is currently restricted to Ack Ratio (RFC 4341, 6.1.2)
+        */
+       case DCCP_OPEN:
+       case DCCP_PARTOPEN:
+               return dccp_feat_handle_nn_established(sk, mandatory, opt, feat,
+                                                      val, len);
        }
        return 0;       /* ignore FN options in all other states */
 }