EXPORT_SYMBOL_GPL(dccp_feat_change);
 
+/*
+ *     Tracking features whose value depend on the choice of CCID
+ *
+ * This is designed with an extension in mind so that a list walk could be done
+ * before activating any features. However, the existing framework was found to
+ * work satisfactorily up until now, the automatic verification is left open.
+ * When adding new CCIDs, add a corresponding dependency table here.
+ */
+static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
+{
+       static const struct ccid_dependency ccid2_dependencies[2][2] = {
+               /*
+                * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
+                * feature and Send Ack Vector is an RX feature, `is_local'
+                * needs to be reversed.
+                */
+               {       /* Dependencies of the receiver-side (remote) CCID2 */
+                       {
+                               .dependent_feat = DCCPF_SEND_ACK_VECTOR,
+                               .is_local       = true,
+                               .is_mandatory   = true,
+                               .val            = 1
+                       },
+                       { 0, 0, 0, 0 }
+               },
+               {       /* Dependencies of the sender-side (local) CCID2 */
+                       {
+                               .dependent_feat = DCCPF_SEND_ACK_VECTOR,
+                               .is_local       = false,
+                               .is_mandatory   = true,
+                               .val            = 1
+                       },
+                       { 0, 0, 0, 0 }
+               }
+       };
+       static const struct ccid_dependency ccid3_dependencies[2][5] = {
+               {       /*
+                        * Dependencies of the receiver-side CCID3
+                        */
+                       {       /* locally disable Ack Vectors */
+                               .dependent_feat = DCCPF_SEND_ACK_VECTOR,
+                               .is_local       = true,
+                               .is_mandatory   = false,
+                               .val            = 0
+                       },
+                       {       /* see below why Send Loss Event Rate is on */
+                               .dependent_feat = DCCPF_SEND_LEV_RATE,
+                               .is_local       = true,
+                               .is_mandatory   = true,
+                               .val            = 1
+                       },
+                       {       /* NDP Count is needed as per RFC 4342, 6.1.1 */
+                               .dependent_feat = DCCPF_SEND_NDP_COUNT,
+                               .is_local       = false,
+                               .is_mandatory   = true,
+                               .val            = 1
+                       },
+                       { 0, 0, 0, 0 },
+               },
+               {       /*
+                        * CCID3 at the TX side: we request that the HC-receiver
+                        * will not send Ack Vectors (they will be ignored, so
+                        * Mandatory is not set); we enable Send Loss Event Rate
+                        * (Mandatory since the implementation does not support
+                        * the Loss Intervals option of RFC 4342, 8.6).
+                        * The last two options are for peer's information only.
+                       */
+                       {
+                               .dependent_feat = DCCPF_SEND_ACK_VECTOR,
+                               .is_local       = false,
+                               .is_mandatory   = false,
+                               .val            = 0
+                       },
+                       {
+                               .dependent_feat = DCCPF_SEND_LEV_RATE,
+                               .is_local       = false,
+                               .is_mandatory   = true,
+                               .val            = 1
+                       },
+                       {       /* this CCID does not support Ack Ratio */
+                               .dependent_feat = DCCPF_ACK_RATIO,
+                               .is_local       = true,
+                               .is_mandatory   = false,
+                               .val            = 0
+                       },
+                       {       /* tell receiver we are sending NDP counts */
+                               .dependent_feat = DCCPF_SEND_NDP_COUNT,
+                               .is_local       = true,
+                               .is_mandatory   = false,
+                               .val            = 1
+                       },
+                       { 0, 0, 0, 0 }
+               }
+       };
+       switch (ccid) {
+       case DCCPC_CCID2:
+               return ccid2_dependencies[is_local];
+       case DCCPC_CCID3:
+               return ccid3_dependencies[is_local];
+       default:
+               return NULL;
+       }
+}
+
+/**
+ * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
+ * @fn: feature-negotiation list to update
+ * @id: CCID number to track
+ * @is_local: whether TX CCID (1) or RX CCID (0) is meant
+ * This function needs to be called after registering all other features.
+ */
+static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
+{
+       const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
+       int i, rc = (table == NULL);
+
+       for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
+               if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
+                       rc = __feat_register_sp(fn, table[i].dependent_feat,
+                                                   table[i].is_local,
+                                                   table[i].is_mandatory,
+                                                   &table[i].val, 1);
+               else
+                       rc = __feat_register_nn(fn, table[i].dependent_feat,
+                                                   table[i].is_mandatory,
+                                                   table[i].val);
+       return rc;
+}
+
+/**
+ * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
+ * @dp: client or listening socket (settings will be inherited)
+ * This is called after all registrations (socket initialisation, sysctls, and
+ * sockopt calls), and before sending the first packet containing Change options
+ * (ie. client-Request or server-Response), to ensure internal consistency.
+ */
+int dccp_feat_finalise_settings(struct dccp_sock *dp)
+{
+       struct list_head *fn = &dp->dccps_featneg;
+       struct dccp_feat_entry *entry;
+       int i = 2, ccids[2] = { -1, -1 };
+
+       /*
+        * Propagating CCIDs:
+        * 1) not useful to propagate CCID settings if this host advertises more
+        *    than one CCID: the choice of CCID  may still change - if this is
+        *    the client, or if this is the server and the client sends
+        *    singleton CCID values.
+        * 2) since is that propagate_ccid changes the list, we defer changing
+        *    the sorted list until after the traversal.
+        */
+       list_for_each_entry(entry, fn, node)
+               if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
+                       ccids[entry->is_local] = entry->val.sp.vec[0];
+       while (i--)
+               if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
+                       return -1;
+       return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
        struct dccp_sock *dp = dccp_sk(sk);