aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:30 -0400
commitc926c6aed3e444e8c88a768f063b2de8fd6ae760 (patch)
treec3d2507f5652aed5ff0a2908ad8147a143e09a82
parentd2150b7bff3d397692cf0dc890f198d23564de5f (diff)
dccp: Feature activation handlers
This patch provides the post-processing of feature negotiation state, after the negotiation has completed. To this purpose, handlers are used and added to the dccp_feat_table. Each handler is passed a boolean flag whether the RX or TX side of the feature is meant. Several handlers are provided already, new handlers can easily be added. The initialisation is now fully dynamic, i.e. CCIDs are activated only after the feature negotiation. The integration of this dynamic activation is done in the subsequent patches. Thanks to Wei Yongjun for pointing out the necessity of skipping over empty Confirm options while copying the negotiated feature values. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
-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 2e2a6f229eaf..1baed789bcc2 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 da3bbad9d50d..f78bd357b5b1 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
@@ -99,6 +189,41 @@ static int dccp_feat_default_value(u8 feat_num)
99 return idx < 0 ? : dccp_feat_table[idx].default_value; 189 return idx < 0 ? : dccp_feat_table[idx].default_value;
100} 190}
101 191
192static int __dccp_feat_activate(struct sock *sk, const int idx,
193 const bool is_local, dccp_feat_val const *fval)
194{
195 bool rx;
196 u64 val;
197
198 if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
199 return -1;
200 if (dccp_feat_table[idx].activation_hdlr == NULL)
201 return 0;
202
203 if (fval == NULL) {
204 val = dccp_feat_table[idx].default_value;
205 } else if (dccp_feat_table[idx].reconciliation == FEAT_SP) {
206 if (fval->sp.vec == NULL) {
207 /*
208 * This can happen when an empty Confirm is sent
209 * for an SP (i.e. known) feature. In this case
210 * we would be using the default anyway.
211 */
212 DCCP_CRIT("Feature #%d undefined: using default", idx);
213 val = dccp_feat_table[idx].default_value;
214 } else {
215 val = fval->sp.vec[0];
216 }
217 } else {
218 val = fval->nn;
219 }
220
221 /* Location is RX if this is a local-RX or remote-TX feature */
222 rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
223
224 return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
225}
226
102/* Test for "Req'd" feature (RFC 4340, 6.4) */ 227/* Test for "Req'd" feature (RFC 4340, 6.4) */
103static inline int dccp_feat_must_be_understood(u8 feat_num) 228static inline int dccp_feat_must_be_understood(u8 feat_num)
104{ 229{
@@ -1506,6 +1631,74 @@ out:
1506 1631
1507EXPORT_SYMBOL_GPL(dccp_feat_init); 1632EXPORT_SYMBOL_GPL(dccp_feat_init);
1508 1633
1634int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
1635{
1636 struct dccp_sock *dp = dccp_sk(sk);
1637 struct dccp_feat_entry *cur, *next;
1638 int idx;
1639 dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
1640 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
1641 };
1642
1643 list_for_each_entry(cur, fn_list, node) {
1644 /*
1645 * An empty Confirm means that either an unknown feature type
1646 * or an invalid value was present. In the first case there is
1647 * nothing to activate, in the other the default value is used.
1648 */
1649 if (cur->empty_confirm)
1650 continue;
1651
1652 idx = dccp_feat_index(cur->feat_num);
1653 if (idx < 0) {
1654 DCCP_BUG("Unknown feature %u", cur->feat_num);
1655 goto activation_failed;
1656 }
1657 if (cur->state != FEAT_STABLE) {
1658 DCCP_CRIT("Negotiation of %s %u failed in state %u",
1659 cur->is_local ? "local" : "remote",
1660 cur->feat_num, cur->state);
1661 goto activation_failed;
1662 }
1663 fvals[idx][cur->is_local] = &cur->val;
1664 }
1665
1666 /*
1667 * Activate in decreasing order of index, so that the CCIDs are always
1668 * activated as the last feature. This avoids the case where a CCID
1669 * relies on the initialisation of one or more features that it depends
1670 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
1671 */
1672 for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
1673 if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
1674 __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
1675 DCCP_CRIT("Could not activate %d", idx);
1676 goto activation_failed;
1677 }
1678
1679 /* Clean up Change options which have been confirmed already */
1680 list_for_each_entry_safe(cur, next, fn_list, node)
1681 if (!cur->needs_confirm)
1682 dccp_feat_list_pop(cur);
1683
1684 dccp_pr_debug("Activation OK\n");
1685 return 0;
1686
1687activation_failed:
1688 /*
1689 * We clean up everything that may have been allocated, since
1690 * it is difficult to track at which stage negotiation failed.
1691 * This is ok, since all allocation functions below are robust
1692 * against NULL arguments.
1693 */
1694 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
1695 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
1696 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
1697 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
1698 dp->dccps_hc_rx_ackvec = NULL;
1699 return -1;
1700}
1701
1509#ifdef CONFIG_IP_DCCP_DEBUG 1702#ifdef CONFIG_IP_DCCP_DEBUG
1510const char *dccp_feat_typename(const u8 type) 1703const char *dccp_feat_typename(const u8 type)
1511{ 1704{