aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-12-02 02:34:01 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-02 02:34:01 -0500
commit422d9cdcb85b3622d08a590fed66021af7aea333 (patch)
treee40520346933d4c1d27ad7712f09bcd45fb25fca /net/dccp
parentb1ad00422ecba0449f8e3a8f2ec9267bc994bf8f (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> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp')
-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{