18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  net/dccp/feat.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
88c2ecf20Sopenharmony_ci *  Rewrote from scratch, some bits from earlier code by
98c2ecf20Sopenharmony_ci *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  ASSUMPTIONS
128c2ecf20Sopenharmony_ci *  -----------
138c2ecf20Sopenharmony_ci *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
148c2ecf20Sopenharmony_ci *    changes of parameters of an established connection are not supported.
158c2ecf20Sopenharmony_ci *  o Changing non-negotiable (NN) values is supported in state OPEN/PARTOPEN.
168c2ecf20Sopenharmony_ci *  o All currently known SP features have 1-byte quantities. If in the future
178c2ecf20Sopenharmony_ci *    extensions of RFCs 4340..42 define features with item lengths larger than
188c2ecf20Sopenharmony_ci *    one byte, a feature-specific extension of the code will be required.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include "ccid.h"
238c2ecf20Sopenharmony_ci#include "feat.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
268c2ecf20Sopenharmony_ciunsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
278c2ecf20Sopenharmony_ciint		sysctl_dccp_rx_ccid	    __read_mostly = 2,
288c2ecf20Sopenharmony_ci		sysctl_dccp_tx_ccid	    __read_mostly = 2;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * Feature activation handlers.
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * These all use an u64 argument, to provide enough room for NN/SP features. At
348c2ecf20Sopenharmony_ci * this stage the negotiated values have been checked to be within their range.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_cistatic int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct dccp_sock *dp = dccp_sk(sk);
398c2ecf20Sopenharmony_ci	struct ccid *new_ccid = ccid_new(ccid, sk, rx);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (new_ccid == NULL)
428c2ecf20Sopenharmony_ci		return -ENOMEM;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (rx) {
458c2ecf20Sopenharmony_ci		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
468c2ecf20Sopenharmony_ci		dp->dccps_hc_rx_ccid = new_ccid;
478c2ecf20Sopenharmony_ci	} else {
488c2ecf20Sopenharmony_ci		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
498c2ecf20Sopenharmony_ci		dp->dccps_hc_tx_ccid = new_ccid;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci	return 0;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct dccp_sock *dp = dccp_sk(sk);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (rx) {
598c2ecf20Sopenharmony_ci		dp->dccps_r_seq_win = seq_win;
608c2ecf20Sopenharmony_ci		/* propagate changes to update SWL/SWH */
618c2ecf20Sopenharmony_ci		dccp_update_gsr(sk, dp->dccps_gsr);
628c2ecf20Sopenharmony_ci	} else {
638c2ecf20Sopenharmony_ci		dp->dccps_l_seq_win = seq_win;
648c2ecf20Sopenharmony_ci		/* propagate changes to update AWL */
658c2ecf20Sopenharmony_ci		dccp_update_gss(sk, dp->dccps_gss);
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci	return 0;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	if (rx)
738c2ecf20Sopenharmony_ci		dccp_sk(sk)->dccps_r_ack_ratio = ratio;
748c2ecf20Sopenharmony_ci	else
758c2ecf20Sopenharmony_ci		dccp_sk(sk)->dccps_l_ack_ratio = ratio;
768c2ecf20Sopenharmony_ci	return 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	struct dccp_sock *dp = dccp_sk(sk);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (rx) {
848c2ecf20Sopenharmony_ci		if (enable && dp->dccps_hc_rx_ackvec == NULL) {
858c2ecf20Sopenharmony_ci			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
868c2ecf20Sopenharmony_ci			if (dp->dccps_hc_rx_ackvec == NULL)
878c2ecf20Sopenharmony_ci				return -ENOMEM;
888c2ecf20Sopenharmony_ci		} else if (!enable) {
898c2ecf20Sopenharmony_ci			dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
908c2ecf20Sopenharmony_ci			dp->dccps_hc_rx_ackvec = NULL;
918c2ecf20Sopenharmony_ci		}
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci	return 0;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	if (!rx)
998c2ecf20Sopenharmony_ci		dccp_sk(sk)->dccps_send_ndp_count = (enable > 0);
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/*
1048c2ecf20Sopenharmony_ci * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
1058c2ecf20Sopenharmony_ci * `rx' holds when the sending peer informs about his partial coverage via a
1068c2ecf20Sopenharmony_ci * ChangeR() option. In the other case, we are the sender and the receiver
1078c2ecf20Sopenharmony_ci * announces its coverage via ChangeL() options. The policy here is to honour
1088c2ecf20Sopenharmony_ci * such communication by enabling the corresponding partial coverage - but only
1098c2ecf20Sopenharmony_ci * if it has not been set manually before; the warning here means that all
1108c2ecf20Sopenharmony_ci * packets will be dropped.
1118c2ecf20Sopenharmony_ci */
1128c2ecf20Sopenharmony_cistatic int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct dccp_sock *dp = dccp_sk(sk);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (rx)
1178c2ecf20Sopenharmony_ci		dp->dccps_pcrlen = cscov;
1188c2ecf20Sopenharmony_ci	else {
1198c2ecf20Sopenharmony_ci		if (dp->dccps_pcslen == 0)
1208c2ecf20Sopenharmony_ci			dp->dccps_pcslen = cscov;
1218c2ecf20Sopenharmony_ci		else if (cscov > dp->dccps_pcslen)
1228c2ecf20Sopenharmony_ci			DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
1238c2ecf20Sopenharmony_ci				  dp->dccps_pcslen, (u8)cscov);
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci	return 0;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic const struct {
1298c2ecf20Sopenharmony_ci	u8			feat_num;		/* DCCPF_xxx */
1308c2ecf20Sopenharmony_ci	enum dccp_feat_type	rxtx;			/* RX or TX  */
1318c2ecf20Sopenharmony_ci	enum dccp_feat_type	reconciliation;		/* SP or NN  */
1328c2ecf20Sopenharmony_ci	u8			default_value;		/* as in 6.4 */
1338c2ecf20Sopenharmony_ci	int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
1348c2ecf20Sopenharmony_ci/*
1358c2ecf20Sopenharmony_ci *    Lookup table for location and type of features (from RFC 4340/4342)
1368c2ecf20Sopenharmony_ci *  +--------------------------+----+-----+----+----+---------+-----------+
1378c2ecf20Sopenharmony_ci *  | Feature                  | Location | Reconc. | Initial |  Section  |
1388c2ecf20Sopenharmony_ci *  |                          | RX | TX  | SP | NN |  Value  | Reference |
1398c2ecf20Sopenharmony_ci *  +--------------------------+----+-----+----+----+---------+-----------+
1408c2ecf20Sopenharmony_ci *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
1418c2ecf20Sopenharmony_ci *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
1428c2ecf20Sopenharmony_ci *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
1438c2ecf20Sopenharmony_ci *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
1448c2ecf20Sopenharmony_ci *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
1458c2ecf20Sopenharmony_ci *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
1468c2ecf20Sopenharmony_ci *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
1478c2ecf20Sopenharmony_ci *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
1488c2ecf20Sopenharmony_ci *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
1498c2ecf20Sopenharmony_ci *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
1508c2ecf20Sopenharmony_ci *  +--------------------------+----+-----+----+----+---------+-----------+
1518c2ecf20Sopenharmony_ci */
1528c2ecf20Sopenharmony_ci} dccp_feat_table[] = {
1538c2ecf20Sopenharmony_ci	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2,   dccp_hdlr_ccid     },
1548c2ecf20Sopenharmony_ci	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0,   NULL },
1558c2ecf20Sopenharmony_ci	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win  },
1568c2ecf20Sopenharmony_ci	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
1578c2ecf20Sopenharmony_ci	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2,   dccp_hdlr_ack_ratio},
1588c2ecf20Sopenharmony_ci	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_ackvec   },
1598c2ecf20Sopenharmony_ci	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0,   dccp_hdlr_ndp      },
1608c2ecf20Sopenharmony_ci	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_min_cscov},
1618c2ecf20Sopenharmony_ci	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
1628c2ecf20Sopenharmony_ci	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
1638c2ecf20Sopenharmony_ci};
1648c2ecf20Sopenharmony_ci#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/**
1678c2ecf20Sopenharmony_ci * dccp_feat_index  -  Hash function to map feature number into array position
1688c2ecf20Sopenharmony_ci * @feat_num: feature to hash, one of %dccp_feature_numbers
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * Returns consecutive array index or -1 if the feature is not understood.
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_cistatic int dccp_feat_index(u8 feat_num)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
1758c2ecf20Sopenharmony_ci	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
1768c2ecf20Sopenharmony_ci		return feat_num - 1;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/*
1798c2ecf20Sopenharmony_ci	 * Other features: add cases for new feature types here after adding
1808c2ecf20Sopenharmony_ci	 * them to the above table.
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	switch (feat_num) {
1838c2ecf20Sopenharmony_ci	case DCCPF_SEND_LEV_RATE:
1848c2ecf20Sopenharmony_ci			return DCCP_FEAT_SUPPORTED_MAX - 1;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci	return -1;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic u8 dccp_feat_type(u8 feat_num)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	int idx = dccp_feat_index(feat_num);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (idx < 0)
1948c2ecf20Sopenharmony_ci		return FEAT_UNKNOWN;
1958c2ecf20Sopenharmony_ci	return dccp_feat_table[idx].reconciliation;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic int dccp_feat_default_value(u8 feat_num)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	int idx = dccp_feat_index(feat_num);
2018c2ecf20Sopenharmony_ci	/*
2028c2ecf20Sopenharmony_ci	 * There are no default values for unknown features, so encountering a
2038c2ecf20Sopenharmony_ci	 * negative index here indicates a serious problem somewhere else.
2048c2ecf20Sopenharmony_ci	 */
2058c2ecf20Sopenharmony_ci	DCCP_BUG_ON(idx < 0);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/*
2118c2ecf20Sopenharmony_ci *	Debugging and verbose-printing section
2128c2ecf20Sopenharmony_ci */
2138c2ecf20Sopenharmony_cistatic const char *dccp_feat_fname(const u8 feat)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	static const char *const feature_names[] = {
2168c2ecf20Sopenharmony_ci		[DCCPF_RESERVED]	= "Reserved",
2178c2ecf20Sopenharmony_ci		[DCCPF_CCID]		= "CCID",
2188c2ecf20Sopenharmony_ci		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
2198c2ecf20Sopenharmony_ci		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
2208c2ecf20Sopenharmony_ci		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
2218c2ecf20Sopenharmony_ci		[DCCPF_ACK_RATIO]	= "Ack Ratio",
2228c2ecf20Sopenharmony_ci		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
2238c2ecf20Sopenharmony_ci		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
2248c2ecf20Sopenharmony_ci		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
2258c2ecf20Sopenharmony_ci		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
2268c2ecf20Sopenharmony_ci	};
2278c2ecf20Sopenharmony_ci	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
2288c2ecf20Sopenharmony_ci		return feature_names[DCCPF_RESERVED];
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (feat ==  DCCPF_SEND_LEV_RATE)
2318c2ecf20Sopenharmony_ci		return "Send Loss Event Rate";
2328c2ecf20Sopenharmony_ci	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
2338c2ecf20Sopenharmony_ci		return "CCID-specific";
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return feature_names[feat];
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic const char *const dccp_feat_sname[] = {
2398c2ecf20Sopenharmony_ci	"DEFAULT", "INITIALISING", "CHANGING", "UNSTABLE", "STABLE",
2408c2ecf20Sopenharmony_ci};
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci#ifdef CONFIG_IP_DCCP_DEBUG
2438c2ecf20Sopenharmony_cistatic const char *dccp_feat_oname(const u8 opt)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	switch (opt) {
2468c2ecf20Sopenharmony_ci	case DCCPO_CHANGE_L:  return "Change_L";
2478c2ecf20Sopenharmony_ci	case DCCPO_CONFIRM_L: return "Confirm_L";
2488c2ecf20Sopenharmony_ci	case DCCPO_CHANGE_R:  return "Change_R";
2498c2ecf20Sopenharmony_ci	case DCCPO_CONFIRM_R: return "Confirm_R";
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci	return NULL;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic void dccp_feat_printval(u8 feat_num, dccp_feat_val const *val)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	u8 i, type = dccp_feat_type(feat_num);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (val == NULL || (type == FEAT_SP && val->sp.vec == NULL))
2598c2ecf20Sopenharmony_ci		dccp_pr_debug_cat("(NULL)");
2608c2ecf20Sopenharmony_ci	else if (type == FEAT_SP)
2618c2ecf20Sopenharmony_ci		for (i = 0; i < val->sp.len; i++)
2628c2ecf20Sopenharmony_ci			dccp_pr_debug_cat("%s%u", i ? " " : "", val->sp.vec[i]);
2638c2ecf20Sopenharmony_ci	else if (type == FEAT_NN)
2648c2ecf20Sopenharmony_ci		dccp_pr_debug_cat("%llu", (unsigned long long)val->nn);
2658c2ecf20Sopenharmony_ci	else
2668c2ecf20Sopenharmony_ci		dccp_pr_debug_cat("unknown type %u", type);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic void dccp_feat_printvals(u8 feat_num, u8 *list, u8 len)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	u8 type = dccp_feat_type(feat_num);
2728c2ecf20Sopenharmony_ci	dccp_feat_val fval = { .sp.vec = list, .sp.len = len };
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (type == FEAT_NN)
2758c2ecf20Sopenharmony_ci		fval.nn = dccp_decode_value_var(list, len);
2768c2ecf20Sopenharmony_ci	dccp_feat_printval(feat_num, &fval);
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic void dccp_feat_print_entry(struct dccp_feat_entry const *entry)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	dccp_debug("   * %s %s = ", entry->is_local ? "local" : "remote",
2828c2ecf20Sopenharmony_ci				    dccp_feat_fname(entry->feat_num));
2838c2ecf20Sopenharmony_ci	dccp_feat_printval(entry->feat_num, &entry->val);
2848c2ecf20Sopenharmony_ci	dccp_pr_debug_cat(", state=%s %s\n", dccp_feat_sname[entry->state],
2858c2ecf20Sopenharmony_ci			  entry->needs_confirm ? "(Confirm pending)" : "");
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci#define dccp_feat_print_opt(opt, feat, val, len, mandatory)	do {	      \
2898c2ecf20Sopenharmony_ci	dccp_pr_debug("%s(%s, ", dccp_feat_oname(opt), dccp_feat_fname(feat));\
2908c2ecf20Sopenharmony_ci	dccp_feat_printvals(feat, val, len);				      \
2918c2ecf20Sopenharmony_ci	dccp_pr_debug_cat(") %s\n", mandatory ? "!" : "");	} while (0)
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci#define dccp_feat_print_fnlist(fn_list)  {		\
2948c2ecf20Sopenharmony_ci	const struct dccp_feat_entry *___entry;		\
2958c2ecf20Sopenharmony_ci							\
2968c2ecf20Sopenharmony_ci	dccp_pr_debug("List Dump:\n");			\
2978c2ecf20Sopenharmony_ci	list_for_each_entry(___entry, fn_list, node)	\
2988c2ecf20Sopenharmony_ci		dccp_feat_print_entry(___entry);	\
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci#else	/* ! CONFIG_IP_DCCP_DEBUG */
3018c2ecf20Sopenharmony_ci#define dccp_feat_print_opt(opt, feat, val, len, mandatory)
3028c2ecf20Sopenharmony_ci#define dccp_feat_print_fnlist(fn_list)
3038c2ecf20Sopenharmony_ci#endif
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic int __dccp_feat_activate(struct sock *sk, const int idx,
3068c2ecf20Sopenharmony_ci				const bool is_local, dccp_feat_val const *fval)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	bool rx;
3098c2ecf20Sopenharmony_ci	u64 val;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
3128c2ecf20Sopenharmony_ci		return -1;
3138c2ecf20Sopenharmony_ci	if (dccp_feat_table[idx].activation_hdlr == NULL)
3148c2ecf20Sopenharmony_ci		return 0;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (fval == NULL) {
3178c2ecf20Sopenharmony_ci		val = dccp_feat_table[idx].default_value;
3188c2ecf20Sopenharmony_ci	} else if (dccp_feat_table[idx].reconciliation == FEAT_SP) {
3198c2ecf20Sopenharmony_ci		if (fval->sp.vec == NULL) {
3208c2ecf20Sopenharmony_ci			/*
3218c2ecf20Sopenharmony_ci			 * This can happen when an empty Confirm is sent
3228c2ecf20Sopenharmony_ci			 * for an SP (i.e. known) feature. In this case
3238c2ecf20Sopenharmony_ci			 * we would be using the default anyway.
3248c2ecf20Sopenharmony_ci			 */
3258c2ecf20Sopenharmony_ci			DCCP_CRIT("Feature #%d undefined: using default", idx);
3268c2ecf20Sopenharmony_ci			val = dccp_feat_table[idx].default_value;
3278c2ecf20Sopenharmony_ci		} else {
3288c2ecf20Sopenharmony_ci			val = fval->sp.vec[0];
3298c2ecf20Sopenharmony_ci		}
3308c2ecf20Sopenharmony_ci	} else {
3318c2ecf20Sopenharmony_ci		val = fval->nn;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* Location is RX if this is a local-RX or remote-TX feature */
3358c2ecf20Sopenharmony_ci	rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	dccp_debug("   -> activating %s %s, %sval=%llu\n", rx ? "RX" : "TX",
3388c2ecf20Sopenharmony_ci		   dccp_feat_fname(dccp_feat_table[idx].feat_num),
3398c2ecf20Sopenharmony_ci		   fval ? "" : "default ",  (unsigned long long)val);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/**
3458c2ecf20Sopenharmony_ci * dccp_feat_activate  -  Activate feature value on socket
3468c2ecf20Sopenharmony_ci * @sk: fully connected DCCP socket (after handshake is complete)
3478c2ecf20Sopenharmony_ci * @feat_num: feature to activate, one of %dccp_feature_numbers
3488c2ecf20Sopenharmony_ci * @local: whether local (1) or remote (0) @feat_num is meant
3498c2ecf20Sopenharmony_ci * @fval: the value (SP or NN) to activate, or NULL to use the default value
3508c2ecf20Sopenharmony_ci *
3518c2ecf20Sopenharmony_ci * For general use this function is preferable over __dccp_feat_activate().
3528c2ecf20Sopenharmony_ci */
3538c2ecf20Sopenharmony_cistatic int dccp_feat_activate(struct sock *sk, u8 feat_num, bool local,
3548c2ecf20Sopenharmony_ci			      dccp_feat_val const *fval)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	return __dccp_feat_activate(sk, dccp_feat_index(feat_num), local, fval);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/* Test for "Req'd" feature (RFC 4340, 6.4) */
3608c2ecf20Sopenharmony_cistatic inline int dccp_feat_must_be_understood(u8 feat_num)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	return	feat_num == DCCPF_CCID || feat_num == DCCPF_SHORT_SEQNOS ||
3638c2ecf20Sopenharmony_ci		feat_num == DCCPF_SEQUENCE_WINDOW;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci/* copy constructor, fval must not already contain allocated memory */
3678c2ecf20Sopenharmony_cistatic int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	fval->sp.len = len;
3708c2ecf20Sopenharmony_ci	if (fval->sp.len > 0) {
3718c2ecf20Sopenharmony_ci		fval->sp.vec = kmemdup(val, len, gfp_any());
3728c2ecf20Sopenharmony_ci		if (fval->sp.vec == NULL) {
3738c2ecf20Sopenharmony_ci			fval->sp.len = 0;
3748c2ecf20Sopenharmony_ci			return -ENOBUFS;
3758c2ecf20Sopenharmony_ci		}
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci	return 0;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	if (unlikely(val == NULL))
3838c2ecf20Sopenharmony_ci		return;
3848c2ecf20Sopenharmony_ci	if (dccp_feat_type(feat_num) == FEAT_SP)
3858c2ecf20Sopenharmony_ci		kfree(val->sp.vec);
3868c2ecf20Sopenharmony_ci	memset(val, 0, sizeof(*val));
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic struct dccp_feat_entry *
3908c2ecf20Sopenharmony_ci	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct dccp_feat_entry *new;
3938c2ecf20Sopenharmony_ci	u8 type = dccp_feat_type(original->feat_num);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (type == FEAT_UNKNOWN)
3968c2ecf20Sopenharmony_ci		return NULL;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
3998c2ecf20Sopenharmony_ci	if (new == NULL)
4008c2ecf20Sopenharmony_ci		return NULL;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
4038c2ecf20Sopenharmony_ci						      original->val.sp.vec,
4048c2ecf20Sopenharmony_ci						      original->val.sp.len)) {
4058c2ecf20Sopenharmony_ci		kfree(new);
4068c2ecf20Sopenharmony_ci		return NULL;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci	return new;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	if (entry != NULL) {
4148c2ecf20Sopenharmony_ci		dccp_feat_val_destructor(entry->feat_num, &entry->val);
4158c2ecf20Sopenharmony_ci		kfree(entry);
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci/*
4208c2ecf20Sopenharmony_ci * List management functions
4218c2ecf20Sopenharmony_ci *
4228c2ecf20Sopenharmony_ci * Feature negotiation lists rely on and maintain the following invariants:
4238c2ecf20Sopenharmony_ci * - each feat_num in the list is known, i.e. we know its type and default value
4248c2ecf20Sopenharmony_ci * - each feat_num/is_local combination is unique (old entries are overwritten)
4258c2ecf20Sopenharmony_ci * - SP values are always freshly allocated
4268c2ecf20Sopenharmony_ci * - list is sorted in increasing order of feature number (faster lookup)
4278c2ecf20Sopenharmony_ci */
4288c2ecf20Sopenharmony_cistatic struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
4298c2ecf20Sopenharmony_ci						     u8 feat_num, bool is_local)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	list_for_each_entry(entry, fn_list, node) {
4348c2ecf20Sopenharmony_ci		if (entry->feat_num == feat_num && entry->is_local == is_local)
4358c2ecf20Sopenharmony_ci			return entry;
4368c2ecf20Sopenharmony_ci		else if (entry->feat_num > feat_num)
4378c2ecf20Sopenharmony_ci			break;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci	return NULL;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/**
4438c2ecf20Sopenharmony_ci * dccp_feat_entry_new  -  Central list update routine (called by all others)
4448c2ecf20Sopenharmony_ci * @head:  list to add to
4458c2ecf20Sopenharmony_ci * @feat:  feature number
4468c2ecf20Sopenharmony_ci * @local: whether the local (1) or remote feature with number @feat is meant
4478c2ecf20Sopenharmony_ci *
4488c2ecf20Sopenharmony_ci * This is the only constructor and serves to ensure the above invariants.
4498c2ecf20Sopenharmony_ci */
4508c2ecf20Sopenharmony_cistatic struct dccp_feat_entry *
4518c2ecf20Sopenharmony_ci	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	list_for_each_entry(entry, head, node)
4568c2ecf20Sopenharmony_ci		if (entry->feat_num == feat && entry->is_local == local) {
4578c2ecf20Sopenharmony_ci			dccp_feat_val_destructor(entry->feat_num, &entry->val);
4588c2ecf20Sopenharmony_ci			return entry;
4598c2ecf20Sopenharmony_ci		} else if (entry->feat_num > feat) {
4608c2ecf20Sopenharmony_ci			head = &entry->node;
4618c2ecf20Sopenharmony_ci			break;
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	entry = kmalloc(sizeof(*entry), gfp_any());
4658c2ecf20Sopenharmony_ci	if (entry != NULL) {
4668c2ecf20Sopenharmony_ci		entry->feat_num = feat;
4678c2ecf20Sopenharmony_ci		entry->is_local = local;
4688c2ecf20Sopenharmony_ci		list_add_tail(&entry->node, head);
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci	return entry;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci/**
4748c2ecf20Sopenharmony_ci * dccp_feat_push_change  -  Add/overwrite a Change option in the list
4758c2ecf20Sopenharmony_ci * @fn_list: feature-negotiation list to update
4768c2ecf20Sopenharmony_ci * @feat: one of %dccp_feature_numbers
4778c2ecf20Sopenharmony_ci * @local: whether local (1) or remote (0) @feat_num is meant
4788c2ecf20Sopenharmony_ci * @mandatory: whether to use Mandatory feature negotiation options
4798c2ecf20Sopenharmony_ci * @fval: pointer to NN/SP value to be inserted (will be copied)
4808c2ecf20Sopenharmony_ci */
4818c2ecf20Sopenharmony_cistatic int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
4828c2ecf20Sopenharmony_ci				 u8 mandatory, dccp_feat_val *fval)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (new == NULL)
4878c2ecf20Sopenharmony_ci		return -ENOMEM;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	new->feat_num	     = feat;
4908c2ecf20Sopenharmony_ci	new->is_local	     = local;
4918c2ecf20Sopenharmony_ci	new->state	     = FEAT_INITIALISING;
4928c2ecf20Sopenharmony_ci	new->needs_confirm   = false;
4938c2ecf20Sopenharmony_ci	new->empty_confirm   = false;
4948c2ecf20Sopenharmony_ci	new->val	     = *fval;
4958c2ecf20Sopenharmony_ci	new->needs_mandatory = mandatory;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci/**
5018c2ecf20Sopenharmony_ci * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
5028c2ecf20Sopenharmony_ci * @fn_list: feature-negotiation list to add to
5038c2ecf20Sopenharmony_ci * @feat: one of %dccp_feature_numbers
5048c2ecf20Sopenharmony_ci * @local: whether local (1) or remote (0) @feat_num is being confirmed
5058c2ecf20Sopenharmony_ci * @fval: pointer to NN/SP value to be inserted or NULL
5068c2ecf20Sopenharmony_ci *
5078c2ecf20Sopenharmony_ci * Returns 0 on success, a Reset code for further processing otherwise.
5088c2ecf20Sopenharmony_ci */
5098c2ecf20Sopenharmony_cistatic int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
5108c2ecf20Sopenharmony_ci				  dccp_feat_val *fval)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	if (new == NULL)
5158c2ecf20Sopenharmony_ci		return DCCP_RESET_CODE_TOO_BUSY;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	new->feat_num	     = feat;
5188c2ecf20Sopenharmony_ci	new->is_local	     = local;
5198c2ecf20Sopenharmony_ci	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
5208c2ecf20Sopenharmony_ci	new->needs_confirm   = true;
5218c2ecf20Sopenharmony_ci	new->empty_confirm   = (fval == NULL);
5228c2ecf20Sopenharmony_ci	new->val.nn	     = 0;		/* zeroes the whole structure */
5238c2ecf20Sopenharmony_ci	if (!new->empty_confirm)
5248c2ecf20Sopenharmony_ci		new->val     = *fval;
5258c2ecf20Sopenharmony_ci	new->needs_mandatory = false;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return 0;
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	list_del(&entry->node);
5388c2ecf20Sopenharmony_ci	dccp_feat_entry_destructor(entry);
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_civoid dccp_feat_list_purge(struct list_head *fn_list)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry, *next;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, next, fn_list, node)
5468c2ecf20Sopenharmony_ci		dccp_feat_entry_destructor(entry);
5478c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(fn_list);
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_feat_list_purge);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci/* generate @to as full clone of @from - @to must not contain any nodes */
5528c2ecf20Sopenharmony_ciint dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry, *new;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(to);
5578c2ecf20Sopenharmony_ci	list_for_each_entry(entry, from, node) {
5588c2ecf20Sopenharmony_ci		new = dccp_feat_clone_entry(entry);
5598c2ecf20Sopenharmony_ci		if (new == NULL)
5608c2ecf20Sopenharmony_ci			goto cloning_failed;
5618c2ecf20Sopenharmony_ci		list_add_tail(&new->node, to);
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci	return 0;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cicloning_failed:
5668c2ecf20Sopenharmony_ci	dccp_feat_list_purge(to);
5678c2ecf20Sopenharmony_ci	return -ENOMEM;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci/**
5718c2ecf20Sopenharmony_ci * dccp_feat_valid_nn_length  -  Enforce length constraints on NN options
5728c2ecf20Sopenharmony_ci * @feat_num: feature to return length of, one of %dccp_feature_numbers
5738c2ecf20Sopenharmony_ci *
5748c2ecf20Sopenharmony_ci * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only,
5758c2ecf20Sopenharmony_ci * incoming options are accepted as long as their values are valid.
5768c2ecf20Sopenharmony_ci */
5778c2ecf20Sopenharmony_cistatic u8 dccp_feat_valid_nn_length(u8 feat_num)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	if (feat_num == DCCPF_ACK_RATIO)	/* RFC 4340, 11.3 and 6.6.8 */
5808c2ecf20Sopenharmony_ci		return 2;
5818c2ecf20Sopenharmony_ci	if (feat_num == DCCPF_SEQUENCE_WINDOW)	/* RFC 4340, 7.5.2 and 6.5  */
5828c2ecf20Sopenharmony_ci		return 6;
5838c2ecf20Sopenharmony_ci	return 0;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	switch (feat_num) {
5898c2ecf20Sopenharmony_ci	case DCCPF_ACK_RATIO:
5908c2ecf20Sopenharmony_ci		return val <= DCCPF_ACK_RATIO_MAX;
5918c2ecf20Sopenharmony_ci	case DCCPF_SEQUENCE_WINDOW:
5928c2ecf20Sopenharmony_ci		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci	return 0;	/* feature unknown - so we can't tell */
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci/* check that SP values are within the ranges defined in RFC 4340 */
5988c2ecf20Sopenharmony_cistatic u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	switch (feat_num) {
6018c2ecf20Sopenharmony_ci	case DCCPF_CCID:
6028c2ecf20Sopenharmony_ci		return val == DCCPC_CCID2 || val == DCCPC_CCID3;
6038c2ecf20Sopenharmony_ci	/* Type-check Boolean feature values: */
6048c2ecf20Sopenharmony_ci	case DCCPF_SHORT_SEQNOS:
6058c2ecf20Sopenharmony_ci	case DCCPF_ECN_INCAPABLE:
6068c2ecf20Sopenharmony_ci	case DCCPF_SEND_ACK_VECTOR:
6078c2ecf20Sopenharmony_ci	case DCCPF_SEND_NDP_COUNT:
6088c2ecf20Sopenharmony_ci	case DCCPF_DATA_CHECKSUM:
6098c2ecf20Sopenharmony_ci	case DCCPF_SEND_LEV_RATE:
6108c2ecf20Sopenharmony_ci		return val < 2;
6118c2ecf20Sopenharmony_ci	case DCCPF_MIN_CSUM_COVER:
6128c2ecf20Sopenharmony_ci		return val < 16;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci	return 0;			/* feature unknown */
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_cistatic u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	if (sp_list == NULL || sp_len < 1)
6208c2ecf20Sopenharmony_ci		return 0;
6218c2ecf20Sopenharmony_ci	while (sp_len--)
6228c2ecf20Sopenharmony_ci		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
6238c2ecf20Sopenharmony_ci			return 0;
6248c2ecf20Sopenharmony_ci	return 1;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci/**
6288c2ecf20Sopenharmony_ci * dccp_feat_insert_opts  -  Generate FN options from current list state
6298c2ecf20Sopenharmony_ci * @skb: next sk_buff to be sent to the peer
6308c2ecf20Sopenharmony_ci * @dp: for client during handshake and general negotiation
6318c2ecf20Sopenharmony_ci * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND)
6328c2ecf20Sopenharmony_ci */
6338c2ecf20Sopenharmony_ciint dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
6348c2ecf20Sopenharmony_ci			  struct sk_buff *skb)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
6378c2ecf20Sopenharmony_ci	struct dccp_feat_entry *pos, *next;
6388c2ecf20Sopenharmony_ci	u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN];
6398c2ecf20Sopenharmony_ci	bool rpt;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	/* put entries into @skb in the order they appear in the list */
6428c2ecf20Sopenharmony_ci	list_for_each_entry_safe_reverse(pos, next, fn, node) {
6438c2ecf20Sopenharmony_ci		opt  = dccp_feat_genopt(pos);
6448c2ecf20Sopenharmony_ci		type = dccp_feat_type(pos->feat_num);
6458c2ecf20Sopenharmony_ci		rpt  = false;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		if (pos->empty_confirm) {
6488c2ecf20Sopenharmony_ci			len = 0;
6498c2ecf20Sopenharmony_ci			ptr = NULL;
6508c2ecf20Sopenharmony_ci		} else {
6518c2ecf20Sopenharmony_ci			if (type == FEAT_SP) {
6528c2ecf20Sopenharmony_ci				len = pos->val.sp.len;
6538c2ecf20Sopenharmony_ci				ptr = pos->val.sp.vec;
6548c2ecf20Sopenharmony_ci				rpt = pos->needs_confirm;
6558c2ecf20Sopenharmony_ci			} else if (type == FEAT_NN) {
6568c2ecf20Sopenharmony_ci				len = dccp_feat_valid_nn_length(pos->feat_num);
6578c2ecf20Sopenharmony_ci				ptr = nn_in_nbo;
6588c2ecf20Sopenharmony_ci				dccp_encode_value_var(pos->val.nn, ptr, len);
6598c2ecf20Sopenharmony_ci			} else {
6608c2ecf20Sopenharmony_ci				DCCP_BUG("unknown feature %u", pos->feat_num);
6618c2ecf20Sopenharmony_ci				return -1;
6628c2ecf20Sopenharmony_ci			}
6638c2ecf20Sopenharmony_ci		}
6648c2ecf20Sopenharmony_ci		dccp_feat_print_opt(opt, pos->feat_num, ptr, len, 0);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
6678c2ecf20Sopenharmony_ci			return -1;
6688c2ecf20Sopenharmony_ci		if (pos->needs_mandatory && dccp_insert_option_mandatory(skb))
6698c2ecf20Sopenharmony_ci			return -1;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci		if (skb->sk->sk_state == DCCP_OPEN &&
6728c2ecf20Sopenharmony_ci		    (opt == DCCPO_CONFIRM_R || opt == DCCPO_CONFIRM_L)) {
6738c2ecf20Sopenharmony_ci			/*
6748c2ecf20Sopenharmony_ci			 * Confirms don't get retransmitted (6.6.3) once the
6758c2ecf20Sopenharmony_ci			 * connection is in state OPEN
6768c2ecf20Sopenharmony_ci			 */
6778c2ecf20Sopenharmony_ci			dccp_feat_list_pop(pos);
6788c2ecf20Sopenharmony_ci		} else {
6798c2ecf20Sopenharmony_ci			/*
6808c2ecf20Sopenharmony_ci			 * Enter CHANGING after transmitting the Change
6818c2ecf20Sopenharmony_ci			 * option (6.6.2).
6828c2ecf20Sopenharmony_ci			 */
6838c2ecf20Sopenharmony_ci			if (pos->state == FEAT_INITIALISING)
6848c2ecf20Sopenharmony_ci				pos->state = FEAT_CHANGING;
6858c2ecf20Sopenharmony_ci		}
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci	return 0;
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci/**
6918c2ecf20Sopenharmony_ci * __feat_register_nn  -  Register new NN value on socket
6928c2ecf20Sopenharmony_ci * @fn: feature-negotiation list to register with
6938c2ecf20Sopenharmony_ci * @feat: an NN feature from %dccp_feature_numbers
6948c2ecf20Sopenharmony_ci * @mandatory: use Mandatory option if 1
6958c2ecf20Sopenharmony_ci * @nn_val: value to register (restricted to 4 bytes)
6968c2ecf20Sopenharmony_ci *
6978c2ecf20Sopenharmony_ci * Note that NN features are local by definition (RFC 4340, 6.3.2).
6988c2ecf20Sopenharmony_ci */
6998c2ecf20Sopenharmony_cistatic int __feat_register_nn(struct list_head *fn, u8 feat,
7008c2ecf20Sopenharmony_ci			      u8 mandatory, u64 nn_val)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	dccp_feat_val fval = { .nn = nn_val };
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	if (dccp_feat_type(feat) != FEAT_NN ||
7058c2ecf20Sopenharmony_ci	    !dccp_feat_is_valid_nn_val(feat, nn_val))
7068c2ecf20Sopenharmony_ci		return -EINVAL;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* Don't bother with default values, they will be activated anyway. */
7098c2ecf20Sopenharmony_ci	if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
7108c2ecf20Sopenharmony_ci		return 0;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci/**
7168c2ecf20Sopenharmony_ci * __feat_register_sp  -  Register new SP value/list on socket
7178c2ecf20Sopenharmony_ci * @fn: feature-negotiation list to register with
7188c2ecf20Sopenharmony_ci * @feat: an SP feature from %dccp_feature_numbers
7198c2ecf20Sopenharmony_ci * @is_local: whether the local (1) or the remote (0) @feat is meant
7208c2ecf20Sopenharmony_ci * @mandatory: use Mandatory option if 1
7218c2ecf20Sopenharmony_ci * @sp_val: SP value followed by optional preference list
7228c2ecf20Sopenharmony_ci * @sp_len: length of @sp_val in bytes
7238c2ecf20Sopenharmony_ci */
7248c2ecf20Sopenharmony_cistatic int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
7258c2ecf20Sopenharmony_ci			      u8 mandatory, u8 const *sp_val, u8 sp_len)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	dccp_feat_val fval;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	if (dccp_feat_type(feat) != FEAT_SP ||
7308c2ecf20Sopenharmony_ci	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
7318c2ecf20Sopenharmony_ci		return -EINVAL;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	/* Avoid negotiating alien CCIDs by only advertising supported ones */
7348c2ecf20Sopenharmony_ci	if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
7358c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
7388c2ecf20Sopenharmony_ci		return -ENOMEM;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	if (dccp_feat_push_change(fn, feat, is_local, mandatory, &fval)) {
7418c2ecf20Sopenharmony_ci		kfree(fval.sp.vec);
7428c2ecf20Sopenharmony_ci		return -ENOMEM;
7438c2ecf20Sopenharmony_ci	}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	return 0;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci/**
7498c2ecf20Sopenharmony_ci * dccp_feat_register_sp  -  Register requests to change SP feature values
7508c2ecf20Sopenharmony_ci * @sk: client or listening socket
7518c2ecf20Sopenharmony_ci * @feat: one of %dccp_feature_numbers
7528c2ecf20Sopenharmony_ci * @is_local: whether the local (1) or remote (0) @feat is meant
7538c2ecf20Sopenharmony_ci * @list: array of preferred values, in descending order of preference
7548c2ecf20Sopenharmony_ci * @len: length of @list in bytes
7558c2ecf20Sopenharmony_ci */
7568c2ecf20Sopenharmony_ciint dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
7578c2ecf20Sopenharmony_ci			  u8 const *list, u8 len)
7588c2ecf20Sopenharmony_ci{	 /* any changes must be registered before establishing the connection */
7598c2ecf20Sopenharmony_ci	if (sk->sk_state != DCCP_CLOSED)
7608c2ecf20Sopenharmony_ci		return -EISCONN;
7618c2ecf20Sopenharmony_ci	if (dccp_feat_type(feat) != FEAT_SP)
7628c2ecf20Sopenharmony_ci		return -EINVAL;
7638c2ecf20Sopenharmony_ci	return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local,
7648c2ecf20Sopenharmony_ci				  0, list, len);
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci/**
7688c2ecf20Sopenharmony_ci * dccp_feat_nn_get  -  Query current/pending value of NN feature
7698c2ecf20Sopenharmony_ci * @sk: DCCP socket of an established connection
7708c2ecf20Sopenharmony_ci * @feat: NN feature number from %dccp_feature_numbers
7718c2ecf20Sopenharmony_ci *
7728c2ecf20Sopenharmony_ci * For a known NN feature, returns value currently being negotiated, or
7738c2ecf20Sopenharmony_ci * current (confirmed) value if no negotiation is going on.
7748c2ecf20Sopenharmony_ci */
7758c2ecf20Sopenharmony_ciu64 dccp_feat_nn_get(struct sock *sk, u8 feat)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	if (dccp_feat_type(feat) == FEAT_NN) {
7788c2ecf20Sopenharmony_ci		struct dccp_sock *dp = dccp_sk(sk);
7798c2ecf20Sopenharmony_ci		struct dccp_feat_entry *entry;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci		entry = dccp_feat_list_lookup(&dp->dccps_featneg, feat, 1);
7828c2ecf20Sopenharmony_ci		if (entry != NULL)
7838c2ecf20Sopenharmony_ci			return entry->val.nn;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci		switch (feat) {
7868c2ecf20Sopenharmony_ci		case DCCPF_ACK_RATIO:
7878c2ecf20Sopenharmony_ci			return dp->dccps_l_ack_ratio;
7888c2ecf20Sopenharmony_ci		case DCCPF_SEQUENCE_WINDOW:
7898c2ecf20Sopenharmony_ci			return dp->dccps_l_seq_win;
7908c2ecf20Sopenharmony_ci		}
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci	DCCP_BUG("attempt to look up unsupported feature %u", feat);
7938c2ecf20Sopenharmony_ci	return 0;
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_feat_nn_get);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci/**
7988c2ecf20Sopenharmony_ci * dccp_feat_signal_nn_change  -  Update NN values for an established connection
7998c2ecf20Sopenharmony_ci * @sk: DCCP socket of an established connection
8008c2ecf20Sopenharmony_ci * @feat: NN feature number from %dccp_feature_numbers
8018c2ecf20Sopenharmony_ci * @nn_val: the new value to use
8028c2ecf20Sopenharmony_ci *
8038c2ecf20Sopenharmony_ci * This function is used to communicate NN updates out-of-band.
8048c2ecf20Sopenharmony_ci */
8058c2ecf20Sopenharmony_ciint dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val)
8068c2ecf20Sopenharmony_ci{
8078c2ecf20Sopenharmony_ci	struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
8088c2ecf20Sopenharmony_ci	dccp_feat_val fval = { .nn = nn_val };
8098c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (sk->sk_state != DCCP_OPEN && sk->sk_state != DCCP_PARTOPEN)
8128c2ecf20Sopenharmony_ci		return 0;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (dccp_feat_type(feat) != FEAT_NN ||
8158c2ecf20Sopenharmony_ci	    !dccp_feat_is_valid_nn_val(feat, nn_val))
8168c2ecf20Sopenharmony_ci		return -EINVAL;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (nn_val == dccp_feat_nn_get(sk, feat))
8198c2ecf20Sopenharmony_ci		return 0;	/* already set or negotiation under way */
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	entry = dccp_feat_list_lookup(fn, feat, 1);
8228c2ecf20Sopenharmony_ci	if (entry != NULL) {
8238c2ecf20Sopenharmony_ci		dccp_pr_debug("Clobbering existing NN entry %llu -> %llu\n",
8248c2ecf20Sopenharmony_ci			      (unsigned long long)entry->val.nn,
8258c2ecf20Sopenharmony_ci			      (unsigned long long)nn_val);
8268c2ecf20Sopenharmony_ci		dccp_feat_list_pop(entry);
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	inet_csk_schedule_ack(sk);
8308c2ecf20Sopenharmony_ci	return dccp_feat_push_change(fn, feat, 1, 0, &fval);
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_feat_signal_nn_change);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci/*
8358c2ecf20Sopenharmony_ci *	Tracking features whose value depend on the choice of CCID
8368c2ecf20Sopenharmony_ci *
8378c2ecf20Sopenharmony_ci * This is designed with an extension in mind so that a list walk could be done
8388c2ecf20Sopenharmony_ci * before activating any features. However, the existing framework was found to
8398c2ecf20Sopenharmony_ci * work satisfactorily up until now, the automatic verification is left open.
8408c2ecf20Sopenharmony_ci * When adding new CCIDs, add a corresponding dependency table here.
8418c2ecf20Sopenharmony_ci */
8428c2ecf20Sopenharmony_cistatic const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	static const struct ccid_dependency ccid2_dependencies[2][2] = {
8458c2ecf20Sopenharmony_ci		/*
8468c2ecf20Sopenharmony_ci		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
8478c2ecf20Sopenharmony_ci		 * feature and Send Ack Vector is an RX feature, `is_local'
8488c2ecf20Sopenharmony_ci		 * needs to be reversed.
8498c2ecf20Sopenharmony_ci		 */
8508c2ecf20Sopenharmony_ci		{	/* Dependencies of the receiver-side (remote) CCID2 */
8518c2ecf20Sopenharmony_ci			{
8528c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
8538c2ecf20Sopenharmony_ci				.is_local	= true,
8548c2ecf20Sopenharmony_ci				.is_mandatory	= true,
8558c2ecf20Sopenharmony_ci				.val		= 1
8568c2ecf20Sopenharmony_ci			},
8578c2ecf20Sopenharmony_ci			{ 0, 0, 0, 0 }
8588c2ecf20Sopenharmony_ci		},
8598c2ecf20Sopenharmony_ci		{	/* Dependencies of the sender-side (local) CCID2 */
8608c2ecf20Sopenharmony_ci			{
8618c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
8628c2ecf20Sopenharmony_ci				.is_local	= false,
8638c2ecf20Sopenharmony_ci				.is_mandatory	= true,
8648c2ecf20Sopenharmony_ci				.val		= 1
8658c2ecf20Sopenharmony_ci			},
8668c2ecf20Sopenharmony_ci			{ 0, 0, 0, 0 }
8678c2ecf20Sopenharmony_ci		}
8688c2ecf20Sopenharmony_ci	};
8698c2ecf20Sopenharmony_ci	static const struct ccid_dependency ccid3_dependencies[2][5] = {
8708c2ecf20Sopenharmony_ci		{	/*
8718c2ecf20Sopenharmony_ci			 * Dependencies of the receiver-side CCID3
8728c2ecf20Sopenharmony_ci			 */
8738c2ecf20Sopenharmony_ci			{	/* locally disable Ack Vectors */
8748c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
8758c2ecf20Sopenharmony_ci				.is_local	= true,
8768c2ecf20Sopenharmony_ci				.is_mandatory	= false,
8778c2ecf20Sopenharmony_ci				.val		= 0
8788c2ecf20Sopenharmony_ci			},
8798c2ecf20Sopenharmony_ci			{	/* see below why Send Loss Event Rate is on */
8808c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_SEND_LEV_RATE,
8818c2ecf20Sopenharmony_ci				.is_local	= true,
8828c2ecf20Sopenharmony_ci				.is_mandatory	= true,
8838c2ecf20Sopenharmony_ci				.val		= 1
8848c2ecf20Sopenharmony_ci			},
8858c2ecf20Sopenharmony_ci			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
8868c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
8878c2ecf20Sopenharmony_ci				.is_local	= false,
8888c2ecf20Sopenharmony_ci				.is_mandatory	= true,
8898c2ecf20Sopenharmony_ci				.val		= 1
8908c2ecf20Sopenharmony_ci			},
8918c2ecf20Sopenharmony_ci			{ 0, 0, 0, 0 },
8928c2ecf20Sopenharmony_ci		},
8938c2ecf20Sopenharmony_ci		{	/*
8948c2ecf20Sopenharmony_ci			 * CCID3 at the TX side: we request that the HC-receiver
8958c2ecf20Sopenharmony_ci			 * will not send Ack Vectors (they will be ignored, so
8968c2ecf20Sopenharmony_ci			 * Mandatory is not set); we enable Send Loss Event Rate
8978c2ecf20Sopenharmony_ci			 * (Mandatory since the implementation does not support
8988c2ecf20Sopenharmony_ci			 * the Loss Intervals option of RFC 4342, 8.6).
8998c2ecf20Sopenharmony_ci			 * The last two options are for peer's information only.
9008c2ecf20Sopenharmony_ci			*/
9018c2ecf20Sopenharmony_ci			{
9028c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
9038c2ecf20Sopenharmony_ci				.is_local	= false,
9048c2ecf20Sopenharmony_ci				.is_mandatory	= false,
9058c2ecf20Sopenharmony_ci				.val		= 0
9068c2ecf20Sopenharmony_ci			},
9078c2ecf20Sopenharmony_ci			{
9088c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_SEND_LEV_RATE,
9098c2ecf20Sopenharmony_ci				.is_local	= false,
9108c2ecf20Sopenharmony_ci				.is_mandatory	= true,
9118c2ecf20Sopenharmony_ci				.val		= 1
9128c2ecf20Sopenharmony_ci			},
9138c2ecf20Sopenharmony_ci			{	/* this CCID does not support Ack Ratio */
9148c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_ACK_RATIO,
9158c2ecf20Sopenharmony_ci				.is_local	= true,
9168c2ecf20Sopenharmony_ci				.is_mandatory	= false,
9178c2ecf20Sopenharmony_ci				.val		= 0
9188c2ecf20Sopenharmony_ci			},
9198c2ecf20Sopenharmony_ci			{	/* tell receiver we are sending NDP counts */
9208c2ecf20Sopenharmony_ci				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
9218c2ecf20Sopenharmony_ci				.is_local	= true,
9228c2ecf20Sopenharmony_ci				.is_mandatory	= false,
9238c2ecf20Sopenharmony_ci				.val		= 1
9248c2ecf20Sopenharmony_ci			},
9258c2ecf20Sopenharmony_ci			{ 0, 0, 0, 0 }
9268c2ecf20Sopenharmony_ci		}
9278c2ecf20Sopenharmony_ci	};
9288c2ecf20Sopenharmony_ci	switch (ccid) {
9298c2ecf20Sopenharmony_ci	case DCCPC_CCID2:
9308c2ecf20Sopenharmony_ci		return ccid2_dependencies[is_local];
9318c2ecf20Sopenharmony_ci	case DCCPC_CCID3:
9328c2ecf20Sopenharmony_ci		return ccid3_dependencies[is_local];
9338c2ecf20Sopenharmony_ci	default:
9348c2ecf20Sopenharmony_ci		return NULL;
9358c2ecf20Sopenharmony_ci	}
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci/**
9398c2ecf20Sopenharmony_ci * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
9408c2ecf20Sopenharmony_ci * @fn: feature-negotiation list to update
9418c2ecf20Sopenharmony_ci * @id: CCID number to track
9428c2ecf20Sopenharmony_ci * @is_local: whether TX CCID (1) or RX CCID (0) is meant
9438c2ecf20Sopenharmony_ci *
9448c2ecf20Sopenharmony_ci * This function needs to be called after registering all other features.
9458c2ecf20Sopenharmony_ci */
9468c2ecf20Sopenharmony_cistatic int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
9498c2ecf20Sopenharmony_ci	int i, rc = (table == NULL);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
9528c2ecf20Sopenharmony_ci		if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
9538c2ecf20Sopenharmony_ci			rc = __feat_register_sp(fn, table[i].dependent_feat,
9548c2ecf20Sopenharmony_ci						    table[i].is_local,
9558c2ecf20Sopenharmony_ci						    table[i].is_mandatory,
9568c2ecf20Sopenharmony_ci						    &table[i].val, 1);
9578c2ecf20Sopenharmony_ci		else
9588c2ecf20Sopenharmony_ci			rc = __feat_register_nn(fn, table[i].dependent_feat,
9598c2ecf20Sopenharmony_ci						    table[i].is_mandatory,
9608c2ecf20Sopenharmony_ci						    table[i].val);
9618c2ecf20Sopenharmony_ci	return rc;
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci/**
9658c2ecf20Sopenharmony_ci * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
9668c2ecf20Sopenharmony_ci * @dp: client or listening socket (settings will be inherited)
9678c2ecf20Sopenharmony_ci *
9688c2ecf20Sopenharmony_ci * This is called after all registrations (socket initialisation, sysctls, and
9698c2ecf20Sopenharmony_ci * sockopt calls), and before sending the first packet containing Change options
9708c2ecf20Sopenharmony_ci * (ie. client-Request or server-Response), to ensure internal consistency.
9718c2ecf20Sopenharmony_ci */
9728c2ecf20Sopenharmony_ciint dccp_feat_finalise_settings(struct dccp_sock *dp)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	struct list_head *fn = &dp->dccps_featneg;
9758c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry;
9768c2ecf20Sopenharmony_ci	int i = 2, ccids[2] = { -1, -1 };
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	/*
9798c2ecf20Sopenharmony_ci	 * Propagating CCIDs:
9808c2ecf20Sopenharmony_ci	 * 1) not useful to propagate CCID settings if this host advertises more
9818c2ecf20Sopenharmony_ci	 *    than one CCID: the choice of CCID  may still change - if this is
9828c2ecf20Sopenharmony_ci	 *    the client, or if this is the server and the client sends
9838c2ecf20Sopenharmony_ci	 *    singleton CCID values.
9848c2ecf20Sopenharmony_ci	 * 2) since is that propagate_ccid changes the list, we defer changing
9858c2ecf20Sopenharmony_ci	 *    the sorted list until after the traversal.
9868c2ecf20Sopenharmony_ci	 */
9878c2ecf20Sopenharmony_ci	list_for_each_entry(entry, fn, node)
9888c2ecf20Sopenharmony_ci		if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
9898c2ecf20Sopenharmony_ci			ccids[entry->is_local] = entry->val.sp.vec[0];
9908c2ecf20Sopenharmony_ci	while (i--)
9918c2ecf20Sopenharmony_ci		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
9928c2ecf20Sopenharmony_ci			return -1;
9938c2ecf20Sopenharmony_ci	dccp_feat_print_fnlist(fn);
9948c2ecf20Sopenharmony_ci	return 0;
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci/**
9988c2ecf20Sopenharmony_ci * dccp_feat_server_ccid_dependencies  -  Resolve CCID-dependent features
9998c2ecf20Sopenharmony_ci * It is the server which resolves the dependencies once the CCID has been
10008c2ecf20Sopenharmony_ci * fully negotiated. If no CCID has been negotiated, it uses the default CCID.
10018c2ecf20Sopenharmony_ci */
10028c2ecf20Sopenharmony_ciint dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	struct list_head *fn = &dreq->dreq_featneg;
10058c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry;
10068c2ecf20Sopenharmony_ci	u8 is_local, ccid;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	for (is_local = 0; is_local <= 1; is_local++) {
10098c2ecf20Sopenharmony_ci		entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci		if (entry != NULL && !entry->empty_confirm)
10128c2ecf20Sopenharmony_ci			ccid = entry->val.sp.vec[0];
10138c2ecf20Sopenharmony_ci		else
10148c2ecf20Sopenharmony_ci			ccid = dccp_feat_default_value(DCCPF_CCID);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci		if (dccp_feat_propagate_ccid(fn, ccid, is_local))
10178c2ecf20Sopenharmony_ci			return -1;
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci	return 0;
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
10238c2ecf20Sopenharmony_cistatic int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci	u8 c, s;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	for (s = 0; s < slen; s++)
10288c2ecf20Sopenharmony_ci		for (c = 0; c < clen; c++)
10298c2ecf20Sopenharmony_ci			if (servlist[s] == clilist[c])
10308c2ecf20Sopenharmony_ci				return servlist[s];
10318c2ecf20Sopenharmony_ci	return -1;
10328c2ecf20Sopenharmony_ci}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci/**
10358c2ecf20Sopenharmony_ci * dccp_feat_prefer  -  Move preferred entry to the start of array
10368c2ecf20Sopenharmony_ci * Reorder the @array_len elements in @array so that @preferred_value comes
10378c2ecf20Sopenharmony_ci * first. Returns >0 to indicate that @preferred_value does occur in @array.
10388c2ecf20Sopenharmony_ci */
10398c2ecf20Sopenharmony_cistatic u8 dccp_feat_prefer(u8 preferred_value, u8 *array, u8 array_len)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	u8 i, does_occur = 0;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	if (array != NULL) {
10448c2ecf20Sopenharmony_ci		for (i = 0; i < array_len; i++)
10458c2ecf20Sopenharmony_ci			if (array[i] == preferred_value) {
10468c2ecf20Sopenharmony_ci				array[i] = array[0];
10478c2ecf20Sopenharmony_ci				does_occur++;
10488c2ecf20Sopenharmony_ci			}
10498c2ecf20Sopenharmony_ci		if (does_occur)
10508c2ecf20Sopenharmony_ci			array[0] = preferred_value;
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci	return does_occur;
10538c2ecf20Sopenharmony_ci}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci/**
10568c2ecf20Sopenharmony_ci * dccp_feat_reconcile  -  Reconcile SP preference lists
10578c2ecf20Sopenharmony_ci *  @fv: SP list to reconcile into
10588c2ecf20Sopenharmony_ci *  @arr: received SP preference list
10598c2ecf20Sopenharmony_ci *  @len: length of @arr in bytes
10608c2ecf20Sopenharmony_ci *  @is_server: whether this side is the server (and @fv is the server's list)
10618c2ecf20Sopenharmony_ci *  @reorder: whether to reorder the list in @fv after reconciling with @arr
10628c2ecf20Sopenharmony_ci * When successful, > 0 is returned and the reconciled list is in @fval.
10638c2ecf20Sopenharmony_ci * A value of 0 means that negotiation failed (no shared entry).
10648c2ecf20Sopenharmony_ci */
10658c2ecf20Sopenharmony_cistatic int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
10668c2ecf20Sopenharmony_ci			       bool is_server, bool reorder)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	int rc;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (!fv->sp.vec || !arr) {
10718c2ecf20Sopenharmony_ci		DCCP_CRIT("NULL feature value or array");
10728c2ecf20Sopenharmony_ci		return 0;
10738c2ecf20Sopenharmony_ci	}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	if (is_server)
10768c2ecf20Sopenharmony_ci		rc = dccp_feat_preflist_match(fv->sp.vec, fv->sp.len, arr, len);
10778c2ecf20Sopenharmony_ci	else
10788c2ecf20Sopenharmony_ci		rc = dccp_feat_preflist_match(arr, len, fv->sp.vec, fv->sp.len);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if (!reorder)
10818c2ecf20Sopenharmony_ci		return rc;
10828c2ecf20Sopenharmony_ci	if (rc < 0)
10838c2ecf20Sopenharmony_ci		return 0;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	/*
10868c2ecf20Sopenharmony_ci	 * Reorder list: used for activating features and in dccp_insert_fn_opt.
10878c2ecf20Sopenharmony_ci	 */
10888c2ecf20Sopenharmony_ci	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
10898c2ecf20Sopenharmony_ci}
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci/**
10928c2ecf20Sopenharmony_ci * dccp_feat_change_recv  -  Process incoming ChangeL/R options
10938c2ecf20Sopenharmony_ci * @fn: feature-negotiation list to update
10948c2ecf20Sopenharmony_ci * @is_mandatory: whether the Change was preceded by a Mandatory option
10958c2ecf20Sopenharmony_ci * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R
10968c2ecf20Sopenharmony_ci * @feat: one of %dccp_feature_numbers
10978c2ecf20Sopenharmony_ci * @val: NN value or SP value/preference list
10988c2ecf20Sopenharmony_ci * @len: length of @val in bytes
10998c2ecf20Sopenharmony_ci * @server: whether this node is the server (1) or the client (0)
11008c2ecf20Sopenharmony_ci */
11018c2ecf20Sopenharmony_cistatic u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
11028c2ecf20Sopenharmony_ci				u8 feat, u8 *val, u8 len, const bool server)
11038c2ecf20Sopenharmony_ci{
11048c2ecf20Sopenharmony_ci	u8 defval, type = dccp_feat_type(feat);
11058c2ecf20Sopenharmony_ci	const bool local = (opt == DCCPO_CHANGE_R);
11068c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry;
11078c2ecf20Sopenharmony_ci	dccp_feat_val fval;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	if (len == 0 || type == FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
11108c2ecf20Sopenharmony_ci		goto unknown_feature_or_value;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	/*
11158c2ecf20Sopenharmony_ci	 *	Negotiation of NN features: Change R is invalid, so there is no
11168c2ecf20Sopenharmony_ci	 *	simultaneous negotiation; hence we do not look up in the list.
11178c2ecf20Sopenharmony_ci	 */
11188c2ecf20Sopenharmony_ci	if (type == FEAT_NN) {
11198c2ecf20Sopenharmony_ci		if (local || len > sizeof(fval.nn))
11208c2ecf20Sopenharmony_ci			goto unknown_feature_or_value;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci		/* 6.3.2: "The feature remote MUST accept any valid value..." */
11238c2ecf20Sopenharmony_ci		fval.nn = dccp_decode_value_var(val, len);
11248c2ecf20Sopenharmony_ci		if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
11258c2ecf20Sopenharmony_ci			goto unknown_feature_or_value;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci		return dccp_feat_push_confirm(fn, feat, local, &fval);
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	/*
11318c2ecf20Sopenharmony_ci	 *	Unidirectional/simultaneous negotiation of SP features (6.3.1)
11328c2ecf20Sopenharmony_ci	 */
11338c2ecf20Sopenharmony_ci	entry = dccp_feat_list_lookup(fn, feat, local);
11348c2ecf20Sopenharmony_ci	if (entry == NULL) {
11358c2ecf20Sopenharmony_ci		/*
11368c2ecf20Sopenharmony_ci		 * No particular preferences have been registered. We deal with
11378c2ecf20Sopenharmony_ci		 * this situation by assuming that all valid values are equally
11388c2ecf20Sopenharmony_ci		 * acceptable, and apply the following checks:
11398c2ecf20Sopenharmony_ci		 * - if the peer's list is a singleton, we accept a valid value;
11408c2ecf20Sopenharmony_ci		 * - if we are the server, we first try to see if the peer (the
11418c2ecf20Sopenharmony_ci		 *   client) advertises the default value. If yes, we use it,
11428c2ecf20Sopenharmony_ci		 *   otherwise we accept the preferred value;
11438c2ecf20Sopenharmony_ci		 * - else if we are the client, we use the first list element.
11448c2ecf20Sopenharmony_ci		 */
11458c2ecf20Sopenharmony_ci		if (dccp_feat_clone_sp_val(&fval, val, 1))
11468c2ecf20Sopenharmony_ci			return DCCP_RESET_CODE_TOO_BUSY;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci		if (len > 1 && server) {
11498c2ecf20Sopenharmony_ci			defval = dccp_feat_default_value(feat);
11508c2ecf20Sopenharmony_ci			if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
11518c2ecf20Sopenharmony_ci				fval.sp.vec[0] = defval;
11528c2ecf20Sopenharmony_ci		} else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) {
11538c2ecf20Sopenharmony_ci			kfree(fval.sp.vec);
11548c2ecf20Sopenharmony_ci			goto unknown_feature_or_value;
11558c2ecf20Sopenharmony_ci		}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci		/* Treat unsupported CCIDs like invalid values */
11588c2ecf20Sopenharmony_ci		if (feat == DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) {
11598c2ecf20Sopenharmony_ci			kfree(fval.sp.vec);
11608c2ecf20Sopenharmony_ci			goto not_valid_or_not_known;
11618c2ecf20Sopenharmony_ci		}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci		return dccp_feat_push_confirm(fn, feat, local, &fval);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	} else if (entry->state == FEAT_UNSTABLE) {	/* 6.6.2 */
11668c2ecf20Sopenharmony_ci		return 0;
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	if (dccp_feat_reconcile(&entry->val, val, len, server, true)) {
11708c2ecf20Sopenharmony_ci		entry->empty_confirm = false;
11718c2ecf20Sopenharmony_ci	} else if (is_mandatory) {
11728c2ecf20Sopenharmony_ci		return DCCP_RESET_CODE_MANDATORY_ERROR;
11738c2ecf20Sopenharmony_ci	} else if (entry->state == FEAT_INITIALISING) {
11748c2ecf20Sopenharmony_ci		/*
11758c2ecf20Sopenharmony_ci		 * Failed simultaneous negotiation (server only): try to `save'
11768c2ecf20Sopenharmony_ci		 * the connection by checking whether entry contains the default
11778c2ecf20Sopenharmony_ci		 * value for @feat. If yes, send an empty Confirm to signal that
11788c2ecf20Sopenharmony_ci		 * the received Change was not understood - which implies using
11798c2ecf20Sopenharmony_ci		 * the default value.
11808c2ecf20Sopenharmony_ci		 * If this also fails, we use Reset as the last resort.
11818c2ecf20Sopenharmony_ci		 */
11828c2ecf20Sopenharmony_ci		WARN_ON(!server);
11838c2ecf20Sopenharmony_ci		defval = dccp_feat_default_value(feat);
11848c2ecf20Sopenharmony_ci		if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true))
11858c2ecf20Sopenharmony_ci			return DCCP_RESET_CODE_OPTION_ERROR;
11868c2ecf20Sopenharmony_ci		entry->empty_confirm = true;
11878c2ecf20Sopenharmony_ci	}
11888c2ecf20Sopenharmony_ci	entry->needs_confirm   = true;
11898c2ecf20Sopenharmony_ci	entry->needs_mandatory = false;
11908c2ecf20Sopenharmony_ci	entry->state	       = FEAT_STABLE;
11918c2ecf20Sopenharmony_ci	return 0;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ciunknown_feature_or_value:
11948c2ecf20Sopenharmony_ci	if (!is_mandatory)
11958c2ecf20Sopenharmony_ci		return dccp_push_empty_confirm(fn, feat, local);
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_cinot_valid_or_not_known:
11988c2ecf20Sopenharmony_ci	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
11998c2ecf20Sopenharmony_ci			    : DCCP_RESET_CODE_OPTION_ERROR;
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci/**
12038c2ecf20Sopenharmony_ci * dccp_feat_confirm_recv  -  Process received Confirm options
12048c2ecf20Sopenharmony_ci * @fn: feature-negotiation list to update
12058c2ecf20Sopenharmony_ci * @is_mandatory: whether @opt was preceded by a Mandatory option
12068c2ecf20Sopenharmony_ci * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R
12078c2ecf20Sopenharmony_ci * @feat: one of %dccp_feature_numbers
12088c2ecf20Sopenharmony_ci * @val: NN value or SP value/preference list
12098c2ecf20Sopenharmony_ci * @len: length of @val in bytes
12108c2ecf20Sopenharmony_ci * @server: whether this node is server (1) or client (0)
12118c2ecf20Sopenharmony_ci */
12128c2ecf20Sopenharmony_cistatic u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
12138c2ecf20Sopenharmony_ci				 u8 feat, u8 *val, u8 len, const bool server)
12148c2ecf20Sopenharmony_ci{
12158c2ecf20Sopenharmony_ci	u8 *plist, plen, type = dccp_feat_type(feat);
12168c2ecf20Sopenharmony_ci	const bool local = (opt == DCCPO_CONFIRM_R);
12178c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	if (entry == NULL) {	/* nothing queued: ignore or handle error */
12228c2ecf20Sopenharmony_ci		if (is_mandatory && type == FEAT_UNKNOWN)
12238c2ecf20Sopenharmony_ci			return DCCP_RESET_CODE_MANDATORY_ERROR;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		if (!local && type == FEAT_NN)		/* 6.3.2 */
12268c2ecf20Sopenharmony_ci			goto confirmation_failed;
12278c2ecf20Sopenharmony_ci		return 0;
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	if (entry->state != FEAT_CHANGING)		/* 6.6.2 */
12318c2ecf20Sopenharmony_ci		return 0;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	if (len == 0) {
12348c2ecf20Sopenharmony_ci		if (dccp_feat_must_be_understood(feat))	/* 6.6.7 */
12358c2ecf20Sopenharmony_ci			goto confirmation_failed;
12368c2ecf20Sopenharmony_ci		/*
12378c2ecf20Sopenharmony_ci		 * Empty Confirm during connection setup: this means reverting
12388c2ecf20Sopenharmony_ci		 * to the `old' value, which in this case is the default. Since
12398c2ecf20Sopenharmony_ci		 * we handle default values automatically when no other values
12408c2ecf20Sopenharmony_ci		 * have been set, we revert to the old value by removing this
12418c2ecf20Sopenharmony_ci		 * entry from the list.
12428c2ecf20Sopenharmony_ci		 */
12438c2ecf20Sopenharmony_ci		dccp_feat_list_pop(entry);
12448c2ecf20Sopenharmony_ci		return 0;
12458c2ecf20Sopenharmony_ci	}
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	if (type == FEAT_NN) {
12488c2ecf20Sopenharmony_ci		if (len > sizeof(entry->val.nn))
12498c2ecf20Sopenharmony_ci			goto confirmation_failed;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci		if (entry->val.nn == dccp_decode_value_var(val, len))
12528c2ecf20Sopenharmony_ci			goto confirmation_succeeded;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci		DCCP_WARN("Bogus Confirm for non-existing value\n");
12558c2ecf20Sopenharmony_ci		goto confirmation_failed;
12568c2ecf20Sopenharmony_ci	}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	/*
12598c2ecf20Sopenharmony_ci	 * Parsing SP Confirms: the first element of @val is the preferred
12608c2ecf20Sopenharmony_ci	 * SP value which the peer confirms, the remainder depends on @len.
12618c2ecf20Sopenharmony_ci	 * Note that only the confirmed value need to be a valid SP value.
12628c2ecf20Sopenharmony_ci	 */
12638c2ecf20Sopenharmony_ci	if (!dccp_feat_is_valid_sp_val(feat, *val))
12648c2ecf20Sopenharmony_ci		goto confirmation_failed;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	if (len == 1) {		/* peer didn't supply a preference list */
12678c2ecf20Sopenharmony_ci		plist = val;
12688c2ecf20Sopenharmony_ci		plen  = len;
12698c2ecf20Sopenharmony_ci	} else {		/* preferred value + preference list */
12708c2ecf20Sopenharmony_ci		plist = val + 1;
12718c2ecf20Sopenharmony_ci		plen  = len - 1;
12728c2ecf20Sopenharmony_ci	}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	/* Check whether the peer got the reconciliation right (6.6.8) */
12758c2ecf20Sopenharmony_ci	if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) {
12768c2ecf20Sopenharmony_ci		DCCP_WARN("Confirm selected the wrong value %u\n", *val);
12778c2ecf20Sopenharmony_ci		return DCCP_RESET_CODE_OPTION_ERROR;
12788c2ecf20Sopenharmony_ci	}
12798c2ecf20Sopenharmony_ci	entry->val.sp.vec[0] = *val;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ciconfirmation_succeeded:
12828c2ecf20Sopenharmony_ci	entry->state = FEAT_STABLE;
12838c2ecf20Sopenharmony_ci	return 0;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ciconfirmation_failed:
12868c2ecf20Sopenharmony_ci	DCCP_WARN("Confirmation failed\n");
12878c2ecf20Sopenharmony_ci	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
12888c2ecf20Sopenharmony_ci			    : DCCP_RESET_CODE_OPTION_ERROR;
12898c2ecf20Sopenharmony_ci}
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci/**
12928c2ecf20Sopenharmony_ci * dccp_feat_handle_nn_established  -  Fast-path reception of NN options
12938c2ecf20Sopenharmony_ci * @sk:		socket of an established DCCP connection
12948c2ecf20Sopenharmony_ci * @mandatory:	whether @opt was preceded by a Mandatory option
12958c2ecf20Sopenharmony_ci * @opt:	%DCCPO_CHANGE_L | %DCCPO_CONFIRM_R (NN only)
12968c2ecf20Sopenharmony_ci * @feat:	NN number, one of %dccp_feature_numbers
12978c2ecf20Sopenharmony_ci * @val:	NN value
12988c2ecf20Sopenharmony_ci * @len:	length of @val in bytes
12998c2ecf20Sopenharmony_ci *
13008c2ecf20Sopenharmony_ci * This function combines the functionality of change_recv/confirm_recv, with
13018c2ecf20Sopenharmony_ci * the following differences (reset codes are the same):
13028c2ecf20Sopenharmony_ci *    - cleanup after receiving the Confirm;
13038c2ecf20Sopenharmony_ci *    - values are directly activated after successful parsing;
13048c2ecf20Sopenharmony_ci *    - deliberately restricted to NN features.
13058c2ecf20Sopenharmony_ci * The restriction to NN features is essential since SP features can have non-
13068c2ecf20Sopenharmony_ci * predictable outcomes (depending on the remote configuration), and are inter-
13078c2ecf20Sopenharmony_ci * dependent (CCIDs for instance cause further dependencies).
13088c2ecf20Sopenharmony_ci */
13098c2ecf20Sopenharmony_cistatic u8 dccp_feat_handle_nn_established(struct sock *sk, u8 mandatory, u8 opt,
13108c2ecf20Sopenharmony_ci					  u8 feat, u8 *val, u8 len)
13118c2ecf20Sopenharmony_ci{
13128c2ecf20Sopenharmony_ci	struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
13138c2ecf20Sopenharmony_ci	const bool local = (opt == DCCPO_CONFIRM_R);
13148c2ecf20Sopenharmony_ci	struct dccp_feat_entry *entry;
13158c2ecf20Sopenharmony_ci	u8 type = dccp_feat_type(feat);
13168c2ecf20Sopenharmony_ci	dccp_feat_val fval;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	dccp_feat_print_opt(opt, feat, val, len, mandatory);
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	/* Ignore non-mandatory unknown and non-NN features */
13218c2ecf20Sopenharmony_ci	if (type == FEAT_UNKNOWN) {
13228c2ecf20Sopenharmony_ci		if (local && !mandatory)
13238c2ecf20Sopenharmony_ci			return 0;
13248c2ecf20Sopenharmony_ci		goto fast_path_unknown;
13258c2ecf20Sopenharmony_ci	} else if (type != FEAT_NN) {
13268c2ecf20Sopenharmony_ci		return 0;
13278c2ecf20Sopenharmony_ci	}
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	/*
13308c2ecf20Sopenharmony_ci	 * We don't accept empty Confirms, since in fast-path feature
13318c2ecf20Sopenharmony_ci	 * negotiation the values are enabled immediately after sending
13328c2ecf20Sopenharmony_ci	 * the Change option.
13338c2ecf20Sopenharmony_ci	 * Empty Changes on the other hand are invalid (RFC 4340, 6.1).
13348c2ecf20Sopenharmony_ci	 */
13358c2ecf20Sopenharmony_ci	if (len == 0 || len > sizeof(fval.nn))
13368c2ecf20Sopenharmony_ci		goto fast_path_unknown;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if (opt == DCCPO_CHANGE_L) {
13398c2ecf20Sopenharmony_ci		fval.nn = dccp_decode_value_var(val, len);
13408c2ecf20Sopenharmony_ci		if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
13418c2ecf20Sopenharmony_ci			goto fast_path_unknown;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci		if (dccp_feat_push_confirm(fn, feat, local, &fval) ||
13448c2ecf20Sopenharmony_ci		    dccp_feat_activate(sk, feat, local, &fval))
13458c2ecf20Sopenharmony_ci			return DCCP_RESET_CODE_TOO_BUSY;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci		/* set the `Ack Pending' flag to piggyback a Confirm */
13488c2ecf20Sopenharmony_ci		inet_csk_schedule_ack(sk);
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	} else if (opt == DCCPO_CONFIRM_R) {
13518c2ecf20Sopenharmony_ci		entry = dccp_feat_list_lookup(fn, feat, local);
13528c2ecf20Sopenharmony_ci		if (entry == NULL || entry->state != FEAT_CHANGING)
13538c2ecf20Sopenharmony_ci			return 0;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci		fval.nn = dccp_decode_value_var(val, len);
13568c2ecf20Sopenharmony_ci		/*
13578c2ecf20Sopenharmony_ci		 * Just ignore a value that doesn't match our current value.
13588c2ecf20Sopenharmony_ci		 * If the option changes twice within two RTTs, then at least
13598c2ecf20Sopenharmony_ci		 * one CONFIRM will be received for the old value after a
13608c2ecf20Sopenharmony_ci		 * new CHANGE was sent.
13618c2ecf20Sopenharmony_ci		 */
13628c2ecf20Sopenharmony_ci		if (fval.nn != entry->val.nn)
13638c2ecf20Sopenharmony_ci			return 0;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci		/* Only activate after receiving the Confirm option (6.6.1). */
13668c2ecf20Sopenharmony_ci		dccp_feat_activate(sk, feat, local, &fval);
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci		/* It has been confirmed - so remove the entry */
13698c2ecf20Sopenharmony_ci		dccp_feat_list_pop(entry);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	} else {
13728c2ecf20Sopenharmony_ci		DCCP_WARN("Received illegal option %u\n", opt);
13738c2ecf20Sopenharmony_ci		goto fast_path_failed;
13748c2ecf20Sopenharmony_ci	}
13758c2ecf20Sopenharmony_ci	return 0;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_cifast_path_unknown:
13788c2ecf20Sopenharmony_ci	if (!mandatory)
13798c2ecf20Sopenharmony_ci		return dccp_push_empty_confirm(fn, feat, local);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_cifast_path_failed:
13828c2ecf20Sopenharmony_ci	return mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
13838c2ecf20Sopenharmony_ci			 : DCCP_RESET_CODE_OPTION_ERROR;
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci/**
13878c2ecf20Sopenharmony_ci * dccp_feat_parse_options  -  Process Feature-Negotiation Options
13888c2ecf20Sopenharmony_ci * @sk: for general use and used by the client during connection setup
13898c2ecf20Sopenharmony_ci * @dreq: used by the server during connection setup
13908c2ecf20Sopenharmony_ci * @mandatory: whether @opt was preceded by a Mandatory option
13918c2ecf20Sopenharmony_ci * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R
13928c2ecf20Sopenharmony_ci * @feat: one of %dccp_feature_numbers
13938c2ecf20Sopenharmony_ci * @val: value contents of @opt
13948c2ecf20Sopenharmony_ci * @len: length of @val in bytes
13958c2ecf20Sopenharmony_ci *
13968c2ecf20Sopenharmony_ci * Returns 0 on success, a Reset code for ending the connection otherwise.
13978c2ecf20Sopenharmony_ci */
13988c2ecf20Sopenharmony_ciint dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
13998c2ecf20Sopenharmony_ci			    u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
14008c2ecf20Sopenharmony_ci{
14018c2ecf20Sopenharmony_ci	struct dccp_sock *dp = dccp_sk(sk);
14028c2ecf20Sopenharmony_ci	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
14038c2ecf20Sopenharmony_ci	bool server = false;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
14068c2ecf20Sopenharmony_ci	/*
14078c2ecf20Sopenharmony_ci	 *	Negotiation during connection setup
14088c2ecf20Sopenharmony_ci	 */
14098c2ecf20Sopenharmony_ci	case DCCP_LISTEN:
14108c2ecf20Sopenharmony_ci		server = true;
14118c2ecf20Sopenharmony_ci		fallthrough;
14128c2ecf20Sopenharmony_ci	case DCCP_REQUESTING:
14138c2ecf20Sopenharmony_ci		switch (opt) {
14148c2ecf20Sopenharmony_ci		case DCCPO_CHANGE_L:
14158c2ecf20Sopenharmony_ci		case DCCPO_CHANGE_R:
14168c2ecf20Sopenharmony_ci			return dccp_feat_change_recv(fn, mandatory, opt, feat,
14178c2ecf20Sopenharmony_ci						     val, len, server);
14188c2ecf20Sopenharmony_ci		case DCCPO_CONFIRM_R:
14198c2ecf20Sopenharmony_ci		case DCCPO_CONFIRM_L:
14208c2ecf20Sopenharmony_ci			return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
14218c2ecf20Sopenharmony_ci						      val, len, server);
14228c2ecf20Sopenharmony_ci		}
14238c2ecf20Sopenharmony_ci		break;
14248c2ecf20Sopenharmony_ci	/*
14258c2ecf20Sopenharmony_ci	 *	Support for exchanging NN options on an established connection.
14268c2ecf20Sopenharmony_ci	 */
14278c2ecf20Sopenharmony_ci	case DCCP_OPEN:
14288c2ecf20Sopenharmony_ci	case DCCP_PARTOPEN:
14298c2ecf20Sopenharmony_ci		return dccp_feat_handle_nn_established(sk, mandatory, opt, feat,
14308c2ecf20Sopenharmony_ci						       val, len);
14318c2ecf20Sopenharmony_ci	}
14328c2ecf20Sopenharmony_ci	return 0;	/* ignore FN options in all other states */
14338c2ecf20Sopenharmony_ci}
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci/**
14368c2ecf20Sopenharmony_ci * dccp_feat_init  -  Seed feature negotiation with host-specific defaults
14378c2ecf20Sopenharmony_ci * @sk: Socket to initialize.
14388c2ecf20Sopenharmony_ci *
14398c2ecf20Sopenharmony_ci * This initialises global defaults, depending on the value of the sysctls.
14408c2ecf20Sopenharmony_ci * These can later be overridden by registering changes via setsockopt calls.
14418c2ecf20Sopenharmony_ci * The last link in the chain is finalise_settings, to make sure that between
14428c2ecf20Sopenharmony_ci * here and the start of actual feature negotiation no inconsistencies enter.
14438c2ecf20Sopenharmony_ci *
14448c2ecf20Sopenharmony_ci * All features not appearing below use either defaults or are otherwise
14458c2ecf20Sopenharmony_ci * later adjusted through dccp_feat_finalise_settings().
14468c2ecf20Sopenharmony_ci */
14478c2ecf20Sopenharmony_ciint dccp_feat_init(struct sock *sk)
14488c2ecf20Sopenharmony_ci{
14498c2ecf20Sopenharmony_ci	struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
14508c2ecf20Sopenharmony_ci	u8 on = 1, off = 0;
14518c2ecf20Sopenharmony_ci	int rc;
14528c2ecf20Sopenharmony_ci	struct {
14538c2ecf20Sopenharmony_ci		u8 *val;
14548c2ecf20Sopenharmony_ci		u8 len;
14558c2ecf20Sopenharmony_ci	} tx, rx;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	/* Non-negotiable (NN) features */
14588c2ecf20Sopenharmony_ci	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
14598c2ecf20Sopenharmony_ci				    sysctl_dccp_sequence_window);
14608c2ecf20Sopenharmony_ci	if (rc)
14618c2ecf20Sopenharmony_ci		return rc;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	/* Server-priority (SP) features */
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	/* Advertise that short seqnos are not supported (7.6.1) */
14668c2ecf20Sopenharmony_ci	rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1);
14678c2ecf20Sopenharmony_ci	if (rc)
14688c2ecf20Sopenharmony_ci		return rc;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	/* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */
14718c2ecf20Sopenharmony_ci	rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1);
14728c2ecf20Sopenharmony_ci	if (rc)
14738c2ecf20Sopenharmony_ci		return rc;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	/*
14768c2ecf20Sopenharmony_ci	 * We advertise the available list of CCIDs and reorder according to
14778c2ecf20Sopenharmony_ci	 * preferences, to avoid failure resulting from negotiating different
14788c2ecf20Sopenharmony_ci	 * singleton values (which always leads to failure).
14798c2ecf20Sopenharmony_ci	 * These settings can still (later) be overridden via sockopts.
14808c2ecf20Sopenharmony_ci	 */
14818c2ecf20Sopenharmony_ci	if (ccid_get_builtin_ccids(&tx.val, &tx.len))
14828c2ecf20Sopenharmony_ci		return -ENOBUFS;
14838c2ecf20Sopenharmony_ci	if (ccid_get_builtin_ccids(&rx.val, &rx.len)) {
14848c2ecf20Sopenharmony_ci		kfree(tx.val);
14858c2ecf20Sopenharmony_ci		return -ENOBUFS;
14868c2ecf20Sopenharmony_ci	}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
14898c2ecf20Sopenharmony_ci	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
14908c2ecf20Sopenharmony_ci		goto free_ccid_lists;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
14938c2ecf20Sopenharmony_ci	if (rc)
14948c2ecf20Sopenharmony_ci		goto free_ccid_lists;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len);
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cifree_ccid_lists:
14998c2ecf20Sopenharmony_ci	kfree(tx.val);
15008c2ecf20Sopenharmony_ci	kfree(rx.val);
15018c2ecf20Sopenharmony_ci	return rc;
15028c2ecf20Sopenharmony_ci}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ciint dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
15058c2ecf20Sopenharmony_ci{
15068c2ecf20Sopenharmony_ci	struct dccp_sock *dp = dccp_sk(sk);
15078c2ecf20Sopenharmony_ci	struct dccp_feat_entry *cur, *next;
15088c2ecf20Sopenharmony_ci	int idx;
15098c2ecf20Sopenharmony_ci	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
15108c2ecf20Sopenharmony_ci		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
15118c2ecf20Sopenharmony_ci	};
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	list_for_each_entry(cur, fn_list, node) {
15148c2ecf20Sopenharmony_ci		/*
15158c2ecf20Sopenharmony_ci		 * An empty Confirm means that either an unknown feature type
15168c2ecf20Sopenharmony_ci		 * or an invalid value was present. In the first case there is
15178c2ecf20Sopenharmony_ci		 * nothing to activate, in the other the default value is used.
15188c2ecf20Sopenharmony_ci		 */
15198c2ecf20Sopenharmony_ci		if (cur->empty_confirm)
15208c2ecf20Sopenharmony_ci			continue;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci		idx = dccp_feat_index(cur->feat_num);
15238c2ecf20Sopenharmony_ci		if (idx < 0) {
15248c2ecf20Sopenharmony_ci			DCCP_BUG("Unknown feature %u", cur->feat_num);
15258c2ecf20Sopenharmony_ci			goto activation_failed;
15268c2ecf20Sopenharmony_ci		}
15278c2ecf20Sopenharmony_ci		if (cur->state != FEAT_STABLE) {
15288c2ecf20Sopenharmony_ci			DCCP_CRIT("Negotiation of %s %s failed in state %s",
15298c2ecf20Sopenharmony_ci				  cur->is_local ? "local" : "remote",
15308c2ecf20Sopenharmony_ci				  dccp_feat_fname(cur->feat_num),
15318c2ecf20Sopenharmony_ci				  dccp_feat_sname[cur->state]);
15328c2ecf20Sopenharmony_ci			goto activation_failed;
15338c2ecf20Sopenharmony_ci		}
15348c2ecf20Sopenharmony_ci		fvals[idx][cur->is_local] = &cur->val;
15358c2ecf20Sopenharmony_ci	}
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	/*
15388c2ecf20Sopenharmony_ci	 * Activate in decreasing order of index, so that the CCIDs are always
15398c2ecf20Sopenharmony_ci	 * activated as the last feature. This avoids the case where a CCID
15408c2ecf20Sopenharmony_ci	 * relies on the initialisation of one or more features that it depends
15418c2ecf20Sopenharmony_ci	 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
15428c2ecf20Sopenharmony_ci	 */
15438c2ecf20Sopenharmony_ci	for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
15448c2ecf20Sopenharmony_ci		if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
15458c2ecf20Sopenharmony_ci		    __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
15468c2ecf20Sopenharmony_ci			DCCP_CRIT("Could not activate %d", idx);
15478c2ecf20Sopenharmony_ci			goto activation_failed;
15488c2ecf20Sopenharmony_ci		}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	/* Clean up Change options which have been confirmed already */
15518c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cur, next, fn_list, node)
15528c2ecf20Sopenharmony_ci		if (!cur->needs_confirm)
15538c2ecf20Sopenharmony_ci			dccp_feat_list_pop(cur);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	dccp_pr_debug("Activation OK\n");
15568c2ecf20Sopenharmony_ci	return 0;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ciactivation_failed:
15598c2ecf20Sopenharmony_ci	/*
15608c2ecf20Sopenharmony_ci	 * We clean up everything that may have been allocated, since
15618c2ecf20Sopenharmony_ci	 * it is difficult to track at which stage negotiation failed.
15628c2ecf20Sopenharmony_ci	 * This is ok, since all allocation functions below are robust
15638c2ecf20Sopenharmony_ci	 * against NULL arguments.
15648c2ecf20Sopenharmony_ci	 */
15658c2ecf20Sopenharmony_ci	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
15668c2ecf20Sopenharmony_ci	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
15678c2ecf20Sopenharmony_ci	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
15688c2ecf20Sopenharmony_ci	dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
15698c2ecf20Sopenharmony_ci	dp->dccps_hc_rx_ackvec = NULL;
15708c2ecf20Sopenharmony_ci	return -1;
15718c2ecf20Sopenharmony_ci}
1572