aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/feat.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/feat.c')
-rw-r--r--net/dccp/feat.c167
1 files changed, 167 insertions, 0 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 933a0ecf8d46..069d8ffe4c6f 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,171 @@
23 23
24#define DCCP_FEAT_SP_NOAGREE (-123) 24#define DCCP_FEAT_SP_NOAGREE (-123)
25 25
26static const struct {
27 u8 feat_num; /* DCCPF_xxx */
28 enum dccp_feat_type rxtx; /* RX or TX */
29 enum dccp_feat_type reconciliation; /* SP or NN */
30 u8 default_value; /* as in 6.4 */
31/*
32 * Lookup table for location and type of features (from RFC 4340/4342)
33 * +--------------------------+----+-----+----+----+---------+-----------+
34 * | Feature | Location | Reconc. | Initial | Section |
35 * | | RX | TX | SP | NN | Value | Reference |
36 * +--------------------------+----+-----+----+----+---------+-----------+
37 * | DCCPF_CCID | | X | X | | 2 | 10 |
38 * | DCCPF_SHORT_SEQNOS | | X | X | | 0 | 7.6.1 |
39 * | DCCPF_SEQUENCE_WINDOW | | X | | X | 100 | 7.5.2 |
40 * | DCCPF_ECN_INCAPABLE | X | | X | | 0 | 12.1 |
41 * | DCCPF_ACK_RATIO | | X | | X | 2 | 11.3 |
42 * | DCCPF_SEND_ACK_VECTOR | X | | X | | 0 | 11.5 |
43 * | DCCPF_SEND_NDP_COUNT | | X | X | | 0 | 7.7.2 |
44 * | DCCPF_MIN_CSUM_COVER | X | | X | | 0 | 9.2.1 |
45 * | DCCPF_DATA_CHECKSUM | X | | X | | 0 | 9.3.1 |
46 * | DCCPF_SEND_LEV_RATE | X | | X | | 0 | 4342/8.4 |
47 * +--------------------------+----+-----+----+----+---------+-----------+
48 */
49} dccp_feat_table[] = {
50 { DCCPF_CCID, FEAT_AT_TX, FEAT_SP, 2 },
51 { DCCPF_SHORT_SEQNOS, FEAT_AT_TX, FEAT_SP, 0 },
52 { DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
53 { DCCPF_ECN_INCAPABLE, FEAT_AT_RX, FEAT_SP, 0 },
54 { DCCPF_ACK_RATIO, FEAT_AT_TX, FEAT_NN, 2 },
55 { DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
56 { DCCPF_SEND_NDP_COUNT, FEAT_AT_TX, FEAT_SP, 0 },
57 { DCCPF_MIN_CSUM_COVER, FEAT_AT_RX, FEAT_SP, 0 },
58 { DCCPF_DATA_CHECKSUM, FEAT_AT_RX, FEAT_SP, 0 },
59 { DCCPF_SEND_LEV_RATE, FEAT_AT_RX, FEAT_SP, 0 },
60};
61#define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table)
62
63/**
64 * dccp_feat_index - Hash function to map feature number into array position
65 * Returns consecutive array index or -1 if the feature is not understood.
66 */
67static int dccp_feat_index(u8 feat_num)
68{
69 /* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
70 if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
71 return feat_num - 1;
72
73 /*
74 * Other features: add cases for new feature types here after adding
75 * them to the above table.
76 */
77 switch (feat_num) {
78 case DCCPF_SEND_LEV_RATE:
79 return DCCP_FEAT_SUPPORTED_MAX - 1;
80 }
81 return -1;
82}
83
84static u8 dccp_feat_type(u8 feat_num)
85{
86 int idx = dccp_feat_index(feat_num);
87
88 if (idx < 0)
89 return FEAT_UNKNOWN;
90 return dccp_feat_table[idx].reconciliation;
91}
92
93/* copy constructor, fval must not already contain allocated memory */
94static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
95{
96 fval->sp.len = len;
97 if (fval->sp.len > 0) {
98 fval->sp.vec = kmemdup(val, len, gfp_any());
99 if (fval->sp.vec == NULL) {
100 fval->sp.len = 0;
101 return -ENOBUFS;
102 }
103 }
104 return 0;
105}
106
107static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
108{
109 if (unlikely(val == NULL))
110 return;
111 if (dccp_feat_type(feat_num) == FEAT_SP)
112 kfree(val->sp.vec);
113 memset(val, 0, sizeof(*val));
114}
115
116static struct dccp_feat_entry *
117 dccp_feat_clone_entry(struct dccp_feat_entry const *original)
118{
119 struct dccp_feat_entry *new;
120 u8 type = dccp_feat_type(original->feat_num);
121
122 if (type == FEAT_UNKNOWN)
123 return NULL;
124
125 new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
126 if (new == NULL)
127 return NULL;
128
129 if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
130 original->val.sp.vec,
131 original->val.sp.len)) {
132 kfree(new);
133 return NULL;
134 }
135 return new;
136}
137
138static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
139{
140 if (entry != NULL) {
141 dccp_feat_val_destructor(entry->feat_num, &entry->val);
142 kfree(entry);
143 }
144}
145
146/*
147 * List management functions
148 *
149 * Feature negotiation lists rely on and maintain the following invariants:
150 * - each feat_num in the list is known, i.e. we know its type and default value
151 * - each feat_num/is_local combination is unique (old entries are overwritten)
152 * - SP values are always freshly allocated
153 * - list is sorted in increasing order of feature number (faster lookup)
154 */
155
156static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
157{
158 list_del(&entry->node);
159 dccp_feat_entry_destructor(entry);
160}
161
162void dccp_feat_list_purge(struct list_head *fn_list)
163{
164 struct dccp_feat_entry *entry, *next;
165
166 list_for_each_entry_safe(entry, next, fn_list, node)
167 dccp_feat_entry_destructor(entry);
168 INIT_LIST_HEAD(fn_list);
169}
170EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
171
172/* generate @to as full clone of @from - @to must not contain any nodes */
173int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
174{
175 struct dccp_feat_entry *entry, *new;
176
177 INIT_LIST_HEAD(to);
178 list_for_each_entry(entry, from, node) {
179 new = dccp_feat_clone_entry(entry);
180 if (new == NULL)
181 goto cloning_failed;
182 list_add_tail(&new->node, to);
183 }
184 return 0;
185
186cloning_failed:
187 dccp_feat_list_purge(to);
188 return -ENOMEM;
189}
190
26int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 191int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
27 u8 *val, u8 len, gfp_t gfp) 192 u8 *val, u8 len, gfp_t gfp)
28{ 193{
@@ -639,6 +804,8 @@ const char *dccp_feat_name(const u8 feat)
639 if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC) 804 if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
640 return feature_names[DCCPF_RESERVED]; 805 return feature_names[DCCPF_RESERVED];
641 806
807 if (feat == DCCPF_SEND_LEV_RATE)
808 return "Send Loss Event Rate";
642 if (feat >= DCCPF_MIN_CCID_SPECIFIC) 809 if (feat >= DCCPF_MIN_CCID_SPECIFIC)
643 return "CCID-specific"; 810 return "CCID-specific";
644 811