aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dccp/dccp.h1
-rw-r--r--net/dccp/feat.c213
2 files changed, 204 insertions, 10 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 4ed7c5936bcf..94f6785f81ec 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -445,6 +445,7 @@ extern int dccp_feat_finalise_settings(struct dccp_sock *dp);
445extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); 445extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
446extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*, 446extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*,
447 struct sk_buff *skb); 447 struct sk_buff *skb);
448extern int dccp_feat_activate_values(struct sock *sk, struct list_head *fn);
448extern void dccp_feat_list_purge(struct list_head *fn_list); 449extern void dccp_feat_list_purge(struct list_head *fn_list);
449 450
450extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); 451extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index bc00c038e4a5..b127189550f1 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -25,11 +25,101 @@
25 25
26#define DCCP_FEAT_SP_NOAGREE (-123) 26#define DCCP_FEAT_SP_NOAGREE (-123)
27 27
28/*
29 * Feature activation handlers.
30 *
31 * These all use an u64 argument, to provide enough room for NN/SP features. At
32 * this stage the negotiated values have been checked to be within their range.
33 */
34static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
35{
36 struct dccp_sock *dp = dccp_sk(sk);
37 struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
38
39 if (new_ccid == NULL)
40 return -ENOMEM;
41
42 if (rx) {
43 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
44 dp->dccps_hc_rx_ccid = new_ccid;
45 } else {
46 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
47 dp->dccps_hc_tx_ccid = new_ccid;
48 }
49 return 0;
50}
51
52static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
53{
54 if (!rx)
55 dccp_msk(sk)->dccpms_sequence_window = seq_win;
56 return 0;
57}
58
59static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
60{
61 if (rx)
62 dccp_sk(sk)->dccps_r_ack_ratio = ratio;
63 else
64 dccp_sk(sk)->dccps_l_ack_ratio = ratio;
65 return 0;
66}
67
68static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
69{
70 struct dccp_sock *dp = dccp_sk(sk);
71
72 if (rx) {
73 if (enable && dp->dccps_hc_rx_ackvec == NULL) {
74 dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
75 if (dp->dccps_hc_rx_ackvec == NULL)
76 return -ENOMEM;
77 } else if (!enable) {
78 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
79 dp->dccps_hc_rx_ackvec = NULL;
80 }
81 }
82 return 0;
83}
84
85static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
86{
87 if (!rx)
88 dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
89 return 0;
90}
91
92/*
93 * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
94 * `rx' holds when the sending peer informs about his partial coverage via a
95 * ChangeR() option. In the other case, we are the sender and the receiver
96 * announces its coverage via ChangeL() options. The policy here is to honour
97 * such communication by enabling the corresponding partial coverage - but only
98 * if it has not been set manually before; the warning here means that all
99 * packets will be dropped.
100 */
101static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
102{
103 struct dccp_sock *dp = dccp_sk(sk);
104
105 if (rx)
106 dp->dccps_pcrlen = cscov;
107 else {
108 if (dp->dccps_pcslen == 0)
109 dp->dccps_pcslen = cscov;
110 else if (cscov > dp->dccps_pcslen)
111 DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
112 dp->dccps_pcslen, (u8)cscov);
113 }
114 return 0;
115}
116
28static const struct { 117static const struct {
29 u8 feat_num; /* DCCPF_xxx */ 118 u8 feat_num; /* DCCPF_xxx */
30 enum dccp_feat_type rxtx; /* RX or TX */ 119 enum dccp_feat_type rxtx; /* RX or TX */
31 enum dccp_feat_type reconciliation; /* SP or NN */ 120 enum dccp_feat_type reconciliation; /* SP or NN */
32 u8 default_value; /* as in 6.4 */ 121 u8 default_value; /* as in 6.4 */
122 int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
33/* 123/*
34 * Lookup table for location and type of features (from RFC 4340/4342) 124 * Lookup table for location and type of features (from RFC 4340/4342)
35 * +--------------------------+----+-----+----+----+---------+-----------+ 125 * +--------------------------+----+-----+----+----+---------+-----------+
@@ -49,16 +139,16 @@ static const struct {
49 * +--------------------------+----+-----+----+----+---------+-----------+ 139 * +--------------------------+----+-----+----+----+---------+-----------+
50 */ 140 */
51} dccp_feat_table[] = { 141} dccp_feat_table[] = {
52 { DCCPF_CCID, FEAT_AT_TX, FEAT_SP, 2 }, 142 { DCCPF_CCID, FEAT_AT_TX, FEAT_SP, 2, dccp_hdlr_ccid },
53 { DCCPF_SHORT_SEQNOS, FEAT_AT_TX, FEAT_SP, 0 }, 143 { DCCPF_SHORT_SEQNOS, FEAT_AT_TX, FEAT_SP, 0, NULL },
54 { DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 }, 144 { DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win },
55 { DCCPF_ECN_INCAPABLE, FEAT_AT_RX, FEAT_SP, 0 }, 145 { DCCPF_ECN_INCAPABLE, FEAT_AT_RX, FEAT_SP, 0, NULL },
56 { DCCPF_ACK_RATIO, FEAT_AT_TX, FEAT_NN, 2 }, 146 { DCCPF_ACK_RATIO, FEAT_AT_TX, FEAT_NN, 2, dccp_hdlr_ack_ratio},
57 { DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 }, 147 { DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0, dccp_hdlr_ackvec },
58 { DCCPF_SEND_NDP_COUNT, FEAT_AT_TX, FEAT_SP, 0 }, 148 { DCCPF_SEND_NDP_COUNT, FEAT_AT_TX, FEAT_SP, 0, dccp_hdlr_ndp },
59 { DCCPF_MIN_CSUM_COVER, FEAT_AT_RX, FEAT_SP, 0 }, 149 { DCCPF_MIN_CSUM_COVER, FEAT_AT_RX, FEAT_SP, 0, dccp_hdlr_min_cscov},
60 { DCCPF_DATA_CHECKSUM, FEAT_AT_RX, FEAT_SP, 0 }, 150 { DCCPF_DATA_CHECKSUM, FEAT_AT_RX, FEAT_SP, 0, NULL },
61 { DCCPF_SEND_LEV_RATE, FEAT_AT_RX, FEAT_SP, 0 }, 151 { DCCPF_SEND_LEV_RATE, FEAT_AT_RX, FEAT_SP, 0, NULL },
62}; 152};
63#define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table) 153#define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table)
64 154
@@ -104,6 +194,41 @@ static int dccp_feat_default_value(u8 feat_num)
104 return idx < 0 ? 0 : dccp_feat_table[idx].default_value; 194 return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
105} 195}
106 196
197static int __dccp_feat_activate(struct sock *sk, const int idx,
198 const bool is_local, dccp_feat_val const *fval)
199{
200 bool rx;
201 u64 val;
202
203 if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
204 return -1;
205 if (dccp_feat_table[idx].activation_hdlr == NULL)
206 return 0;
207
208 if (fval == NULL) {
209 val = dccp_feat_table[idx].default_value;
210 } else if (dccp_feat_table[idx].reconciliation == FEAT_SP) {
211 if (fval->sp.vec == NULL) {
212 /*
213 * This can happen when an empty Confirm is sent
214 * for an SP (i.e. known) feature. In this case
215 * we would be using the default anyway.
216 */
217 DCCP_CRIT("Feature #%d undefined: using default", idx);
218 val = dccp_feat_table[idx].default_value;
219 } else {
220 val = fval->sp.vec[0];
221 }
222 } else {
223 val = fval->nn;
224 }
225
226 /* Location is RX if this is a local-RX or remote-TX feature */
227 rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
228
229 return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
230}
231
107/* Test for "Req'd" feature (RFC 4340, 6.4) */ 232/* Test for "Req'd" feature (RFC 4340, 6.4) */
108static inline int dccp_feat_must_be_understood(u8 feat_num) 233static inline int dccp_feat_must_be_understood(u8 feat_num)
109{ 234{
@@ -1512,6 +1637,74 @@ out:
1512 1637
1513EXPORT_SYMBOL_GPL(dccp_feat_init); 1638EXPORT_SYMBOL_GPL(dccp_feat_init);
1514 1639
1640int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
1641{
1642 struct dccp_sock *dp = dccp_sk(sk);
1643 struct dccp_feat_entry *cur, *next;
1644 int idx;
1645 dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
1646 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
1647 };
1648
1649 list_for_each_entry(cur, fn_list, node) {
1650 /*
1651 * An empty Confirm means that either an unknown feature type
1652 * or an invalid value was present. In the first case there is
1653 * nothing to activate, in the other the default value is used.
1654 */
1655 if (cur->empty_confirm)
1656 continue;
1657
1658 idx = dccp_feat_index(cur->feat_num);
1659 if (idx < 0) {
1660 DCCP_BUG("Unknown feature %u", cur->feat_num);
1661 goto activation_failed;
1662 }
1663 if (cur->state != FEAT_STABLE) {
1664 DCCP_CRIT("Negotiation of %s %u failed in state %u",
1665 cur->is_local ? "local" : "remote",
1666 cur->feat_num, cur->state);
1667 goto activation_failed;
1668 }
1669 fvals[idx][cur->is_local] = &cur->val;
1670 }
1671
1672 /*
1673 * Activate in decreasing order of index, so that the CCIDs are always
1674 * activated as the last feature. This avoids the case where a CCID
1675 * relies on the initialisation of one or more features that it depends
1676 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
1677 */
1678 for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
1679 if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
1680 __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
1681 DCCP_CRIT("Could not activate %d", idx);
1682 goto activation_failed;
1683 }
1684
1685 /* Clean up Change options which have been confirmed already */
1686 list_for_each_entry_safe(cur, next, fn_list, node)
1687 if (!cur->needs_confirm)
1688 dccp_feat_list_pop(cur);
1689
1690 dccp_pr_debug("Activation OK\n");
1691 return 0;
1692
1693activation_failed:
1694 /*
1695 * We clean up everything that may have been allocated, since
1696 * it is difficult to track at which stage negotiation failed.
1697 * This is ok, since all allocation functions below are robust
1698 * against NULL arguments.
1699 */
1700 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
1701 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
1702 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
1703 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
1704 dp->dccps_hc_rx_ackvec = NULL;
1705 return -1;
1706}
1707
1515#ifdef CONFIG_IP_DCCP_DEBUG 1708#ifdef CONFIG_IP_DCCP_DEBUG
1516const char *dccp_feat_typename(const u8 type) 1709const char *dccp_feat_typename(const u8 type)
1517{ 1710{